[php-src] PHP-8.5: TSRM: Fix Windows shared memory payload offset

From: Date: Thu, 01 Oct 2026 21:47:54 +0000
Subject: [php-src] PHP-8.5: TSRM: Fix Windows shared memory payload offset
Groups: php.cvs 
Request: Send a blank email to php-cvs+get-141857@lists.php.net to get a copy of this message
Author: Ilia Alshanetsky (iliaal) Date: 2026-10-01T17:18:50-04:00 Commit: https://github.com/php/php-src/commit/e50b8b05be8881072f29e9311000390d9fef2468 Raw diff: https://github.com/php/php-src/commit/e50b8b05be8881072f29e9311000390d9fef2468.diff TSRM: Fix Windows shared memory payload offset shmat() returned shm->descriptor + sizeof(shm->descriptor), which scales the pointer-size offset by sizeof(struct shmid_ds), while shmget() reserved only pointer-size bytes for the descriptor and stored that inflated size in shm_segsz. shmop and sysvshm therefore read and wrote past the end of the mapping. Reserve sizeof(struct shmid_ds), return the address right after the descriptor, and keep shm_segsz at the requested size. Closes GH-24042 Changed paths: A ext/shmop/tests/tsrm_shmat.phpt M NEWS M TSRM/tsrm_win32.c Diff: diff --git a/NEWS b/NEWS index 439f7c83f2c1..edeca96eaebd 100644 --- a/NEWS +++ b/NEWS @@ -28,6 +28,8 @@ PHP NEWS throwing deprecation). (lazerg) . Fixed use-after-free when a dl()-loaded extension declares a frameless function and a later request calls it. (Ilia Alshanetsky) + . Fixed System V shared memory emulation for Windows attaching segments past + the end of their mapping. (Ilia Alshanetsky) - DOM: . Fixed use-after-free when re-constructing a DOMXPath whose php:function diff --git a/TSRM/tsrm_win32.c b/TSRM/tsrm_win32.c index 1fe2a47a87c2..e49aac76121c 100644 --- a/TSRM/tsrm_win32.c +++ b/TSRM/tsrm_win32.c @@ -635,6 +635,7 @@ static key_t tsrm_choose_random_shm_key(key_t prev_key) { TSRM_API int shmget(key_t key, size_t size, int flags) {/*{{{*/ shm_pair *shm; + size_t mapping_size; char shm_segment[sizeof(SEGMENT_PREFIX INT_MIN_AS_STRING)]; HANDLE shm_handle = NULL, info_handle = NULL; BOOL created = FALSE; @@ -650,16 +651,16 @@ TSRM_API int shmget(key_t key, size_t size, int flags) if (!shm_handle) { if (flags & IPC_CREAT) { - if (size == 0 || size > SIZE_MAX - sizeof(shm->descriptor)) { + if (size == 0 || size > SIZE_MAX - sizeof(*shm->descriptor)) { return -1; } - size += sizeof(shm->descriptor); + mapping_size = size + sizeof(*shm->descriptor); #if SIZEOF_SIZE_T == 8 - DWORD high = size >> 32; - DWORD low = (DWORD)size; + DWORD high = mapping_size >> 32; + DWORD low = (DWORD)mapping_size; #else DWORD high = 0; - DWORD low = size; + DWORD low = mapping_size; #endif shm_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, high, low, key == IPC_PRIVATE ? NULL : shm_segment); created = TRUE; @@ -730,7 +731,7 @@ TSRM_API void *shmat(int key, const void *shmaddr, int flags) return (void*)-1; } - shm->addr = shm->descriptor + sizeof(shm->descriptor); + shm->addr = shm->descriptor + 1; shm->descriptor->shm_atime = time(NULL); shm->descriptor->shm_lpid = getpid(); shm->descriptor->shm_nattch++; diff --git a/ext/shmop/tests/tsrm_shmat.phpt b/ext/shmop/tests/tsrm_shmat.phpt new file mode 100644 index 000000000000..3a5b92efcf87 --- /dev/null +++ b/ext/shmop/tests/tsrm_shmat.phpt @@ -0,0 +1,24 @@ +--TEST-- +TSRM Windows shmop keeps the payload within its mapping +--EXTENSIONS-- +shmop +--SKIPIF-- +<?php +if (PHP_OS_FAMILY !== 'Windows') die('skip only for Windows'); +?> +--FILE-- +<?php +$shm = shmop_open(0, 'c', 0644, 65472); +$payload = str_repeat('x', 65471) . 'z'; +var_dump($shm !== false); +var_dump(shmop_size($shm)); +var_dump(shmop_write($shm, $payload, 0)); +var_dump(shmop_read($shm, 65471, 1)); +var_dump(shmop_delete($shm)); +?> +--EXPECT-- +bool(true) +int(65472) +int(65472) +string(1) "z" +bool(true)

« previous php.cvs (#141857) next »