BUDAlloc 中文解读
《BUDAlloc:通过解耦内核与虚拟地址管理来防御“释放后使用”漏洞》
这篇论文介绍了一种名为 BUDAlloc 的新型内存分配器,旨在高效地检测和防御“释放后使用”(Use-After-Free, UAF)这一严重的安全漏洞。
它的核心思想是 “用户态和内核态协同设计”,将虚拟地址的管理权从内核解耦到用户态分配器,同时利用 eBPF 技术定制内核的缺页中断处理程序。这种设计使得 BUDAlloc 能够在不修改应用程序二进制文件的情况下,实现了性能、内存开销和漏洞检测能力之间的出色平衡。
1. 背景:UAF漏洞与现有防御技术的挑战
什么是UAF漏洞?
当程序释放了一块内存后,如果仍然保留着指向这块内存的“悬空指针”,并在之后通过这个指针再次访问这块已被释放的内存时,就会发生UAF漏洞。攻击者可以利用这一点来读取敏感信息或执行恶意代码。
什么是一次性分配器(OTA)?
OTA的基本原理是:分配过的虚拟地址永远不会被重新用于新的分配请求。这样,即使程序中存在悬空指针,它也无法再访问到任何有效的、被重新分配的数据,从而使UAF攻击失效。
现有OTA方案的困境(“语义鸿沟”问题)
为了避免巨大的内存浪费,现代OTA普遍采用“虚拟地址别名”(Virtual Aliasing)技术,即多个内存对象共享同一个物理内存页,但每个对象都有自己独立的、一次性的“别名”虚拟地址。
这带来了一个核心挑战,论文称之为 “语义鸿沟” (Semantic Gap):用户态的分配器知道哪个“别名地址”对应哪个“真实地址”,但内核对此一无所知。如何跨越这道鸿沟,是所有OTA设计的关键,并直接影响其表现:
- FFmalloc方案(无别名映射):此方案放弃了别名技术。虽然性能接近原生分配器,但导致了极高的内存开销(在某些应用中高达800%),且漏洞检测能力很弱。
- Syscall-based方案(如Oscar):每次分配和释放都通过系统调用(如 mremap, munmap)来通知内核地址映射关系。这种方式会带来巨大的性能开销和内核锁竞争,可扩展性差。
- LibOS-based方案(如DangZero):在一个轻量级操作系统(LibOS)和虚拟机中运行程序,直接在用户态修改页表。这种方法检测精度高,但引入了虚拟化本身的开销(如I/O性能下降),且严重破坏了系统兼容性,例如它不支持 fork() 系统调用的“写时复制”机制。
2. BUDAlloc 的核心设计与原理
BUDAlloc通过一种全新的“用户态-内核协同设计”方法,巧妙地解决了上述问题。
设计核心:分离与协同
- 管理权分离:BUDAlloc 将地址管理一分为二。用户态分配器 负责管理 虚拟地址的布局(制定策略),而 内核 则保留对 物理地址的管理 和最终的页表映射权(执行机制)。
- eBPF作为桥梁:BUDAlloc 使用 eBPF (extended Berkeley Packet Filter) 技术,向内核中安全地注入一个 自定义的缺页中断处理程序。
- 共享元数据:用户态分配器和内核的eBPF处理程序之间共享一个Trie树结构的元数据,其中记录了“别名地址”到“规范地址”的映射关系。
工作流程
- 分配内存 (malloc):
- 程序请求内存。
- BUDAlloc的用户态部分首先从内部维护的分配器获取一个“规范地址”。
- 然后,它在自己的虚拟地址空间中划出一个新的、从未用过的“别名地址”。此步骤无需任何系统调用。
- 它将“别名地址 → 规范地址”的映射关系存入共享的Trie树中。
- 最后,将这个“别名地址”返回给应用程序。
- 首次访问与缺页处理:
- 当应用程序首次访问这个别名地址时,CPU会产生一个“缺页中断”。
- BUDAlloc的eBPF自定义处理程序被触发,查询共享的Trie树,找到该别名地址对应的规范地址。
- 最后,它请求内核将这个别名地址映射到其规范地址所对应的物理页上,完成映射。
- 释放内存 (free):
BUDAlloc提供了两种模式,以平衡性能和检测精度:- 检测模式 (BUDAlloc-d):当应用释放一个别名地址时,BUDAlloc会立即发起系统调用,解除该地址的页表映射。这能立即、精确地检测到任何后续对该地址的访问。
- 防护模式 (BUDAlloc-p):为了追求更高性能,此模式会延迟解除映射的操作。它将被释放的别名地址放入一个缓冲区,等到下一次发生缺页中断时,再批量地将缓冲区中的地址一次性解除映射。
3. BUDAlloc 的主要优势
- 高性能与高可扩展性:由于分配操作无需系统调用,且释放操作可以批量处理,BUDAlloc显著降低了性能开销和内核锁竞争,在多线程环境中表现出极佳的可扩展性。
- 完全的兼容性:与DangZero不同,BUDAlloc没有绕过内核的核心机制。因此,它完全兼容标准的Linux功能,如 fork 的写时复制、按需分页 以及 /proc 文件系统 等,能够直接运行未经修改的二进制程序。
- 较低的内存开销:通过虚拟别名技术,BUDAlloc的内存开销远低于FFmalloc,与DangZero和标准分配器GLIBC处于相似水平。
- 灵活而强大的安全性:提供了“检测”和“防护”两种模式。实验表明,即使是性能更高的防护模式,也足以检测到绝大多数现实世界中的UAF漏洞。
4. 实验评估结果
- 安全性:在一系列已知的UAF漏洞(CVE)测试中,BUDAlloc成功防御了所有攻击。其防护模式检测出了30个案例中的29个,而FFmalloc虽然能阻止攻击,但几乎检测不到这些漏洞。
- 性能和内存:
- 在SPEC CPU测试中,BUDAlloc的性能开销显著低于DangZero,内存开销远低于FFmalloc。
- 在多线程的PARSEC测试中,当线程数增加时(>8个),BUDAlloc的可扩展性优势凸显,其性能甚至超越了FFmalloc。
- 在Apache和Nginx服务器测试中,BUDAlloc的表现与原生GLIBC分配器非常接近,而FFmalloc和MarkUs(一种基于垃圾回收的方案)则分别出现了严重的内存膨胀或性能下降问题。
结论
BUDAlloc通过创新的“用户态-内核协同设计”,并巧妙利用eBPF技术,成功地打造了一个实用、高效、兼容且安全的UAF防御方案。它在性能、内存使用、可扩展性和漏洞检测能力之间取得了前所未有的平衡,为解决长期存在的UAF问题提供了一个极具前景的实践方向。
Defeating Use-After-Free Bugs.pdf
https://github.com/casys-kaist/BUDAlloc/tree/main