Skip to content

ext/sysvshm: don't orphan the segment shm_attach() just created - #22959

Closed
iliaal wants to merge 1 commit into
php:PHP-8.4from
iliaal:fix/sysvshm-orphan-segment
Closed

ext/sysvshm: don't orphan the segment shm_attach() just created#22959
iliaal wants to merge 1 commit into
php:PHP-8.4from
iliaal:fix/sysvshm-orphan-segment

Conversation

@iliaal

@iliaal iliaal commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

shm_attach() probes with shmget($key, 0, 0) and, when that fails, creates the segment with IPC_CREAT | IPC_EXCL before attaching. A failing shmat() then returns false and drops the id, so the segment it created stays in the kernel with nothing on the PHP side able to remove it. The next call probes successfully, finds the orphan and fails on the same shmat(), so the key stays wedged until someone runs ipcrm:

$key = ftok(__FILE__, 't');
var_dump(shm_attach($key, 1024, 0));     // false: mode 0000 denies the owner's own attach
var_dump(shm_attach($key, 1024, 0600));  // false, and stays false on every later run

IPC_EXCL is what makes the ownership flag safe here. A successful probe means the segment predates the call, so only the create branch sets it, and the removal can't destroy a segment we merely opened. ext/opcache/shared_alloc_shm.c does the same IPC_RMID on shmat() failure without an ownership check, since it only ever creates its own.

shmop_open() has the same defect on three exits after a create and cannot take this guard as-is: its "c" mode passes IPC_CREAT without IPC_EXCL, so one shmget() can't tell a create from an open. That needs its own change.

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 phpGH-22959
@iliaal iliaal closed this in a72e063 Jul 31, 2026
devnexen added a commit to devnexen/php-src that referenced this pull request Aug 1, 2026
shm_attach() wrote the requested size into the header of a segment it
did not create, so a foreign segment framed as larger than it is let
shm_put_var() write past the mapping. Take the size from shmctl()
IPC_STAT instead, and reject a segment too small to hold the header.

Noticed while reviewing phpGH-22959.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

2 participants