什么是TCACHE?Linux下基于ptmalloc的堆利用双free失效问题咨询
关于ptmalloc中双free无报错与TCACHE的解析
Hey there,作为长期搞Linux二进制漏洞利用的同行,我太懂你这种旧payload突然失效的困惑了!你遇到的这个双free不触发报错的情况,核心原因就是TCACHE(Thread Cache)——ptmalloc在glibc 2.26之后引入的新特性,彻底改变了堆内存分配的行为,尤其是对小尺寸chunk的管理。
为什么你的双free没触发报错?
在glibc 2.26之前,对于非fastbin的chunk(比如你用的0xc0大小,属于small bin),直接双free确实会触发double free or corruption这类报错,因为ptmalloc会严格检查chunk的空闲状态。但TCACHE出现后,规则变了:
- 当你第一次
free(chunk1)时,这个chunk会被放进当前线程的TCACHE对应大小的链表中; - 第二次
free(chunk1)时,早期版本的TCACHE甚至没有重复free的检查逻辑——它会直接把同一个chunk再次加入TCACHE链表,不会在free阶段立刻抛出错误; - 只有当后续你调用malloc取出这些重复的chunk并进行操作时,才会触发崩溃、数据篡改等异常,而不是在free的瞬间报错。
什么是TCACHE?
TCACHE全称为Thread Local Cache,是glibc为优化多线程环境下的内存分配性能而引入的机制:
- 线程私有:每个线程都有独立的TCACHE结构,访问时不需要加锁,彻底避免了多线程操作堆时的锁竞争开销;
- 专注小尺寸chunk:TCACHE只管理较小尺寸的chunk(默认覆盖16B到1024B区间,具体可通过编译选项调整),更大的chunk仍会回到fastbin、small bin、large bin这些传统堆结构;
- 链表缓存结构:每种尺寸的chunk对应一条链表,TCACHE会限制每条链表的最大长度(默认是7个),当链表满了之后,多余的空闲chunk才会被转存到fastbin或bins中;
- 分配优先级最高:调用malloc时,ptmalloc会优先从TCACHE中取出对应尺寸的chunk,只有TCACHE无可用chunk时,才会去fastbin、bins中查找。
验证TCACHE行为的简单示例
你可以试试这段代码,直观感受TCACHE的影响:
#include <stdio.h> #include <string.h> #include <malloc.h> int main() { char *chunk1 = malloc(0xc0); printf("chunk1 addr: %p\n", chunk1); free(chunk1); printf("第一次free后,chunk进入TCACHE\n"); free(chunk1); printf("第二次free,无即时报错(chunk被重复加入TCACHE)\n"); // 两次malloc会取出同一个chunk char *ptr1 = malloc(0xc0); char *ptr2 = malloc(0xc0); printf("ptr1: %p, ptr2: %p\n", ptr1, ptr2); // 两个指针指向同一地址 // 修改ptr1会同时篡改ptr2的内容,这就是双free的风险点 strcpy(ptr1, "Hello TCACHE!"); printf("ptr2的内容:%s\n", ptr2); return 0; }
编译运行后你会发现,两次malloc得到的是完全相同的地址,这说明TCACHE确实接收了重复free的chunk,且没有在free阶段触发报错。
补充:TCACHE的安全检查演进
后续的glibc版本(比如2.32之后)给TCACHE加了部分安全检查,比如free时会检测chunk是否已存在于当前线程的TCACHE中,若存在则触发报错。但这些检查并非100%覆盖所有场景,且部分环境下可能会被禁用。你遇到的情况,大概率是使用了glibc 2.26到2.31之间的版本,或者相关检查被关闭了。
内容的提问来源于stack exchange,提问作者poming
相关产品推荐
相关产品推荐

