tcache attack
glibc用tcache_entry和tcache_perthread两个结构体来管理tcache bin
1、tcache_entry
比较新的版本的tcache_entry如下(glibc-2.33)
tcache_perthread_struct如下
-
Tcache perthread struct在 每- - 个线程中均有一个,用来管理当前线程中所有的tcache_ bins
-
Entries用来存储各个大小的tcache bin链表,TCAHE_ MAX_ _BINS默认值为64,也就是0x20, 0x30....0x4 10(64位)大小的chunk被释放后都有可能放入tcache bins里面
-
counts结构体用来记录各个大小的tcache bin数量,最大为7
Tcache attack|分配机制
我们malloc时,会将size转化为对 应大小的tcache idx,然后判断这个idx是否有tcache bin,如果有,会将tcache 取出,然后将他的next链表指向的值赋值给tcache->entries[tc_ idx] (使其指向下一-个tcache bin或null),再递减当前大小tcache counts(数量)
_libc_malloc
的函数
__libc_malloc (size_t bytes)
{
mstate ar_ptr;
void *victim;
_Static_assert (PTRDIFF_MAX <= SIZE_MAX / 2,
"PTRDIFF_MAX is not more than half of SIZE_MAX");
void *(*hook) (size_t, const void *)
= atomic_forced_read (__malloc_hook);
if (__builtin_expect (hook != NULL, 0))
return (*hook)(bytes, RETURN_ADDRESS (0));
其中有一个判读语句
if (tc_idx < mp_.tcache_bins
&& tcache
&& tcache->counts[tc_idx] > 0)
{
victim = tcache_get (tc_idx);
return TAG_NEW_USABLE (victim);
}
tcache_get
中的代码如下
tcache_get (size_t tc_idx)
{
tcache_entry *e = tcache->entries[tc_idx];
if (__glibc_unlikely (!aligned_OK (e)))
malloc_printerr ("malloc(): unaligned tcache chunk detected");
tcache->entries[tc_idx] = REVEAL_PTR (e->next);
--(tcache->counts[tc_idx]);
e->key = NULL;
return (void *) e;
}
_libc_free
函数如下
void
__libc_free (void *mem)
{
mstate ar_ptr;
mchunkptr p; /* chunk corresponding to mem */
void (*hook) (void *, const void *)
= atomic_forced_read (__free_hook);
if (__builtin_expect (hook != NULL, 0))
{
(*hook)(mem, RETURN_ADDRESS (0));
return;
}
if (mem == 0) /* free(0) has no effect */
return;
其中调用了_int_free
,其中有部分的代码如下
在上述代码的最后一个if语句中,成立后调用tcache_put
,其代码如下
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;
e->next = PROTECT_PTR (&e->next, tcache->entries[tc_idx]);
tcache->entries[tc_idx] = e;
++(tcache->counts[tc_idx]);
}
我们free时,首先会检测当前chunk大小是否属于tcache bin,再检测key值,防止double free,最后再看当前大小tcache数量,如果小于7(默认),就会调用tcache_ puts将 这块chunk放入对应大小的tcahce,放入时,首先会设置好key值,然后再将next指针指向原当前大小的tcache链表,再结合malloc的代码,我们可以知道tcache bin也是- -个先进后出的结构
Tcache attack|利用原理