diff --git a/NEWS b/NEWS index 4364d69650e5..bccca2fed5bd 100644 --- a/NEWS +++ b/NEWS @@ -25,6 +25,12 @@ PHP NEWS is_writable(), is_readable(), is_executable(), is_file(), is_dir(), is_link(), file_exists(), lstat(), stat(). (Girgias) +- Sysvmsg: + . Fixed msg_queue_exists() creating and leaking a message queue when passed + IPC_PRIVATE. (iliaal) + . Fixed msg_queue_exists() and msg_get_queue() to throw a ValueError for keys + outside the key_t range. (iliaal) + 30 Jul 2026, PHP 8.6.0alpha3 - Core: diff --git a/ext/sysvmsg/sysvmsg.c b/ext/sysvmsg/sysvmsg.c index 0c2b3dcf183b..965e6a66fb31 100644 --- a/ext/sysvmsg/sysvmsg.c +++ b/ext/sysvmsg/sysvmsg.c @@ -192,12 +192,23 @@ PHP_FUNCTION(msg_stat_queue) /* {{{ Check whether a message queue exists */ PHP_FUNCTION(msg_queue_exists) { - zend_long key; + zend_long key_arg; + key_t key; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &key_arg) == FAILURE) { + RETURN_THROWS(); + } - if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &key) == FAILURE) { + key = (key_t) key_arg; + if ((zend_long) key != key_arg) { + zend_argument_value_error(1, "is out of range"); RETURN_THROWS(); } + if (key == IPC_PRIVATE) { + RETURN_FALSE; + } + RETURN_BOOL(msgget(key, 0) >= 0); } /* }}} */ @@ -205,11 +216,18 @@ PHP_FUNCTION(msg_queue_exists) /* {{{ Attach to a message queue */ PHP_FUNCTION(msg_get_queue) { - zend_long key; + zend_long key_arg; zend_long perms = 0666; + key_t key; sysvmsg_queue_t *mq; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|l", &key, &perms) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|l", &key_arg, &perms) == 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(); } @@ -217,12 +235,16 @@ PHP_FUNCTION(msg_get_queue) mq = Z_SYSVMSG_QUEUE_P(return_value); mq->key = key; - mq->id = msgget(key, 0); + if (key == IPC_PRIVATE) { + mq->id = -1; + } else { + mq->id = msgget(key, 0); + } if (mq->id < 0) { /* doesn't already exist; create it */ mq->id = msgget(key, IPC_CREAT | IPC_EXCL | perms); if (mq->id < 0) { - php_error_docref(NULL, E_WARNING, "Failed for key 0x" ZEND_XLONG_FMT ": %s", key, strerror(errno)); + php_error_docref(NULL, E_WARNING, "Failed for key 0x" ZEND_XLONG_FMT ": %s", key_arg, strerror(errno)); zval_ptr_dtor(return_value); RETURN_FALSE; } diff --git a/ext/sysvmsg/tests/gh9945.phpt b/ext/sysvmsg/tests/gh9945.phpt new file mode 100644 index 000000000000..e346bde9fc29 --- /dev/null +++ b/ext/sysvmsg/tests/gh9945.phpt @@ -0,0 +1,26 @@ +--TEST-- +GH-9945: sysvmsg must reject keys outside the key_t range +--EXTENSIONS-- +sysvmsg +--SKIPIF-- + +--FILE-- +getMessage(), "\n"; +} + +try { + msg_get_queue(0x100000000); +} catch (ValueError $exception) { + echo $exception::class, ": ", $exception->getMessage(), "\n"; +} +?> +--EXPECT-- +ValueError: msg_queue_exists(): Argument #1 ($key) is out of range +ValueError: msg_get_queue(): Argument #1 ($key) is out of range diff --git a/ext/sysvmsg/tests/msg_queue_ipc_private.phpt b/ext/sysvmsg/tests/msg_queue_ipc_private.phpt new file mode 100644 index 000000000000..951cf62f2ab9 --- /dev/null +++ b/ext/sysvmsg/tests/msg_queue_ipc_private.phpt @@ -0,0 +1,28 @@ +--TEST-- +msg_queue_exists() and msg_get_queue() with IPC_PRIVATE +--EXTENSIONS-- +sysvmsg +--FILE-- + +--EXPECT-- +bool(false) +bool(false) +600 +bool(true) +bool(true) +string(5) "hello" +bool(true)