Skip to content

Commit b593b53

Browse files
committed
Merge branch 'PHP-8.2'
* PHP-8.2: Fix Windows shmget() wrt. IPC_PRIVATE
2 parents 2ca03be + 9089e15 commit b593b53

File tree

1 file changed

+33
-0
lines changed

1 file changed

+33
-0
lines changed

TSRM/tsrm_win32.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "tsrm_win32.h"
3131
#include "zend_virtual_cwd.h"
3232
#include "win32/ioutil.h"
33+
#include "win32/winutil.h"
3334

3435
#ifdef ZTS
3536
static ts_rsrc_id win32_globals_id;
@@ -610,6 +611,22 @@ TSRM_API int pclose(FILE *stream)
610611
#define SEGMENT_PREFIX "TSRM_SHM_SEGMENT:"
611612
#define INT_MIN_AS_STRING "-2147483648"
612613

614+
615+
#define TSRM_BASE_SHM_KEY_ADDRESS 0x20000000
616+
/* Returns a number between 0x2000_0000 and 0x3fff_ffff. On Windows, key_t is int. */
617+
static key_t tsrm_choose_random_shm_key(key_t prev_key) {
618+
unsigned char buf[4];
619+
if (php_win32_get_random_bytes(buf, 4) != SUCCESS) {
620+
return prev_key + 2;
621+
}
622+
uint32_t n =
623+
((uint32_t)(buf[0]) << 24) |
624+
(((uint32_t)buf[1]) << 16) |
625+
(((uint32_t)buf[2]) << 8) |
626+
(((uint32_t)buf[3]));
627+
return (n & 0x1fffffff) + TSRM_BASE_SHM_KEY_ADDRESS;
628+
}
629+
613630
TSRM_API int shmget(key_t key, size_t size, int flags)
614631
{/*{{{*/
615632
shm_pair *shm;
@@ -621,6 +638,9 @@ TSRM_API int shmget(key_t key, size_t size, int flags)
621638
snprintf(shm_segment, sizeof(shm_segment), SEGMENT_PREFIX "%d", key);
622639

623640
shm_handle = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, shm_segment);
641+
} else {
642+
/* IPC_PRIVATE always creates a new segment even if IPC_CREAT flag isn't passed. */
643+
flags |= IPC_CREAT;
624644
}
625645

626646
if (!shm_handle) {
@@ -649,6 +669,19 @@ TSRM_API int shmget(key_t key, size_t size, int flags)
649669
}
650670
}
651671

672+
if (key == IPC_PRIVATE) {
673+
/* 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
674+
* 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. */
675+
key = tsrm_choose_random_shm_key(TSRM_BASE_SHM_KEY_ADDRESS);
676+
for (shm_pair *ptr = TWG(shm); ptr < (TWG(shm) + TWG(shm_size)); ptr++) {
677+
if (ptr->descriptor && ptr->descriptor->shm_perm.key == key) {
678+
key = tsrm_choose_random_shm_key(key);
679+
ptr = TWG(shm);
680+
continue;
681+
}
682+
}
683+
}
684+
652685
shm = shm_get(key, NULL);
653686
if (!shm) {
654687
CloseHandle(shm_handle);

0 commit comments

Comments
 (0)