[PHP-CVS] [php-src] PHP-8.5: ext/sysvshm: don't orphan the segment shm_attach() just created
[email protected] (Ilia Alshanetsky) Fri, 31 Jul 2026 20:50:54 +0000
| Newsgroups | php.cvs |
|---|---|
| Message-ID | <[email protected]> |
Author: Ilia Alshanetsky (iliaal)
Date: 2026-07-31T16:40:59-04:00
Commit: https://github.com/php/php-src/commit/a72e0636fe423a7b32739d502a0c40582d157fc1
Raw diff: https://github.com/php/php-src/commit/a72e0636fe423a7b32739d502a0c40582d157fc1.diff
ext/sysvshm: don't orphan the segment shm_attach() just created
When the key does not exist yet, shm_attach() creates the segment with
IPC_CREAT | IPC_EXCL and then attaches to it. If shmat() fails the
segment stays behind with no PHP handle able to remove it, and the
existence probe finds it on every later call, so a permission mask that
denies the caller wedges the key until ipcrm. Remove the segment on that
failure; IPC_EXCL makes the ownership flag exact, so one we opened
rather than created is never touched.
Closes GH-22959
Changed paths:
A ext/sysvshm/tests/shm_attach_failed_attach.phpt
M ext/sysvshm/sysvshm.c
Diff:
diff --git a/ext/sysvshm/sysvshm.c b/ext/sysvshm/sysvshm.c
index 3fa7c77add34..84c10add85ef 100644
--- a/ext/sysvshm/sysvshm.c
+++ b/ext/sysvshm/sysvshm.c
@@ -132,6 +132,7 @@ PHP_FUNCTION(shm_attach)
sysvshm_chunk_head *chunk_ptr;
zend_long shm_key, shm_id, shm_size, shm_flag = 0666;
bool shm_size_is_null = 1;
+ bool created = false;
if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "l|l!l", &shm_key, &shm_size, &shm_size_is_null, &shm_flag)) {
RETURN_THROWS();
@@ -156,10 +157,14 @@ PHP_FUNCTION(shm_attach)
php_error_docref(NULL, E_WARNING, "Failed for key 0x" ZEND_XLONG_FMT ": %s", shm_key, strerror(errno));
RETURN_FALSE;
}
+ created = true;
}
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));
+ if (created) {
+ shmctl(shm_id, IPC_RMID, NULL);
+ }
RETURN_FALSE;
}
diff --git a/ext/sysvshm/tests/shm_attach_failed_attach.phpt b/ext/sysvshm/tests/shm_attach_failed_attach.phpt
new file mode 100644
index 000000000000..34b3261a246b
--- /dev/null
+++ b/ext/sysvshm/tests/shm_attach_failed_attach.phpt
@@ -0,0 +1,34 @@
+--TEST--
+shm_attach() removes the segment it created when shmat() fails
+--EXTENSIONS--
+sysvshm
+posix
+--SKIPIF--
+<?php
+if (posix_geteuid() === 0) die('skip cannot run as root');
+?>
+--FILE--
+<?php
+$key = ftok(__FILE__, 't');
+
+var_dump(shm_attach($key, 1024, 0));
+
+$segment = shm_attach($key, 1024, 0600);
+
+if (!$segment instanceof SysvSharedMemory) {
+ die("the key is still held by the segment of the failed attach\n");
+}
+
+try {
+ var_dump(shm_put_var($segment, 1, 'value'));
+ var_dump(shm_get_var($segment, 1));
+} finally {
+ var_dump(shm_remove($segment));
+}
+?>
+--EXPECTF--
+Warning: shm_attach(): Failed for key 0x%x: %s in %s on line %d
+bool(false)
+bool(true)
+string(5) "value"
+bool(true)