[GIT-PULLS] [php-src] PR #23376: Bind free list shadow pointers to the slot holding them

[email protected] (jvoisin)
Newsgroups php.git-pulls
Message-ID <[email protected]>
Pull Request: https://github.com/php/php-src/pull/23376
Author: jvoisin

The shadow of a free list pointer is currently BSWAP(next) ^ shadow_key, which does not depend on where it is stored, meaning that:

 - zend_mm_free_small() encodes whatever heap->free_slot[bin] happens to be, including NULL when the bin has been drained, meaning the slot ends up holding shadow_key verbatim.
 - A (next, shadow) pair harvested from one free slot is valid in every other slot of every bin. An attacker who can read one free slot can therefore forge a link anywhere in the heap without needing the key.

This commit adds the address of the slot that holds the shadow into the mix:

    shadow = BSWAP(next) ^ shadow_key ^ (uintptr_t)holder

The holder term cancels on decode, so this is one extra xor on a register that is already live, with no branch. Encoding NULL now yields shadow_key ^ holder rather than the key, and a shadow only verifies in the slot it was written for.

This was verified under GDB: Freeing into a drained bin used to store shadow_key exactly; it now stores shadow_key ^ holder (xoring the two back gives the slot address). Naïvely replaying a valid (next, shadow) pair from one slot into another and traversing from it is accepted before this change and aborts with "zend_mm_heap corrupted" after.

Performance-wise, the impact is in the noise level, which is expected as it more or less adds a single `xor` instruction per `zend_mm_set_next_free_slot()`.

This commit is a follow up on 25360ef2495 and c561f7da858.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.