编辑
2023-12-06
Paper
00
请注意,本文编写于 484 天前,最后修改于 484 天前,其中某些信息可能已经过时。

目录

Profile-Driven System Optimizations for Accelerated Greybox Fuzzing
优化方面
先前的优化方向
为什么选择fork server方向优化
为什么选择OS interaction方向优化
传统fork server优化方法 [Snapshot mode]
传统fork server优化方法 [Persistent mode]
fork server优化方法 [Profile-driven State Recovery]
OS交互层面优化 [Profile-driven OS Abstraction]
影响Fuzzer性能的因素
测试IO影响
profiling phase 分析阶段
如何检测全局变量变动

😀

Profile-Driven System Optimizations for Accelerated Greybox Fuzzing

优化方面

  • fork server -> persistent mode with efficient state recovery
  • OS interaction

先前的优化方向

  • 优化测试用例的调度
  • 优化测试用例的变异
  • 优化测试用例的保留

为什么选择fork server方向优化

  • 传统情况下 AFL和AFL++都运行在fork server模式下 但是分叉子进程需要开销大量时间[复制页表 COW等]

  • 如果单纯使用persistent mode往往由于没有恢复初始状态 先前一次的模糊测试往往会影响到后续模糊测试的状态

  • 现有提出的snapshot mode 经过测试也会抵消persistent mode带来的速度优势

为什么选择OS interaction方向优化

  • 现代操作系统为Fuzz提供了许多不必要的操作 占据了许多的时间开销

传统fork server优化方法 [Snapshot mode]

  • 定制内核 在执行测试用例之前对进程内存进行快照
  • 将所有页面设置成为ReadOnly 并且执行COW
  • 完成测试用例恢复所有存在修改的页面

传统fork server优化方法 [Persistent mode]

  • 不需要恢复内存 不需要恢复状态 不需要定制内核
  • 但是没有清理状态 导致要求使用Persistent mode需要目标的状态可以自动完全重置 并且不会造成资源泄露并且要求早期的执行不会影响后续的执行
  • 在大多数情况下需要人工Patch原本的程序以恢复状态

fork server优化方法 [Profile-driven State Recovery]

  • 采用persistent mode
  • 针对Persistent mode中需要重置的资源: 全局变量、内存资源、内核数据结构、文件描述符等
  • 针对persistent mode中状态恢复的问题 在分析阶段使用测试用例动态分析目标程序 了解操作了哪些全局变量、环境变量
  • 在运行测试用例之前快速重置全局变量和环境变量
  • 可以设置为定期运行重置

OS交互层面优化 [Profile-driven OS Abstraction]

  • 大多数情况下执行用例和OS的交互都是进行文件交互 使用VFS来处理对文件的操作 直接将文件读取到内存中以减少文件操作开销

  • 管理内存中文件的数据和元数据 避免和IO设备进行交互

  • 在用户空间运行所有内容 避免中断和上下文切换

  • 只保留与Fuzz相关的功能 删除如日志等与Fuzz无关的操作

  • 可以使用独立的VFS来为每个模糊测试实例提供服务 避免文件系统争用

  • 可以重置VFS达到快速重置文件描述符的目的

影响Fuzzer性能的因素

  • Fuzzer的性能取决于算法因素和系统因素
  • 算法因素:
    • 测试用例的调度: 优先对哪些测试用例进行变异和变异多长时间
    • 测试用例的变异: 变异算法
    • 测试用例的评价标准: 代码覆盖率、调度上下文、路径覆盖率
  • 系统因素: 系统因素主要影响Fuzzer如何实现Fuzz过程

测试IO影响

  • 使用ext4文件系统和tmpfs文件系统对比IO开销

profiling phase 分析阶段

  • 针对内存资源: 不需要处理 在Presistent mode执行1000次之后执行一次fork 如此自动回收内存资源
  • 针对全局变量: 在分析阶段对测试用例进行动态分析 观察操作了哪些全局变量并记录 在执行测试用例之前重置这些全局变量
    • 随着Fuzz的进行可能会影响新的全局变量: 使用AFL的稳定性指标 观察到稳定性下降就重新执行分析阶段 重新记录影响的全局变量
  • 针对环境变量: 使用setenvunsetenv获取环境变量
  • 针对文件系统: 首先构建一个VFS,检测对应IO文件的属性 如果存在分析阶段没有发现的文件 VFS会将其映射到本地文件系统中
    • 现存文件: 如果在分析阶段 打开或者写入一个现存文件, 对于这样的文件在VFS中创建一个保留文件数据和元数据的副本 其中文件路径在VFS中保持一致
    • 不存在的文件: 如果在分析阶段 打开一个不存在的文件,对于这样的文件在VFS中创建一个空白节点,表示该路径下的文件不存在
    • 新建文件: 忽略新建文件的请求 因为VFS支持新建文件
    • 测试用例: 为测试用例分配共享内存以保存文件 并且方便Fuzzer可以直接访问其进行更新
    • 标准输入/输出: 在VFS中维护一个缓冲器以模拟标准输入
    • Socket: 在VFS中添加一个虚拟文件以充当套接字 其保存在内存中

如何检测全局变量变动

  • 传统做法: 将全局数据段设置为只读 当写入全局变量时会触发异常以捕获对应全局变量
  • 本文做法: 为全局变量添加存储或地址获取操作的检查

具体是如何实现的扫描全部的全局变量?

开发了一个llvm插件 以实现在编译器优化之后扫描全局变量

本文作者:Du4t

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!