@@ -197,6 +197,44 @@ typedef zend_mm_bitset zend_mm_page_map[ZEND_MM_PAGE_MAP_LEN]; /* 64B */
197
197
198
198
#define ZEND_MM_BINS 30
199
199
200
+ #if defined(_MSC_VER )
201
+ # if UINTPTR_MAX == UINT64_MAX
202
+ # define BSWAPPTR (u ) _byteswap_uint64(u)
203
+ # else
204
+ # define BSWAPPTR (u ) _byteswap_ulong(u)
205
+ # endif
206
+ #else
207
+ # if UINTPTR_MAX == UINT64_MAX
208
+ # if __has_builtin (__builtin_bswap64 )
209
+ # define BSWAPPTR (u ) __builtin_bswap64(u)
210
+ # else
211
+ zend_always_inline uintptr_t BSWAPPTR (uintptr_t u )
212
+ {
213
+ return (((u & 0xff00000000000000ULL ) >> 56 )
214
+ | ((u & 0x00ff000000000000ULL ) >> 40 )
215
+ | ((u & 0x0000ff0000000000ULL ) >> 24 )
216
+ | ((u & 0x000000ff00000000ULL ) >> 8 )
217
+ | ((u & 0x00000000ff000000ULL ) << 8 )
218
+ | ((u & 0x0000000000ff0000ULL ) << 24 )
219
+ | ((u & 0x000000000000ff00ULL ) << 40 )
220
+ | ((u & 0x00000000000000ffULL ) << 56 ));
221
+ }
222
+ # endif /* __has_builtin(__builtin_bswap64) */
223
+ # else /* UINTPTR_MAX == UINT64_MAX */
224
+ # if __has_builtin (__builtin_bswap32 )
225
+ # define BSWAPPTR (u ) __builtin_bswap32(u)
226
+ # else
227
+ zend_always_inline uintptr_t BSWAPPTR (uintptr_t u )
228
+ {
229
+ return (((u & 0xff000000 ) >> 24 )
230
+ | ((u & 0x00ff0000 ) >> 8 )
231
+ | ((u & 0x0000ff00 ) << 8 )
232
+ | ((u & 0x000000ff ) << 24 ));
233
+ }
234
+ # endif /* __has_builtin(__builtin_bswap32) */
235
+ # endif /* UINTPTR_MAX == UINT64_MAX */
236
+ #endif /* defined(_MSC_VER) */
237
+
200
238
typedef struct _zend_mm_page zend_mm_page ;
201
239
typedef struct _zend_mm_bin zend_mm_bin ;
202
240
typedef struct _zend_mm_free_slot zend_mm_free_slot ;
@@ -248,7 +286,7 @@ struct _zend_mm_heap {
248
286
size_t size ; /* current memory usage */
249
287
size_t peak ; /* peak memory usage */
250
288
#endif
251
- uintptr_t key ; /* free slot shadow ptr key */
289
+ uintptr_t shadow_key ; /* free slot shadow ptr xor key */
252
290
zend_mm_free_slot * free_slot [ZEND_MM_BINS ]; /* free lists for small sizes */
253
291
#if ZEND_MM_STAT || ZEND_MM_LIMIT
254
292
size_t real_size ; /* current size of allocated pages */
@@ -349,14 +387,6 @@ static const uint32_t bin_pages[] = {
349
387
ZEND_MM_BINS_INFO (_BIN_DATA_PAGES_C , x , y )
350
388
};
351
389
352
- #define _BIN_SHADOW_OFFSET (num , size , elements , pages , x , y ) \
353
- (_BIN_DATA_SIZE(num, size, elements, pages, x, y) - sizeof(zend_mm_free_slot*))
354
- #define _BIN_SHADOW_OFFSET_C (num , size , elements , pages , x , y ) \
355
- _BIN_SHADOW_OFFSET(num, size, elements, pages, x, y),
356
- static const uint32_t bin_shadow_offset [] = {
357
- ZEND_MM_BINS_INFO (_BIN_SHADOW_OFFSET_C , x , y )
358
- };
359
-
360
390
#if ZEND_DEBUG
361
391
ZEND_COLD void zend_debug_alloc_output (char * format , ...)
362
392
{
@@ -1272,40 +1302,58 @@ static zend_always_inline int zend_mm_small_size_to_bin(size_t size)
1272
1302
1273
1303
#define ZEND_MM_SMALL_SIZE_TO_BIN (size ) zend_mm_small_size_to_bin(size)
1274
1304
1305
+ /* We keep track of free slots by organizing them in a linked list, with the
1306
+ * first word of every free slot being a pointer to the next one.
1307
+ *
1308
+ * In order to frustrate corruptions, we check the consistency of these pointers
1309
+ * before dereference by comparing them with a shadow.
1310
+ *
1311
+ * The shadow is a copy of the pointer, stored at the end of the slot. It is
1312
+ * XOR'ed with a random key, and converted to big-endian so that smaller
1313
+ * corruptions affect the most significant bytes, which has a high chance of
1314
+ * resulting in an invalid address instead of pointing to an adjacent slot.
1315
+ */
1316
+
1317
+ #define ZEND_MM_FREE_SLOT_PTR_SHADOW (free_slot , bin_num ) \
1318
+ *((zend_mm_free_slot**)((char*)(free_slot) + bin_data_size[(bin_num)] - sizeof(zend_mm_free_slot*)))
1319
+
1275
1320
static zend_always_inline zend_mm_free_slot * zend_mm_encode_free_slot (zend_mm_heap * heap , zend_mm_free_slot * slot )
1276
1321
{
1277
- return (zend_mm_free_slot * )((uintptr_t )slot ^ heap -> key );
1322
+ #if WORDS_BIGENDIAN
1323
+ return (zend_mm_free_slot * )(((uintptr_t )slot ) ^ heap -> shadow_key );
1324
+ #else
1325
+ return (zend_mm_free_slot * )(BSWAPPTR ((uintptr_t )slot ) ^ heap -> shadow_key );
1326
+ #endif
1278
1327
}
1279
1328
1280
1329
static zend_always_inline zend_mm_free_slot * zend_mm_decode_free_slot (zend_mm_heap * heap , zend_mm_free_slot * slot )
1281
1330
{
1282
- return (zend_mm_free_slot * )((uintptr_t )slot ^ heap -> key );
1331
+ #if WORDS_BIGENDIAN
1332
+ return (zend_mm_free_slot * )((uintptr_t )slot ^ heap -> shadow_key ));
1333
+ #else
1334
+ return (zend_mm_free_slot * )(BSWAPPTR ((uintptr_t )slot ^ heap -> shadow_key ));
1335
+ #endif
1283
1336
}
1284
1337
1285
1338
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 )
1286
1339
{
1287
1340
slot -> next_free_slot = next ;
1288
- * ( zend_mm_free_slot * * )(( char * ) slot + bin_shadow_offset [ bin_num ] ) = zend_mm_encode_free_slot (heap , next );
1341
+ ZEND_MM_FREE_SLOT_PTR_SHADOW ( slot , bin_num ) = zend_mm_encode_free_slot (heap , next );
1289
1342
}
1290
1343
1291
1344
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 )
1292
1345
{
1293
1346
dest -> next_free_slot = from -> next_free_slot ;
1294
- * (zend_mm_free_slot * * )((char * )dest + bin_shadow_offset [bin_num ]) = * (zend_mm_free_slot * * )((char * )from + bin_shadow_offset [bin_num ]);
1295
- }
1296
-
1297
- static ZEND_COLD ZEND_NORETURN void zend_mm_free_slot_corrupted (void )
1298
- {
1299
- zend_mm_panic ("zend_mm_heap corrupted" );
1347
+ ZEND_MM_FREE_SLOT_PTR_SHADOW (dest , bin_num ) = ZEND_MM_FREE_SLOT_PTR_SHADOW (from , bin_num );
1300
1348
}
1301
1349
1302
1350
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 )
1303
1351
{
1304
1352
zend_mm_free_slot * next = slot -> next_free_slot ;
1305
- zend_mm_free_slot * shadow = * ( zend_mm_free_slot * * )(( char * ) slot + bin_shadow_offset [ bin_num ] );
1353
+ zend_mm_free_slot * shadow = ZEND_MM_FREE_SLOT_PTR_SHADOW ( slot , bin_num );
1306
1354
if (EXPECTED (next != NULL )) {
1307
1355
if (UNEXPECTED (next != zend_mm_decode_free_slot (heap , shadow ))) {
1308
- zend_mm_free_slot_corrupted ( );
1356
+ zend_mm_panic ( "zend_mm_heap corrupted" );
1309
1357
}
1310
1358
}
1311
1359
return (zend_mm_free_slot * )next ;
@@ -1971,15 +2019,17 @@ static zend_result zend_mm_refresh_key(zend_mm_heap *heap)
1971
2019
{
1972
2020
php_random_result result = php_random_algo_xoshiro256starstar .generate (& heap -> random_state );
1973
2021
ZEND_ASSERT (result .size == sizeof (uint64_t ));
1974
- heap -> key = (uintptr_t ) result .result ;
2022
+ heap -> shadow_key = (uintptr_t ) result .result ;
1975
2023
return SUCCESS ;
1976
2024
}
1977
2025
1978
2026
static zend_result zend_mm_init_key (zend_mm_heap * heap )
1979
2027
{
1980
2028
uint64_t seed [4 ];
1981
- if (php_random_bytes (& seed , sizeof (seed ), false) != SUCCESS ) {
1982
- return FAILURE ;
2029
+ if (php_random_bytes_silent (& seed , sizeof (seed )) != SUCCESS ) {
2030
+ for (int i = 0 ; i < sizeof (seed )/sizeof (seed [0 ]); i ++ ) {
2031
+ seed [i ] = php_random_generate_fallback_seed ();
2032
+ }
1983
2033
}
1984
2034
1985
2035
php_random_xoshiro256starstar_seed256 (& heap -> random_state ,
0 commit comments