Skip to content

Commit 969b7b3

Browse files
committed
ext/sysvmsg: fix IPC_PRIVATE and out-of-range key handling
msgget() always creates a queue for IPC_PRIVATE, so the existence probe in msg_queue_exists() leaks one per call, and the same probe in msg_get_queue() shadows the IPC_CREAT branch and hands back a queue with no permission bits. Skip the probe for IPC_PRIVATE. Both functions also passed the zend_long key straight to msgget(), where it truncates to key_t; they now reject out-of-range keys as shmop_open() and shm_attach() have since GH-9945. Closes GH-22956
1 parent 9ed85af commit 969b7b3

4 files changed

Lines changed: 88 additions & 6 deletions

File tree

NEWS

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@ PHP NEWS
2525
is_writable(), is_readable(), is_executable(), is_file(), is_dir(),
2626
is_link(), file_exists(), lstat(), stat(). (Girgias)
2727

28+
- Sysvmsg:
29+
. Fixed msg_queue_exists() creating and leaking a message queue when passed
30+
IPC_PRIVATE. (iliaal)
31+
. Fixed msg_queue_exists() and msg_get_queue() to throw a ValueError for keys
32+
outside the key_t range. (iliaal)
33+
2834
30 Jul 2026, PHP 8.6.0alpha3
2935

3036
- Core:

ext/sysvmsg/sysvmsg.c

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -192,37 +192,59 @@ PHP_FUNCTION(msg_stat_queue)
192192
/* {{{ Check whether a message queue exists */
193193
PHP_FUNCTION(msg_queue_exists)
194194
{
195-
zend_long key;
195+
zend_long key_arg;
196+
key_t key;
197+
198+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &key_arg) == FAILURE) {
199+
RETURN_THROWS();
200+
}
196201

197-
if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &key) == FAILURE) {
202+
key = (key_t) key_arg;
203+
if ((zend_long) key != key_arg) {
204+
zend_argument_value_error(1, "is out of range");
198205
RETURN_THROWS();
199206
}
200207

208+
if (key == IPC_PRIVATE) {
209+
RETURN_FALSE;
210+
}
211+
201212
RETURN_BOOL(msgget(key, 0) >= 0);
202213
}
203214
/* }}} */
204215

205216
/* {{{ Attach to a message queue */
206217
PHP_FUNCTION(msg_get_queue)
207218
{
208-
zend_long key;
219+
zend_long key_arg;
209220
zend_long perms = 0666;
221+
key_t key;
210222
sysvmsg_queue_t *mq;
211223

212-
if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|l", &key, &perms) == FAILURE) {
224+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|l", &key_arg, &perms) == FAILURE) {
225+
RETURN_THROWS();
226+
}
227+
228+
key = (key_t) key_arg;
229+
if ((zend_long) key != key_arg) {
230+
zend_argument_value_error(1, "is out of range");
213231
RETURN_THROWS();
214232
}
215233

216234
object_init_ex(return_value, sysvmsg_queue_ce);
217235
mq = Z_SYSVMSG_QUEUE_P(return_value);
218236

219237
mq->key = key;
220-
mq->id = msgget(key, 0);
238+
if (key == IPC_PRIVATE) {
239+
mq->id = -1;
240+
} else {
241+
mq->id = msgget(key, 0);
242+
}
221243
if (mq->id < 0) {
222244
/* doesn't already exist; create it */
223245
mq->id = msgget(key, IPC_CREAT | IPC_EXCL | perms);
224246
if (mq->id < 0) {
225-
php_error_docref(NULL, E_WARNING, "Failed for key 0x" ZEND_XLONG_FMT ": %s", key, strerror(errno));
247+
php_error_docref(NULL, E_WARNING, "Failed for key 0x" ZEND_XLONG_FMT ": %s", key_arg, strerror(errno));
226248
zval_ptr_dtor(return_value);
227249
RETURN_FALSE;
228250
}

ext/sysvmsg/tests/gh9945.phpt

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
--TEST--
2+
GH-9945: sysvmsg must reject keys outside the key_t range
3+
--EXTENSIONS--
4+
sysvmsg
5+
--SKIPIF--
6+
<?php
7+
if (PHP_INT_SIZE !== 8) die('skip only for 64-bit');
8+
if (PHP_OS_FAMILY !== 'Linux') die('skip only for platforms with 32-bit key_t');
9+
?>
10+
--FILE--
11+
<?php
12+
try {
13+
msg_queue_exists(0x100000000);
14+
} catch (ValueError $exception) {
15+
echo $exception::class, ": ", $exception->getMessage(), "\n";
16+
}
17+
18+
try {
19+
msg_get_queue(0x100000000);
20+
} catch (ValueError $exception) {
21+
echo $exception::class, ": ", $exception->getMessage(), "\n";
22+
}
23+
?>
24+
--EXPECT--
25+
ValueError: msg_queue_exists(): Argument #1 ($key) is out of range
26+
ValueError: msg_get_queue(): Argument #1 ($key) is out of range
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
--TEST--
2+
msg_queue_exists() and msg_get_queue() with IPC_PRIVATE
3+
--EXTENSIONS--
4+
sysvmsg
5+
--FILE--
6+
<?php
7+
var_dump(msg_queue_exists(0));
8+
9+
$queue = msg_get_queue(0, 0600);
10+
11+
try {
12+
var_dump(msg_queue_exists(0));
13+
printf("%o\n", msg_stat_queue($queue)['msg_perm.mode']);
14+
var_dump(msg_send($queue, 1, 'hello'));
15+
var_dump(msg_receive($queue, 1, $type, 1024, $message));
16+
var_dump($message);
17+
} finally {
18+
var_dump(msg_remove_queue($queue));
19+
}
20+
?>
21+
--EXPECT--
22+
bool(false)
23+
bool(false)
24+
600
25+
bool(true)
26+
bool(true)
27+
string(5) "hello"
28+
bool(true)

0 commit comments

Comments
 (0)