TCache Stashing Unlink
Review Notes on TCache Stashing Unlink
TCache Stashing Unlink
Introduction
- Exploits a UAF or an overflow into the victim’s
bkpointer. - Allows arbitrary fake chunk allocation.
Code Review
Smallbins
- The smallbin is a circular doubly-linked list.
- These chunks can be coalesced to form larger chunks.
- If a request satisfies smallbin size range then the smallbins are checked.
- For large requests, largebins are only checked once unsorted chunks are sorted.
- The bin index for the size is obtained and the
binis intialised to the linked-list at that index.1 2 3 4
if (in_smallbin_range (nb)) { idx = smallbin_index (nb); bin = bin_at (av, idx);
- A check takes place for whether the last chunk in the bin is the same as the first chunk in the bin.
- If not,
bckis initialised to the chunk before the last chunk in the bin.1 2 3
if ((victim = last (bin)) != bin) { bck = victim->bk;
- A check for whether
bck’s forward pointer correctly points to thevictimchunk takes place to mitigate any memory corruption. - If not, the
victimchunk is unlinked from the list after theinusebit is set. bin->bkis set to the 2nd last chunk in the bin.bck->fdis set to the beginning of the linked-list completing the circular link.1 2 3 4 5 6 7 8
if ((victim = last (bin)) != bin) { bck = victim->bk; if (__glibc_unlikely (bck->fd != victim)) malloc_printerr ("malloc(): smallbin double linked list corrupted"); set_inuse_bit_at_offset (victim, nb); bin->bk = bck; bck->fd = bin;
- A check takes place for whether the
malloc_statestruct pointer is equal to themain_arena. If not, then theNMAbit is set . check_malloced_chunkis a function that checks for chunk sanity in debug builds.1 2 3
if (av != &main_arena) set_non_main_arena (victim); check_malloced_chunk (av, victim, nb);
TCache
- If chunks of the same size as the requested size range are found, they are exhaustively stashed in the tcache until it’s full for quick retrieval.
tc_idxis set to the tcache index for the chunk size that has been requested.1
size_t tc_idx = csize2tidx (nb);
- A check for whether the tcache has been initialised and if
tc_idxis less that the no. of total tcache bins. tc_victimis initialised, this is the chunk that will be taken out of the tcache.- A loop is initialised which continues as long as the following conditions are satisfied:
- The bin count for the
tc_idxis less than the maxtcache_count. - The current
tc_victimis not the last chunk in the smallbin.1 2 3 4 5 6
if (tcache != NULL && tc_idx < mp_.tcache_bins) { mchunkptr tc_victim; while (tcache->counts[tc_idx] < mp_.tcache_count && (tc_victim = last (bin)) != bin)
- The bin count for the
- Another check for whether the
tc_victimis null. - If not,
bckis set to thetc_victim’s previous chunk. prev_inuseis set for thetc_victim.nmabit is set if required.tc_victimis unlinked from the smallbin.tc_victimis added to the tcache bin fortc_idxand thetcache->counts[tc_idx]is incremented.1 2 3 4 5 6 7 8 9 10 11 12 13 14
{ if (tc_victim != 0) { bck = tc_victim->bk; set_inuse_bit_at_offset (tc_victim, nb); if (av != &main_arena) set_non_main_arena (tc_victim); bin->bk = bck; bck->fd = bin; tcache_put (tc_victim, tc_idx); } }- If the request was not satisfied by the smallbins then the largebin index for the size is obtained and the fastbins are consolidated before proceeding.
1 2 3 4 5
{ idx = largebin_index (nb); if (atomic_load_relaxed (&av->have_fastchunks)) malloc_consolidate (av); }
Exploitation
- Fill up the tcache bins for a certain size (
0x90recommended) by allocating upto 9 chunks and freeing 7 of them such that the 2nd and 4th chunk are still free. - Free the 2nd and 4th chunk to put them into the unsorted bin, allocate a chunk larger than both of them to sort them into the smallbin.
- Malloc 2 chunks to remove 2 spaces from the tcachebin.
- Overwrite the
victim-bkusing the vulnerability to your target address/chain. - Allocate a chunk from of the smallbin size and your fake chunk should get stashed into tcache.
This post is licensed under CC BY 4.0 by the author.