diff --git a/TSRM/tsrm_win32.c b/TSRM/tsrm_win32.c index a748a3b105f2e..4b5c58d6982a1 100644 --- a/TSRM/tsrm_win32.c +++ b/TSRM/tsrm_win32.c @@ -30,6 +30,7 @@ #include "tsrm_win32.h" #include "zend_virtual_cwd.h" #include "win32/ioutil.h" +#include "win32/winutil.h" #ifdef ZTS static ts_rsrc_id win32_globals_id; @@ -613,6 +614,22 @@ TSRM_API int pclose(FILE *stream) #define DESCRIPTOR_PREFIX "TSRM_SHM_DESCRIPTOR:" #define INT_MIN_AS_STRING "-2147483648" + +#define TSRM_BASE_SHM_KEY_ADDRESS 0x20000000 +/* Returns a number between 0x2000_0000 and 0x3fff_ffff. On Windows, key_t is int. */ +static key_t tsrm_choose_random_shm_key(key_t prev_key) { + unsigned char buf[4]; + if (php_win32_get_random_bytes(buf, 4) != SUCCESS) { + return prev_key + 2; + } + uint32_t n = + ((uint32_t)(buf[0]) << 24) | + (((uint32_t)buf[1]) << 16) | + (((uint32_t)buf[2]) << 8) | + (((uint32_t)buf[3])); + return (n & 0x1fffffff) + TSRM_BASE_SHM_KEY_ADDRESS; +} + TSRM_API int shmget(key_t key, size_t size, int flags) {/*{{{*/ shm_pair *shm; @@ -626,6 +643,9 @@ TSRM_API int shmget(key_t key, size_t size, int flags) shm_handle = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, shm_segment); info_handle = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, shm_info); + } else { + /* IPC_PRIVATE always creates a new segment even if IPC_CREAT flag isn't passed. */ + flags |= IPC_CREAT; } if (!shm_handle && !info_handle) { @@ -662,6 +682,19 @@ TSRM_API int shmget(key_t key, size_t size, int flags) } } + if (key == IPC_PRIVATE) { + /* This should call shm_get with a brand new key id that isn't used yet. See https://man7.org/linux/man-pages/man2/shmget.2.html + * Because extensions such as shmop/sysvshm can be used in userland to attach to shared memory segments, use unpredictable high positive numbers to avoid accidentally conflicting with userland. */ + key = tsrm_choose_random_shm_key(TSRM_BASE_SHM_KEY_ADDRESS); + for (shm_pair *ptr = TWG(shm); ptr < (TWG(shm) + TWG(shm_size)); ptr++) { + if (ptr->descriptor && ptr->descriptor->shm_perm.key == key) { + key = tsrm_choose_random_shm_key(key); + ptr = TWG(shm); + continue; + } + } + } + shm = shm_get(key, NULL); if (!shm) { CloseHandle(shm_handle);