Randomize the layout of zend_mm small freelists - #23361
Conversation
|
Part of #14083 |
zend_mm_alloc_small_slow() carved a fresh bin into a freelist ordered by ascending address and returned the first element, so the address of every small allocation was entirely determined by the allocation sequence: the n-th allocation of a given size class always landed at bin + n*slot_size, and two consecutive allocations were always adjacent. That determinism is what makes heap feng-shui reliable. An attacker who can drive a few allocations of the right size class knows exactly where the next one lands, and can therefore place a victim object immediately after a buffer he can overflow, or reclaim a specific freed slot with an object of a chosen type. Shuffle the slot order when a bin is created: hand out the first slot of the shuffled sequence and link the remaining ones in that order. This is the ~equivalent of Linux' SLAB_FREELIST_RANDOM. Performance-wise, it: - Adds two scratch arrays of ZEND_MM_MAX_BIN_ELEMENTS entries (4KiB total) live on the stack of a non-recursive slow path. - Adds a per-bin-creation shuffleing, on the slow path. - Reduces spatial locality of allocations, but Zend/bench.php shows no measurable difference. Can be compiled out with -DZEND_MM_FREELIST_RANDOM=0.
|
Looks good to me. |
|
@ndossche Could you take a look at this? |
|
I could, but won't. The foundation is paid to look into PRs, I'm not paid at all. |
|
@arnaud-lb Could you take a look at this PR? |
|
I'm hesitating on this one, for multiple reasons: Overhead is not negligible: +0.7% on symfony and phpstan benchmarks. It can make bugs more difficult to reproduce. We can disable it by default in debug builds, but this will affect bug reports anyway. This can be bypassed in may cases. An attack that relies on overflowing to an adjacent bin can be performed by making every bin a valid victim so that their order doesn't matter. For larger bin sizes with only a few bins per page, an attack can be brute-forced. |
|
Fair. I'll try to re-send something in this spirit if quanrantine is ever implemented |
zend_mm_alloc_small_slow() carved a fresh bin into a freelist ordered by ascending address and returned the first element, so the address of every small allocation was entirely determined by the allocation sequence: the n-th allocation of a given size class always landed at bin + n*slot_size, and two consecutive allocations were always adjacent.
That determinism is what makes heap feng-shui reliable. An attacker who can drive a few allocations of the right size class knows exactly where the next one lands, and can therefore place a victim object immediately after a buffer he can overflow, or reclaim a specific freed slot with an object of a chosen type.
Shuffle the slot order when a bin is created: hand out the first slot of the shuffled sequence and link the remaining ones in that order. This is the ~equivalent of Linux' SLAB_FREELIST_RANDOM.
Performance-wise, it:
Can be compiled out with -DZEND_MM_FREELIST_RANDOM=0.