Commit 34116adc119 for php.net
commit 34116adc119f9ca496e7c8f4c1da9b80345f9298
Author: Weilin Du <weilindu@php.net>
Date: Wed Jun 24 18:42:28 2026 +0800
Fix GH-9945: Reject shmop/sysvshm keys outside key_t range (#22423)
Now, shmop_open() and shm_attach() accepted zend_long keys and passed them directly to SysV shared memory APIs, where they may be truncated to key_t.
Generally we should throw ValurErrors on those issues. Fixes #9945
diff --git a/NEWS b/NEWS
index 231e1788bbe..fede5aa5173 100644
--- a/NEWS
+++ b/NEWS
@@ -206,6 +206,10 @@ PHP NEWS
. Changed defaults of session.use_strict_mode (now 1), session.cookie_httponly
(now 1) and session.cookie_samesite (now "Lax"). (jorgsowa)
+- Shmop:
+ . Fixed bug GH-9945 (shmop_open() silently truncates keys outside the key_t
+ range). (Weilin Du)
+
- Soap:
. Soap::__setCookie() when cookie name is a digit is now not stored and
represented as a string anymore but a int. (David Carlier)
@@ -236,6 +240,10 @@ PHP NEWS
. Fix bug GH-22062 (SplDoublyLinkedList iterator UAF
via destructor releasing next node). (David Carlier)
+- Sysvshm:
+ . Fixed shm_attach() to throw ValueError for keys outside the key_t range.
+ (Weilin Du)
+
- Sqlite3:
. Fix NUL byte truncation in sqlite3 TEXT column handling. (ndossche)
diff --git a/ext/shmop/shmop.c b/ext/shmop/shmop.c
index c3ed217443f..645ce172fdc 100644
--- a/ext/shmop/shmop.c
+++ b/ext/shmop/shmop.c
@@ -129,13 +129,20 @@ PHP_MINFO_FUNCTION(shmop)
/* {{{ gets and attaches a shared memory segment */
PHP_FUNCTION(shmop_open)
{
- zend_long key, mode, size;
+ zend_long key_arg, mode, size;
+ key_t key;
php_shmop *shmop;
struct shmid_ds shm;
char *flags;
size_t flags_len;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "lsll", &key, &flags, &flags_len, &mode, &size) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "lsll", &key_arg, &flags, &flags_len, &mode, &size) == FAILURE) {
+ RETURN_THROWS();
+ }
+
+ key = (key_t) key_arg;
+ if ((zend_long) key != key_arg) {
+ zend_argument_value_error(1, "is out of range");
RETURN_THROWS();
}
diff --git a/ext/shmop/tests/gh9945.phpt b/ext/shmop/tests/gh9945.phpt
new file mode 100644
index 00000000000..f22f79149bf
--- /dev/null
+++ b/ext/shmop/tests/gh9945.phpt
@@ -0,0 +1,19 @@
+--TEST--
+GH-9945: shmop_open() must reject keys outside the key_t range
+--EXTENSIONS--
+shmop
+--SKIPIF--
+<?php
+if (PHP_INT_SIZE !== 8) die('skip only for 64-bit');
+if (PHP_OS_FAMILY !== 'Linux' && PHP_OS_FAMILY !== 'Windows') die('skip only for platforms with 32-bit key_t');
+?>
+--FILE--
+<?php
+try {
+ shmop_open(0x100000000, '', 0644, 1);
+} catch (ValueError $exception) {
+ echo $exception->getMessage(), "\n";
+}
+?>
+--EXPECT--
+shmop_open(): Argument #1 ($key) is out of range
diff --git a/ext/sysvshm/sysvshm.c b/ext/sysvshm/sysvshm.c
index 59ca49a974e..6ca06be935d 100644
--- a/ext/sysvshm/sysvshm.c
+++ b/ext/sysvshm/sysvshm.c
@@ -126,10 +126,17 @@ PHP_FUNCTION(shm_attach)
sysvshm_shm *shm_list_ptr;
char *shm_ptr;
sysvshm_chunk_head *chunk_ptr;
- zend_long shm_key, shm_id, shm_size, shm_flag = 0666;
+ zend_long shm_key_arg, shm_id, shm_size, shm_flag = 0666;
+ key_t shm_key;
bool shm_size_is_null = true;
- if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "l|l!l", &shm_key, &shm_size, &shm_size_is_null, &shm_flag)) {
+ if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "l|l!l", &shm_key_arg, &shm_size, &shm_size_is_null, &shm_flag)) {
+ RETURN_THROWS();
+ }
+
+ shm_key = (key_t) shm_key_arg;
+ if ((zend_long) shm_key != shm_key_arg) {
+ zend_argument_value_error(1, "is out of range");
RETURN_THROWS();
}
@@ -145,17 +152,17 @@ PHP_FUNCTION(shm_attach)
/* get the id from a specified key or create new shared memory */
if ((shm_id = shmget(shm_key, 0, 0)) < 0) {
if (shm_size < (zend_long)sizeof(sysvshm_chunk_head)) {
- php_error_docref(NULL, E_WARNING, "Failed for key 0x" ZEND_XLONG_FMT ": memorysize too small", shm_key);
+ php_error_docref(NULL, E_WARNING, "Failed for key 0x" ZEND_XLONG_FMT ": memorysize too small", shm_key_arg);
RETURN_FALSE;
}
if ((shm_id = shmget(shm_key, shm_size, shm_flag | IPC_CREAT | IPC_EXCL)) < 0) {
- php_error_docref(NULL, E_WARNING, "Failed for key 0x" ZEND_XLONG_FMT ": %s", shm_key, strerror(errno));
+ php_error_docref(NULL, E_WARNING, "Failed for key 0x" ZEND_XLONG_FMT ": %s", shm_key_arg, strerror(errno));
RETURN_FALSE;
}
}
if ((shm_ptr = shmat(shm_id, NULL, 0)) == (void *) -1) {
- php_error_docref(NULL, E_WARNING, "Failed for key 0x" ZEND_XLONG_FMT ": %s", shm_key, strerror(errno));
+ php_error_docref(NULL, E_WARNING, "Failed for key 0x" ZEND_XLONG_FMT ": %s", shm_key_arg, strerror(errno));
RETURN_FALSE;
}
diff --git a/ext/sysvshm/tests/gh9945.phpt b/ext/sysvshm/tests/gh9945.phpt
new file mode 100644
index 00000000000..8185d39b098
--- /dev/null
+++ b/ext/sysvshm/tests/gh9945.phpt
@@ -0,0 +1,19 @@
+--TEST--
+GH-9945: shm_attach() must reject keys outside the key_t range
+--EXTENSIONS--
+sysvshm
+--SKIPIF--
+<?php
+if (PHP_INT_SIZE !== 8) die('skip only for 64-bit');
+if (PHP_OS_FAMILY !== 'Linux' && PHP_OS_FAMILY !== 'Windows') die('skip only for platforms with 32-bit key_t');
+?>
+--FILE--
+<?php
+try {
+ shm_attach(0x100000000, 0);
+} catch (ValueError $exception) {
+ echo $exception->getMessage(), "\n";
+}
+?>
+--EXPECT--
+shm_attach(): Argument #1 ($key) is out of range