Skip to content

Commit a72e063

Browse files
committed
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
1 parent ae42ecf commit a72e063

2 files changed

Lines changed: 39 additions & 0 deletions

File tree

ext/sysvshm/sysvshm.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ PHP_FUNCTION(shm_attach)
132132
sysvshm_chunk_head *chunk_ptr;
133133
zend_long shm_key, shm_id, shm_size, shm_flag = 0666;
134134
bool shm_size_is_null = 1;
135+
bool created = false;
135136

136137
if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "l|l!l", &shm_key, &shm_size, &shm_size_is_null, &shm_flag)) {
137138
RETURN_THROWS();
@@ -156,10 +157,14 @@ PHP_FUNCTION(shm_attach)
156157
php_error_docref(NULL, E_WARNING, "Failed for key 0x" ZEND_XLONG_FMT ": %s", shm_key, strerror(errno));
157158
RETURN_FALSE;
158159
}
160+
created = true;
159161
}
160162

161163
if ((shm_ptr = shmat(shm_id, NULL, 0)) == (void *) -1) {
162164
php_error_docref(NULL, E_WARNING, "Failed for key 0x" ZEND_XLONG_FMT ": %s", shm_key, strerror(errno));
165+
if (created) {
166+
shmctl(shm_id, IPC_RMID, NULL);
167+
}
163168
RETURN_FALSE;
164169
}
165170

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
--TEST--
2+
shm_attach() removes the segment it created when shmat() fails
3+
--EXTENSIONS--
4+
sysvshm
5+
posix
6+
--SKIPIF--
7+
<?php
8+
if (posix_geteuid() === 0) die('skip cannot run as root');
9+
?>
10+
--FILE--
11+
<?php
12+
$key = ftok(__FILE__, 't');
13+
14+
var_dump(shm_attach($key, 1024, 0));
15+
16+
$segment = shm_attach($key, 1024, 0600);
17+
18+
if (!$segment instanceof SysvSharedMemory) {
19+
die("the key is still held by the segment of the failed attach\n");
20+
}
21+
22+
try {
23+
var_dump(shm_put_var($segment, 1, 'value'));
24+
var_dump(shm_get_var($segment, 1));
25+
} finally {
26+
var_dump(shm_remove($segment));
27+
}
28+
?>
29+
--EXPECTF--
30+
Warning: shm_attach(): Failed for key 0x%x: %s in %s on line %d
31+
bool(false)
32+
bool(true)
33+
string(5) "value"
34+
bool(true)

0 commit comments

Comments
 (0)