MEDS:增强型内存错误检测Sanitizer

MEDS:增强型内存错误检测Sanitizer

Enhancing Memory Error Detection for Large-Scale Applications and Fuzz Testing

Remarks

Abstract

Memory errors are one of the most common vulnerabilities for the popularity of memory unsafe languages including C and C++. Once exploited, it can easily lead to system crash (i.e., denial-of-service attacks) or allow adversaries to fully compromise the victim system. This paper proposes MEDS, a practical memory error detector. MEDS significantly enhances its detection capability by approximating two ideal properties, called an infinite gap and an infinite heap. The approximated infinite gap of MEDS setups large inaccessible memory region between objects (i.e., 4 MB), and the approximated infinite heap allows MEDS to fully utilize virtual address space (i.e., 45-bits memory space). The key idea of MEDS in achieving these properties is a novel user-space memory allocation mechanism, MEDSALLOC. MEDSALLOC leverages a page aliasing mechanism, which allows MEDS to maximize the virtual memory space utilization but minimize the physical memory uses. To highlight the detection capability and practical impacts of MEDS, we evaluated and then compared to Google’s state-of-the-art detection tool, AddressSanitizer. MEDS showed three times better detection rates on four real-world vulnerabilities in Chrome and Firefox. More importantly, when used for a fuzz testing, MEDS was able to identify 68.3% more memory errors than AddressSanitizer for the same amount of a testing time, highlighting its practical aspects in the software testing area. In terms of performance overhead, MEDS slowed down 108% and 86% compared to native execution and AddressSanitizer, respectively, on real-world applications including Chrome, Firefox, Apache, Nginx, and OpenSSL.

Introduction


Abut ASAN:

Address Sanitizer是Google基于LLVM开发的一种内存错误检测机制,在用 Clang 或者 GCC 编译目标应用的代码,在其中插桩。其主要实现了对内存对象(堆、栈、全局)的监控,将这些对象所在的内存区域映射到shadow memory上,通过shadow memory记录内存对象和其周围(及雷区)的是否可以访问。在对象释放以后,还会对释放的内存区域进行隔离,直到隔离区满以后以FIFO的方式再次分配这块内存给程序。

Linux的内存管理机制:

blog.csdn.net/qq_384107


AddressSanitizer还存在的问题:

  1. False Negative

(1)当指针的访问区域超过了redzone,对Buffer-Overflow会漏报。(下图最左图)

(2)当,对Use-after-free可能会有漏报。(下图最右图)


2. Performance Overhead

AddressSanitizer工具编译的程序的堆栈和栈占用比原生程序的大。


Methodology


本文的方法是基于Google的AddressSanitizer(ASan)进行改进的,利用虚拟页机制扩大雷区(red zone)和隔离区(quarantined zone),进而实现更好捕捉内存错误(Memory Error)。文章中提出了两个ASan存在的问题:一是雷区只有16B~2KB,一般的指针越界访问可以轻易越过这一雷区访问到其他合法的内存对象;二是限制区默认只有256M,并且采用FIFO的管理机制,UAF攻击者可以等待很短的时间就可以对指向已经释放的区域的指针访问内存再次分配后合法的内存对象。为了缓解这两个问题,作者利用页机制对Address Sanitizer进行了改进。利用接管虚拟内存分配让内存对象之间的间隔尽可能大(infinite gap),限制区循环利用的时间尽可能大(infinite heap)。

主要实现思路为,将雷区(实验中为4MB)分为页内和页两级,页内级分配物理shadow memory进行监控,与ASan相同;页级直接不分配内存也不设置物理shadow memory,利用没有map的页访问会产生page fault来探测内存访问错误。实现这个思路需要两个部分,一部分是MEDSALLOC,用于接管内存空间分配;另一部分是内存访问错误探测,用于显式检测shadow memory是否合法,隐式接收page fault,判断是否访问了页级red zone。

为了节省内存,文章中还提出利用页别名技术将占用内存页不同位置的虚拟内存对象映射到同一个物理页上。

这样就实现了每个内存对象都会有一个较大的雷区来探测内存访问错误,即文中所称的“infinite gap”。

而“infinite heap”的实现就是通过MEDSALLOC充分利用64位系统的内存空间,将每个内存对象分配的地址单调变化,是的被回收的虚拟地址在尽量长的时间后才能被重新分配,这样就缓解了Use-After-Free漏洞利用的条件。


论文中主要实现的技术包括MEDSALLOC内存分配机制和页内存访问错误捕捉机制。主要基于LLVM编译器项目,项目整体是一个LLVM extra pass,通过对目标项目的C/C++代码进行编译插桩,并生成可执行文件,运行时动态库主要还是基于LLVM的sanitizer规则来做的。MEDSALLOC基本上会把所有的内存分配和回收函数hook,用来完成程序内存对象以及影子内存的分配和监控操作。代码量10,812行。MEDS会与ASLR发送冲突,所以需要关闭ASLR。



Evaluation


实验测试了三个方面的表现,包括MEDS的兼容性、探测能力和性能。实验结果表明:

  1. MEDS能够兼容所有测试的大型软件,包括Chrome、Firefox、Nginx等大规模软件的所有测试例都能顺利运行。
  2. 对于NIST Juliet Test Suite,MEDS能够比ASan探测更多的内存访问错误(98% - 35%)。
  3. 重用虚拟内存地址的周期比较长,能够充分利用linux支持的80T内存空间。但对nginx的实验表明,在对堆栈全局三种内存对象都进行监控的情况下,0.5分钟就能用完所有内存地址,不得不分配原有虚存地址。
  4. 在配合AFL进行模糊测试时,MEDS能够更快的找到独特的崩溃类型,但并没有表现出能够找出更多漏洞。
  5. MEDS会导致比ASan更多的程序运行速度下降,主要原因是会引起更多的TLB缺失和调用更多的syscall。

编辑于 04-15

文章被以下专栏收录