1616
1717#ifdef PHP_USER_CACHE_USE_SHM_OPEN
1818
19+ #include <errno.h>
1920#include <stdio.h>
2021#include <stdlib.h>
2122#include <unistd.h>
2425#include <sys/stat.h>
2526#include <sys/mman.h>
2627
28+ #include "ext/random/php_random_csprng.h"
29+
30+ #define PHP_USER_CACHE_POSIX_SHM_NAME_PREFIX "/php_uc."
31+ #define PHP_USER_CACHE_POSIX_SHM_NAME_BYTES 10
32+ #define PHP_USER_CACHE_POSIX_SHM_NAME_ATTEMPTS 5
33+
2734typedef struct {
2835 php_user_cache_shm_segment common ;
2936 int shm_fd ;
3037} php_user_cache_shm_segment_posix ;
3138
39+ static bool user_cache_alloc_posix_segment_name (char * buf , size_t buf_size )
40+ {
41+ static const char hexits [] = "0123456789abcdef" ;
42+ unsigned char random_bytes [PHP_USER_CACHE_POSIX_SHM_NAME_BYTES ];
43+ char hex [sizeof (random_bytes ) * 2 + 1 ];
44+ size_t i ;
45+
46+ if (php_random_bytes_silent (random_bytes , sizeof (random_bytes )) == FAILURE ) {
47+ return false;
48+ }
49+
50+ for (i = 0 ; i < sizeof (random_bytes ); i ++ ) {
51+ hex [i * 2 ] = hexits [random_bytes [i ] >> 4 ];
52+ hex [(i * 2 ) + 1 ] = hexits [random_bytes [i ] & 0xf ];
53+ }
54+ hex [sizeof (hex ) - 1 ] = '\0' ;
55+
56+ snprintf (buf , buf_size , PHP_USER_CACHE_POSIX_SHM_NAME_PREFIX "%s" , hex );
57+
58+ return true;
59+ }
60+
3261static int user_cache_alloc_posix_create_segments (size_t requested_size , php_user_cache_shm_segment_posix * * * shared_segments_p , int * shared_segments_count , const char * * error_in )
3362{
3463 php_user_cache_shm_segment_posix * shared_segment ;
35- int shared_segment_flags = O_RDWR | O_CREAT | O_TRUNC ;
36- char shared_segment_name [sizeof ("/php_user_cache." ) + 20 ];
3764 mode_t shared_segment_mode = 0600 ;
65+ /* O_EXCL: never adopt an object somebody else created under this name. */
66+ int shared_segment_flags = O_RDWR | O_CREAT | O_EXCL ,
67+ shared_segment_fd = -1 , shared_segment_attempt ;
68+ char shared_segment_name [sizeof (PHP_USER_CACHE_POSIX_SHM_NAME_PREFIX ) + (PHP_USER_CACHE_POSIX_SHM_NAME_BYTES * 2 )];
3869
3970#if defined(HAVE_SHM_CREATE_LARGEPAGE )
4071 /* Prefer the largest compatible page size. Capture the getpagesizes()
@@ -69,30 +100,52 @@ static int user_cache_alloc_posix_create_segments(size_t requested_size, php_use
69100 shared_segment = (php_user_cache_shm_segment_posix * )((char * )(* shared_segments_p ) + sizeof (void * ));
70101 (* shared_segments_p )[0 ] = shared_segment ;
71102
72- snprintf (shared_segment_name , sizeof (shared_segment_name ), "/php_user_cache.%d" , getpid ());
103+ for (shared_segment_attempt = 0 ; shared_segment_attempt < PHP_USER_CACHE_POSIX_SHM_NAME_ATTEMPTS ; shared_segment_attempt ++ ) {
104+ if (!user_cache_alloc_posix_segment_name (shared_segment_name , sizeof (shared_segment_name ))) {
105+ * error_in = "php_random_bytes" ;
106+
107+ return PHP_USER_CACHE_ALLOC_FAILURE ;
108+ }
109+
73110#if defined(HAVE_SHM_CREATE_LARGEPAGE )
74- if (shared_segment_lg_index > 0 ) {
75- shared_segment -> shm_fd = shm_create_largepage (shared_segment_name , shared_segment_flags , shared_segment_lg_index , SHM_LARGEPAGE_ALLOC_DEFAULT , shared_segment_mode );
76- if (shared_segment -> shm_fd != -1 ) {
77- goto truncate_segment ;
111+ if (shared_segment_lg_index > 0 ) {
112+ shared_segment_fd = shm_create_largepage (shared_segment_name , shared_segment_flags , shared_segment_lg_index , SHM_LARGEPAGE_ALLOC_DEFAULT , shared_segment_mode );
113+ if (shared_segment_fd != -1 ) {
114+ shared_segment -> shm_fd = shared_segment_fd ;
115+
116+ goto truncate_segment ;
117+ }
78118 }
79- }
80119#endif /* HAVE_SHM_CREATE_LARGEPAGE */
81120
82- shared_segment -> shm_fd = shm_open (shared_segment_name , shared_segment_flags , shared_segment_mode );
83- if (shared_segment -> shm_fd == -1 ) {
121+ shared_segment_fd = shm_open (shared_segment_name , shared_segment_flags , shared_segment_mode );
122+ if (shared_segment_fd != -1 ) {
123+ break ;
124+ }
125+
126+ if (errno != EEXIST ) {
127+ * error_in = "shm_open" ;
128+
129+ return PHP_USER_CACHE_ALLOC_FAILURE ;
130+ }
131+ }
132+
133+ if (shared_segment_fd == -1 ) {
84134 * error_in = "shm_open" ;
85135
86136 return PHP_USER_CACHE_ALLOC_FAILURE ;
87137 }
88138
139+ shared_segment -> shm_fd = shared_segment_fd ;
140+
89141#if defined(HAVE_SHM_CREATE_LARGEPAGE )
90142truncate_segment :
91143#endif /* HAVE_SHM_CREATE_LARGEPAGE */
92144 if (ftruncate (shared_segment -> shm_fd , requested_size ) != 0 ) {
93145 * error_in = "ftruncate" ;
94146
95147 close (shared_segment -> shm_fd );
148+
96149 shm_unlink (shared_segment_name );
97150
98151 return PHP_USER_CACHE_ALLOC_FAILURE ;
@@ -103,12 +156,23 @@ static int user_cache_alloc_posix_create_segments(size_t requested_size, php_use
103156 * error_in = "mmap" ;
104157
105158 close (shared_segment -> shm_fd );
159+
106160 shm_unlink (shared_segment_name );
107161
108162 return PHP_USER_CACHE_ALLOC_FAILURE ;
109163 }
110164
111- shm_unlink (shared_segment_name );
165+ if (shm_unlink (shared_segment_name ) != 0 ) {
166+ * error_in = "shm_unlink" ;
167+
168+ munmap (shared_segment -> common .p , requested_size );
169+
170+ shared_segment -> common .p = NULL ;
171+
172+ close (shared_segment -> shm_fd );
173+
174+ return PHP_USER_CACHE_ALLOC_FAILURE ;
175+ }
112176
113177 shared_segment -> common .size = requested_size ;
114178
0 commit comments