Skip to content

Commit 34116ad

Browse files
authored
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
1 parent 3f285f4 commit 34116ad

5 files changed

Lines changed: 67 additions & 7 deletions

File tree

NEWS

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,10 @@ PHP NEWS
206206
. Changed defaults of session.use_strict_mode (now 1), session.cookie_httponly
207207
(now 1) and session.cookie_samesite (now "Lax"). (jorgsowa)
208208

209+
- Shmop:
210+
. Fixed bug GH-9945 (shmop_open() silently truncates keys outside the key_t
211+
range). (Weilin Du)
212+
209213
- Soap:
210214
. Soap::__setCookie() when cookie name is a digit is now not stored and
211215
represented as a string anymore but a int. (David Carlier)
@@ -236,6 +240,10 @@ PHP NEWS
236240
. Fix bug GH-22062 (SplDoublyLinkedList iterator UAF
237241
via destructor releasing next node). (David Carlier)
238242

243+
- Sysvshm:
244+
. Fixed shm_attach() to throw ValueError for keys outside the key_t range.
245+
(Weilin Du)
246+
239247
- Sqlite3:
240248
. Fix NUL byte truncation in sqlite3 TEXT column handling. (ndossche)
241249

ext/shmop/shmop.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,13 +129,20 @@ PHP_MINFO_FUNCTION(shmop)
129129
/* {{{ gets and attaches a shared memory segment */
130130
PHP_FUNCTION(shmop_open)
131131
{
132-
zend_long key, mode, size;
132+
zend_long key_arg, mode, size;
133+
key_t key;
133134
php_shmop *shmop;
134135
struct shmid_ds shm;
135136
char *flags;
136137
size_t flags_len;
137138

138-
if (zend_parse_parameters(ZEND_NUM_ARGS(), "lsll", &key, &flags, &flags_len, &mode, &size) == FAILURE) {
139+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "lsll", &key_arg, &flags, &flags_len, &mode, &size) == FAILURE) {
140+
RETURN_THROWS();
141+
}
142+
143+
key = (key_t) key_arg;
144+
if ((zend_long) key != key_arg) {
145+
zend_argument_value_error(1, "is out of range");
139146
RETURN_THROWS();
140147
}
141148

ext/shmop/tests/gh9945.phpt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
--TEST--
2+
GH-9945: shmop_open() must reject keys outside the key_t range
3+
--EXTENSIONS--
4+
shmop
5+
--SKIPIF--
6+
<?php
7+
if (PHP_INT_SIZE !== 8) die('skip only for 64-bit');
8+
if (PHP_OS_FAMILY !== 'Linux' && PHP_OS_FAMILY !== 'Windows') die('skip only for platforms with 32-bit key_t');
9+
?>
10+
--FILE--
11+
<?php
12+
try {
13+
shmop_open(0x100000000, '', 0644, 1);
14+
} catch (ValueError $exception) {
15+
echo $exception->getMessage(), "\n";
16+
}
17+
?>
18+
--EXPECT--
19+
shmop_open(): Argument #1 ($key) is out of range

ext/sysvshm/sysvshm.c

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -126,10 +126,17 @@ PHP_FUNCTION(shm_attach)
126126
sysvshm_shm *shm_list_ptr;
127127
char *shm_ptr;
128128
sysvshm_chunk_head *chunk_ptr;
129-
zend_long shm_key, shm_id, shm_size, shm_flag = 0666;
129+
zend_long shm_key_arg, shm_id, shm_size, shm_flag = 0666;
130+
key_t shm_key;
130131
bool shm_size_is_null = true;
131132

132-
if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "l|l!l", &shm_key, &shm_size, &shm_size_is_null, &shm_flag)) {
133+
if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "l|l!l", &shm_key_arg, &shm_size, &shm_size_is_null, &shm_flag)) {
134+
RETURN_THROWS();
135+
}
136+
137+
shm_key = (key_t) shm_key_arg;
138+
if ((zend_long) shm_key != shm_key_arg) {
139+
zend_argument_value_error(1, "is out of range");
133140
RETURN_THROWS();
134141
}
135142

@@ -145,17 +152,17 @@ PHP_FUNCTION(shm_attach)
145152
/* get the id from a specified key or create new shared memory */
146153
if ((shm_id = shmget(shm_key, 0, 0)) < 0) {
147154
if (shm_size < (zend_long)sizeof(sysvshm_chunk_head)) {
148-
php_error_docref(NULL, E_WARNING, "Failed for key 0x" ZEND_XLONG_FMT ": memorysize too small", shm_key);
155+
php_error_docref(NULL, E_WARNING, "Failed for key 0x" ZEND_XLONG_FMT ": memorysize too small", shm_key_arg);
149156
RETURN_FALSE;
150157
}
151158
if ((shm_id = shmget(shm_key, shm_size, shm_flag | IPC_CREAT | IPC_EXCL)) < 0) {
152-
php_error_docref(NULL, E_WARNING, "Failed for key 0x" ZEND_XLONG_FMT ": %s", shm_key, strerror(errno));
159+
php_error_docref(NULL, E_WARNING, "Failed for key 0x" ZEND_XLONG_FMT ": %s", shm_key_arg, strerror(errno));
153160
RETURN_FALSE;
154161
}
155162
}
156163

157164
if ((shm_ptr = shmat(shm_id, NULL, 0)) == (void *) -1) {
158-
php_error_docref(NULL, E_WARNING, "Failed for key 0x" ZEND_XLONG_FMT ": %s", shm_key, strerror(errno));
165+
php_error_docref(NULL, E_WARNING, "Failed for key 0x" ZEND_XLONG_FMT ": %s", shm_key_arg, strerror(errno));
159166
RETURN_FALSE;
160167
}
161168

ext/sysvshm/tests/gh9945.phpt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
--TEST--
2+
GH-9945: shm_attach() must reject keys outside the key_t range
3+
--EXTENSIONS--
4+
sysvshm
5+
--SKIPIF--
6+
<?php
7+
if (PHP_INT_SIZE !== 8) die('skip only for 64-bit');
8+
if (PHP_OS_FAMILY !== 'Linux' && PHP_OS_FAMILY !== 'Windows') die('skip only for platforms with 32-bit key_t');
9+
?>
10+
--FILE--
11+
<?php
12+
try {
13+
shm_attach(0x100000000, 0);
14+
} catch (ValueError $exception) {
15+
echo $exception->getMessage(), "\n";
16+
}
17+
?>
18+
--EXPECT--
19+
shm_attach(): Argument #1 ($key) is out of range

0 commit comments

Comments
 (0)