58
58
#include "zend_multiply.h"
59
59
#include "zend_bitset.h"
60
60
#include "zend_mmap.h"
61
+ #include "zend_portability.h"
62
+ #include "ext/random/php_random_csprng.h"
63
+ #include "ext/random/php_random.h"
61
64
#include <signal.h>
62
65
63
66
#ifdef HAVE_UNISTD_H
@@ -200,6 +203,8 @@ typedef struct _zend_mm_free_slot zend_mm_free_slot;
200
203
typedef struct _zend_mm_chunk zend_mm_chunk ;
201
204
typedef struct _zend_mm_huge_list zend_mm_huge_list ;
202
205
206
+ typedef uintptr_t zend_mm_free_slot_shadow ;
207
+
203
208
static bool zend_mm_use_huge_pages = false;
204
209
205
210
/*
@@ -245,6 +250,7 @@ struct _zend_mm_heap {
245
250
size_t size ; /* current memory usage */
246
251
size_t peak ; /* peak memory usage */
247
252
#endif
253
+ uintptr_t key ;
248
254
zend_mm_free_slot * free_slot [ZEND_MM_BINS ]; /* free lists for small sizes */
249
255
#if ZEND_MM_STAT || ZEND_MM_LIMIT
250
256
size_t real_size ; /* current size of allocated pages */
@@ -275,6 +281,8 @@ struct _zend_mm_heap {
275
281
} custom_heap ;
276
282
HashTable * tracked_allocs ;
277
283
#endif
284
+ pid_t pid ;
285
+ php_random_status_state_xoshiro256starstar random_state ;
278
286
};
279
287
280
288
struct _zend_mm_chunk {
@@ -318,7 +326,7 @@ struct _zend_mm_huge_list {
318
326
#define ZEND_MM_PAGE_ADDR (chunk , page_num ) \
319
327
((void*)(((zend_mm_page*)(chunk)) + (page_num)))
320
328
321
- #define _BIN_DATA_SIZE (num , size , elements , pages , x , y ) size,
329
+ #define _BIN_DATA_SIZE (num , size , elements , pages , x , y ) MAX( size, sizeof(void*)*2) ,
322
330
static const uint32_t bin_data_size [] = {
323
331
ZEND_MM_BINS_INFO (_BIN_DATA_SIZE , x , y )
324
332
};
@@ -333,6 +341,12 @@ static const uint32_t bin_pages[] = {
333
341
ZEND_MM_BINS_INFO (_BIN_DATA_PAGES , x , y )
334
342
};
335
343
344
+ #define _BIN_SHADOW_OFFSET (num , size , elements , pages , x , y ) \
345
+ ((MAX(MIN(size, 64), sizeof(void*)*2) - sizeof(void*)) / sizeof(void*)),
346
+ static const uint32_t bin_shadow_offset [] = {
347
+ ZEND_MM_BINS_INFO (_BIN_SHADOW_OFFSET , x , y )
348
+ };
349
+
336
350
#if ZEND_DEBUG
337
351
ZEND_COLD void zend_debug_alloc_output (char * format , ...)
338
352
{
@@ -1248,6 +1262,35 @@ static zend_always_inline int zend_mm_small_size_to_bin(size_t size)
1248
1262
1249
1263
#define ZEND_MM_SMALL_SIZE_TO_BIN (size ) zend_mm_small_size_to_bin(size)
1250
1264
1265
+ static zend_always_inline void zend_mm_set_next_free_slot (zend_mm_heap * heap , uint32_t bin_num , zend_mm_free_slot * slot , zend_mm_free_slot * next )
1266
+ {
1267
+ slot -> next_free_slot = next ;
1268
+ * ((zend_mm_free_slot_shadow * )slot + bin_shadow_offset [bin_num ]) = (zend_mm_free_slot_shadow )next ^ heap -> key ;
1269
+ }
1270
+
1271
+ static zend_always_inline void zend_mm_copy_next_free_slot (zend_mm_free_slot * dest , uint32_t bin_num , zend_mm_free_slot * from )
1272
+ {
1273
+ dest -> next_free_slot = from -> next_free_slot ;
1274
+ * ((zend_mm_free_slot_shadow * )dest + bin_shadow_offset [bin_num ]) = * ((zend_mm_free_slot_shadow * )from + bin_shadow_offset [bin_num ]);
1275
+ }
1276
+
1277
+ static ZEND_COLD ZEND_NORETURN void zend_mm_free_slot_corrupted (void )
1278
+ {
1279
+ zend_mm_panic ("zend_mm_heap corrupted" );
1280
+ }
1281
+
1282
+ static zend_always_inline zend_mm_free_slot * zend_mm_check_next_free_slot (zend_mm_heap * heap , uint32_t bin_num , zend_mm_free_slot * slot )
1283
+ {
1284
+ zend_mm_free_slot * next = slot -> next_free_slot ;
1285
+ if (EXPECTED (next != NULL )) {
1286
+ zend_mm_free_slot_shadow shadow = * ((zend_mm_free_slot_shadow * )slot + bin_shadow_offset [bin_num ]);
1287
+ if (UNEXPECTED (next != (zend_mm_free_slot * )(shadow ^ heap -> key ))) {
1288
+ zend_mm_free_slot_corrupted ();
1289
+ }
1290
+ }
1291
+ return next ;
1292
+ }
1293
+
1251
1294
static zend_never_inline void * zend_mm_alloc_small_slow (zend_mm_heap * heap , uint32_t bin_num ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC )
1252
1295
{
1253
1296
zend_mm_chunk * chunk ;
@@ -1281,7 +1324,7 @@ static zend_never_inline void *zend_mm_alloc_small_slow(zend_mm_heap *heap, uint
1281
1324
end = (zend_mm_free_slot * )((char * )bin + (bin_data_size [bin_num ] * (bin_elements [bin_num ] - 1 )));
1282
1325
heap -> free_slot [bin_num ] = p = (zend_mm_free_slot * )((char * )bin + bin_data_size [bin_num ]);
1283
1326
do {
1284
- p -> next_free_slot = (zend_mm_free_slot * )((char * )p + bin_data_size [bin_num ]);
1327
+ zend_mm_set_next_free_slot ( heap , bin_num , p , (zend_mm_free_slot * )((char * )p + bin_data_size [bin_num ]) );
1285
1328
#if ZEND_DEBUG
1286
1329
do {
1287
1330
zend_mm_debug_info * dbg = (zend_mm_debug_info * )((char * )p + bin_data_size [bin_num ] - ZEND_MM_ALIGNED_SIZE (sizeof (zend_mm_debug_info )));
@@ -1317,7 +1360,7 @@ static zend_always_inline void *zend_mm_alloc_small(zend_mm_heap *heap, int bin_
1317
1360
1318
1361
if (EXPECTED (heap -> free_slot [bin_num ] != NULL )) {
1319
1362
zend_mm_free_slot * p = heap -> free_slot [bin_num ];
1320
- heap -> free_slot [bin_num ] = p -> next_free_slot ;
1363
+ heap -> free_slot [bin_num ] = zend_mm_check_next_free_slot ( heap , bin_num , p ) ;
1321
1364
return p ;
1322
1365
} else {
1323
1366
return zend_mm_alloc_small_slow (heap , bin_num ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC );
@@ -1340,7 +1383,7 @@ static zend_always_inline void zend_mm_free_small(zend_mm_heap *heap, void *ptr,
1340
1383
#endif
1341
1384
1342
1385
p = (zend_mm_free_slot * )ptr ;
1343
- p -> next_free_slot = heap -> free_slot [bin_num ];
1386
+ zend_mm_set_next_free_slot ( heap , bin_num , p , heap -> free_slot [bin_num ]) ;
1344
1387
heap -> free_slot [bin_num ] = p ;
1345
1388
}
1346
1389
@@ -1904,6 +1947,27 @@ static void zend_mm_free_huge(zend_mm_heap *heap, void *ptr ZEND_FILE_LINE_DC ZE
1904
1947
/* Initialization */
1905
1948
/******************/
1906
1949
1950
+ static zend_result zend_mm_refresh_key (zend_mm_heap * heap )
1951
+ {
1952
+ php_random_result result = php_random_algo_xoshiro256starstar .generate (& heap -> random_state );
1953
+ ZEND_ASSERT (result .size == sizeof (uint64_t ));
1954
+ heap -> key = (uintptr_t ) result .result ;
1955
+ return SUCCESS ;
1956
+ }
1957
+
1958
+ static zend_result zend_mm_init_key (zend_mm_heap * heap )
1959
+ {
1960
+ uint64_t seed [4 ];
1961
+ if (php_random_bytes (& seed , sizeof (seed ), false) != SUCCESS ) {
1962
+ return FAILURE ;
1963
+ }
1964
+
1965
+ php_random_xoshiro256starstar_seed256 (& heap -> random_state ,
1966
+ seed [0 ], seed [1 ], seed [2 ], seed [3 ]);
1967
+
1968
+ return zend_mm_refresh_key (heap );
1969
+ }
1970
+
1907
1971
static zend_mm_heap * zend_mm_init (void )
1908
1972
{
1909
1973
zend_mm_chunk * chunk = (zend_mm_chunk * )zend_mm_chunk_alloc_int (ZEND_MM_CHUNK_SIZE , ZEND_MM_CHUNK_SIZE );
@@ -1940,6 +2004,12 @@ static zend_mm_heap *zend_mm_init(void)
1940
2004
heap -> size = 0 ;
1941
2005
heap -> peak = 0 ;
1942
2006
#endif
2007
+ if (zend_mm_init_key (heap ) != SUCCESS ) {
2008
+ #if ZEND_MM_ERROR
2009
+ fprintf (stderr , "Can't initialize heap\n" );
2010
+ #endif
2011
+ return NULL ;
2012
+ }
1943
2013
#if ZEND_MM_LIMIT
1944
2014
heap -> limit = (size_t )Z_L (-1 ) >> 1 ;
1945
2015
heap -> overflow = 0 ;
@@ -1951,12 +2021,13 @@ static zend_mm_heap *zend_mm_init(void)
1951
2021
heap -> storage = NULL ;
1952
2022
#endif
1953
2023
heap -> huge_list = NULL ;
2024
+ heap -> pid = getpid ();
1954
2025
return heap ;
1955
2026
}
1956
2027
1957
2028
ZEND_API size_t zend_mm_gc (zend_mm_heap * heap )
1958
2029
{
1959
- zend_mm_free_slot * p , * * q ;
2030
+ zend_mm_free_slot * p , * q ;
1960
2031
zend_mm_chunk * chunk ;
1961
2032
size_t page_offset ;
1962
2033
int page_num ;
@@ -1994,15 +2065,15 @@ ZEND_API size_t zend_mm_gc(zend_mm_heap *heap)
1994
2065
has_free_pages = true;
1995
2066
}
1996
2067
chunk -> map [page_num ] = ZEND_MM_SRUN_EX (i , free_counter );
1997
- p = p -> next_free_slot ;
2068
+ p = zend_mm_check_next_free_slot ( heap , i , p ) ;
1998
2069
}
1999
2070
2000
2071
if (!has_free_pages ) {
2001
2072
continue ;
2002
2073
}
2003
2074
2004
- q = & heap -> free_slot [i ];
2005
- p = * q ;
2075
+ q = ( zend_mm_free_slot * ) & heap -> free_slot [i ];
2076
+ p = q -> next_free_slot ;
2006
2077
while (p != NULL ) {
2007
2078
chunk = (zend_mm_chunk * )ZEND_MM_ALIGNED_BASE (p , ZEND_MM_CHUNK_SIZE );
2008
2079
ZEND_MM_CHECK (chunk -> heap == heap , "zend_mm_heap corrupted" );
@@ -2020,11 +2091,19 @@ ZEND_API size_t zend_mm_gc(zend_mm_heap *heap)
2020
2091
ZEND_ASSERT (ZEND_MM_SRUN_BIN_NUM (info ) == i );
2021
2092
if (ZEND_MM_SRUN_FREE_COUNTER (info ) == bin_elements [i ]) {
2022
2093
/* remove from cache */
2023
- p = p -> next_free_slot ;
2024
- * q = p ;
2094
+ if (q == (zend_mm_free_slot * )& heap -> free_slot [i ]) {
2095
+ q -> next_free_slot = zend_mm_check_next_free_slot (heap , i , p );
2096
+ } else {
2097
+ zend_mm_copy_next_free_slot ((zend_mm_free_slot * )q , i , p );
2098
+ }
2099
+ p = zend_mm_check_next_free_slot (heap , i , p );
2025
2100
} else {
2026
- q = & p -> next_free_slot ;
2027
- p = * q ;
2101
+ q = p ;
2102
+ if (q == (zend_mm_free_slot * )& heap -> free_slot [i ]) {
2103
+ p = q -> next_free_slot ;
2104
+ } else {
2105
+ p = zend_mm_check_next_free_slot (heap , i , q );
2106
+ }
2028
2107
}
2029
2108
}
2030
2109
}
@@ -2376,6 +2455,18 @@ void zend_mm_shutdown(zend_mm_heap *heap, bool full, bool silent)
2376
2455
memset (p -> free_map , 0 , sizeof (p -> free_map ) + sizeof (p -> map ));
2377
2456
p -> free_map [0 ] = (1L << ZEND_MM_FIRST_PAGE ) - 1 ;
2378
2457
p -> map [0 ] = ZEND_MM_LRUN (ZEND_MM_FIRST_PAGE );
2458
+
2459
+ pid_t pid = getpid ();
2460
+ if (heap -> pid != pid ) {
2461
+ if (zend_mm_init_key (heap ) != SUCCESS ) {
2462
+ zend_mm_panic ("Can't initialize heap" );
2463
+ }
2464
+ heap -> pid = pid ;
2465
+ } else {
2466
+ if (zend_mm_refresh_key (heap ) != SUCCESS ) {
2467
+ zend_mm_panic ("Can't initialize heap" );
2468
+ }
2469
+ }
2379
2470
}
2380
2471
}
2381
2472
@@ -3052,6 +3143,12 @@ ZEND_API zend_mm_heap *zend_mm_startup_ex(const zend_mm_handlers *handlers, void
3052
3143
heap -> size = 0 ;
3053
3144
heap -> peak = 0 ;
3054
3145
#endif
3146
+ if (zend_mm_init_key (heap ) != SUCCESS ) {
3147
+ #if ZEND_MM_ERROR
3148
+ fprintf (stderr , "Can't initialize heap\n" );
3149
+ #endif
3150
+ return NULL ;
3151
+ }
3055
3152
#if ZEND_MM_LIMIT
3056
3153
heap -> limit = (size_t )Z_L (-1 ) >> 1 ;
3057
3154
heap -> overflow = 0 ;
@@ -3076,6 +3173,7 @@ ZEND_API zend_mm_heap *zend_mm_startup_ex(const zend_mm_handlers *handlers, void
3076
3173
memcpy (storage -> data , data , data_size );
3077
3174
}
3078
3175
heap -> storage = storage ;
3176
+ heap -> pid = getpid ();
3079
3177
return heap ;
3080
3178
#else
3081
3179
return NULL ;
0 commit comments