House Of Botcache是用于绕过tcache double free检查的一种方法,在glibc2.29-2.31,对于tcache加入了key值来检测该tcache是否已经存在于tcache bins中,该方法就是借用unsorted bin来绕过double free的检查,下面跟着源码来分析一下。
typedefstructtcache_entry { structtcache_entry *next; /* This field exists to detect double frees. */ structtcache_perthread_struct *key;// 引入key值 } tcache_entry;
tcache double free的检查
2917行
tcache_put
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/* Caller must ensure that we know tc_idx is valid and there's room for more chunks. */ static __always_inline void tcache_put(mchunkptr chunk, size_t tc_idx) { tcache_entry *e = (tcache_entry *) chunk2mem (chunk);
/* Mark this chunk as "in the tcache" so the test in _int_free will detect a double free. */ e->key = tcache; // 设置该tcache
/* 如果该chunk非空,tcache bins没填充满,那么该chunk可能已经在tcache bins中了,所以要对其进行double free的检查,即检查key值 */ if (tcache != NULL && tc_idx < mp_.tcache_bins) { /* Check to see if it's already in the tcache. */ tcache_entry *e = (tcache_entry *) chunk2mem (p);
/* This test succeeds on double free. However, we don't 100% trust it (it also matches random payload data at a 1 in 2^<size_t> chance), so verify it's not an unlikely coincidence before aborting. */ /* 如果是double free,那么put时key字段被设置了tcache,就会进入循环被检查出来 如果不是,那么key字段就是用户数据区域,可以视为随机的,只有1/(2^size_t)的可能行进入循环,然后循环发现并不是double free */ if (__glibc_unlikely (e->key == tcache)) { tcache_entry *tmp; LIBC_PROBE (memory_tcache_double_free, 2, e, tc_idx); for (tmp = tcache->entries[tc_idx]; tmp; tmp = tmp->next) if (tmp == e) malloc_printerr ("free(): double free detected in tcache 2"); /* If we get here, it was a coincidence. We've wasted a few cycles, but don't abort. */ }
defadd(size,content): choice(1) p.sendlineafter("The size of this note : ",str(size)) p.sendlineafter("The content of this note : ",content)
defedit(idx,size,content): choice(2) p.sendlineafter("The index of this note : ",str(idx)) p.sendlineafter("The size of this content : ",str(size)) p.sendlineafter("The content of this note : ",content)
defshow(idx): choice(3) p.sendlineafter("The index of this note : ",str(idx))
deffree(idx): choice(4) p.sendlineafter("The index of this note : ",str(idx))