形象的概括

如果说sysmallloc是向系统要钱,那么这段代码就是负责还钱以及把钱存进不同的钱包。

1.libc free

如果free hook被设置,free不会执行正常逻辑
直接调用hook
经典利用
覆盖free hook=system
然后free(“bin/sh”)

2.null处理

标准行为:free(null)无效果

3.mmap chunk处理

大块内存直接mumap
不进入bin管理

4.普通chunk

进入核心函数int free

int free核心逻辑

可以分成六个阶段

① 基础安全检查

if (misaligned_chunk || size非法)
error

检查内容:

  • 指针是否合法

  • size >= MINSIZE

  • 对齐正确

👉 防止:

  • fake chunk

  • 野指针

② fastbin 路径(小chunk)

条件:

size <= get_max_fast()


fastbin 的关键特点:

✔ 单链表

p->fd = old;

✔ LIFO(后进先出)


⚠️ 关键安全检查

1. double free

if (old == p)
error

👉 fastbin double free 检测(但不完全)

2. lock-free 插入

catomic_compare_and_exchange_val_rel

👉 无锁 CAS 操作


⚠️ 利用点(经典)

  • fastbin dup

  • fastbin attack

  • 覆盖 fd 指针

③ 非 fastbin 路径(normal bin)

进入:

if (!chunk_is_mmapped(p))


先加锁

mutex_lock(&av->mutex)

④ 合并(核心机制🔥)


向前合并(backward consolidation)

if (!prev_inuse(p))

👉 前一个 chunk 是 free:

p = prev_chunk
size += prevsize
unlink(prev)

向后合并(forward consolidation)

if (!nextinuse)

👉 后一个 chunk 是 free:

unlink(next)
size += nextsize

⑤ 插入 unsorted bin

bck = unsorted_chunks(av);
p->fd = fwd;
p->bk = bck;
👉 所有合并后的 chunk:

➡️ 先进入 unsorted bin
➡️ 再在 malloc 时分流

⚠️ 关键检查

if (fwd->bk != bck)
corrupted unsorted chunks

👉 防止链表破坏

⚠️ 利用点(非常重要🔥)

unsorted bin attack:

利用:

p->bk = target

写任意地址:

*(target + offset) = value

⑥ top chunk 合并

if (nextchunk == av->top)

👉 当前 chunk 与 top 相邻:

av->top = p;

⑦ 大块触发整理

if (size >= FASTBIN_CONSOLIDATION_THRESHOLD)

默认:64KB


做两件事:

1. fastbin 合并

malloc_consolidate(av);


2. 尝试归还系统内存

systrim()

四、systrim:归还内存给 OS


条件

top chunk 足够大

核心逻辑:

1. 计算可释放大小

extra = ALIGN_DOWN(…)

必须是页大小整数倍


2. 调用:

sbrk(-extra)

👉 真正把内存还给 OS

3. 更新:

av->system_mem -= released
top chunk size 减少

🔷 free 做了什么?

1️⃣ 分类处理

  • fastbin

  • normal bin

  • mmap


2️⃣ chunk 合并(防碎片)

  • backward

  • forward


3️⃣ bin 管理

  • fastbin(单链表)

  • unsorted bin(双链表入口)


4️⃣ 内存回收

  • top chunk

  • systrim → sbrk

从漏洞利用点看

⚠️ 1. fastbin attack

控制:

p->fd

实现:

  • 任意地址分配

⚠️ 2. double free

绕过:

if (old == p)

构造:

  • fastbin dup

利用:

unlink(av, p)

写:

bk->fd = fd
fd->bk = bk

⚠️ 4. unsorted bin attack

控制:

bk

实现:

  • 任意写

⚠️ 5. __free_hook 劫持(最经典)

__free_hook → system

触发:

free(“/bin/sh”)

七、一句话总结

👉 free() 本质是:

把 chunk 放回合适的 bin,并尽可能合并,再在必要时把内存还给操作系统

但在实现过程中:

⚠️ 大量“指针操作 + 链表操作 + 不完全检查”
→ 成为堆利用(heap exploitation)的核心入口