Repository navigation
Heap hardening #14083
Copy link
Copy link
Open
Description
Description
Currently, PHP's heap implementation is ~trivial to exploit:
- BlackAlps 2022: Generic Remote Exploit Techniques For The PHP Allocator, And 0days by Charles Fol
- SSD Advisory – PHP SplDoublyLinkedList UAF Sandbox Escape
- Gollum: Modular and Greybox Exploit Generation for Heap Overflows in Interpreters
- In the land of PHP you will always be (use-after-)free and Solution to Adepts of 0xCC Challenge 01
- mm0r1's exploits
There are several hardening techniques that could/should be implemented, listed here in order of difficulty:
- prevent unlink abuses:
- prevent freelist-corruption via shadow-pointer à la XNU/linux/partitionAlloc/suhosin/…: Detect heap freelist corruption #14054
Disable ZEND_MM_CUSTOM by default: Make some parts of _zend_mm_heap read-only at runtime #14570- Make some parts of _zend_mm_heap read-only at runtime: Make some parts of _zend_mm_heap read-only at runtime #14570
- surround large allocations with guard-pages, as done in partitionAlloc, scudo, …
- Freelist randomisation, see Linux'
SLAB_FREELIST_RANDOM - isolate types in different heaps to make type confusion/use after free more difficult, as in kalloc_type. An additional benefit of type isolation + freelist bitmap is that we wouldn't need the object_store anymore to enumerate objects. A less invasive approach would be to simply isolate by size as done in partitionAlloc and Webkit's libpas
- once this is done, heaps need to be pinned by size/type, to prevent an attacker from re-using the memory space of a destructed heap with one of different type/size.
- a low-hanging fruit would be to allocate GET/POST/COOKIES into a separated heap, to reduce the reach of heap feng-shui: Remote heap feng shui / heap spraying protection #14304
allocate strings and array buckets in GigaCages so that a corrupt length doesn't allow to access anything else than other strings/array buckets. This will significantly increase the virtual-memory usage though.this isn't doable since those structures have a maximum size ofSIZE_MAX
Reactions are currently unavailable
Activity
arnaud-lb commentedon Apr 30, 2024
Thank you for creating this issue! I though a bit more about this since #13943 (comment):
Longer term, we should check if replacing refcounting+cycle GC by a full tracing GC is practicable, because it would help. Although refcounting can not be entirely removed because CoW semantics rely on it.
jvoisin commentedon Apr 30, 2024
SIZE_MAXwon't fix in a GigaCage, sigh.arnaud-lb commentedon Apr 30, 2024
Great, thank you!
Agreed with changing the base entirely. What I had in mind was to use a random mmap hint in zend alloc, and allocate contiguously from that hint (to avoid splitting the address space too much). After that we can randomize bin placement inside chunks (but I feel this can be easily defeated with heap feng shui) and freelists inside bins indeed.
Regarding the threat model, I'm focusing more on the remote attacker model for now, as I feel this is the most critical.
jvoisin commentedon Apr 30, 2024
Oh, I see. Yes, having a randomized per-child base would help a bit, as an attacker wouldn't be able to use forks to bruteforce the randomization, albeit memory allocated before the fork would still be at the same offset across processes. As for periodic rebasing, I guess having the master process re-executing itself once in a while would be an acceptable
hacktradeoff.Remote PHP exploitation is pretty exotic, to my knowledge, to my knowledge, the only person to do it (publicly) is @cfreal. Local exploitation is much more common, usually to bypass
open_basediranddisable_functions.devnexen commentedon Apr 30, 2024
...
@jvoisin, just curious ; would you recommend using the userfaultfd api in that case ?
jvoisin commentedon Apr 30, 2024
I'd rather keep things simple and portable: map two pages
PROT_NONEand let the process violently crash in case of violation. I'm under the impression thatuserfaultfdadds a lot of complexity, which is never a good thing for security-related features.devnexen commentedon Apr 30, 2024
Oh not so much complexity it allows to handle the violation more smoothly than the usual technique you re referring to. But ... that s just linux :)