Fuzzing Error Handling Code using Context-Sensitive Software Fault Injection
会议:USENIX2020
作者来自清华大学
1 Abstract and Introduction
提出了一个名为 FIFUZZ 的新模糊测试框架,fuzz错误处理代码。核心是上下文敏感的软件故障注入方法。
测试错误处理代码本质上是具有挑战性的,因为错误通常很难确定性地产生。 触发错误处理代码的直观解决方案是使用软件故障注入(SFI)。SFI 故意将故障或错误注入被测程序的代码中,然后执行该程序以测试它是否能够在运行时正确处理注入的故障或错误。
现有的研究几乎都是上下文不敏感的
如上图所示,如果我们只是通过在FuncP中静态地注入一个错误到malloc中来执行上下文不敏感的错误注入,那么程序将总是在执行FuncA时退出,而不会发现任何错误。如果我们考虑调用上下文,并仅在FuncB调用FuncP时才将错误注入到FuncP中的malloc中,则可以在运行时触发对象y的双重free错误
2 Background
-
两类错误
-
输入错误:无效的输入,如错误的数据或是异常的命令
下图是输入错误处理代码,避免除零
-
-
偶发错误:偶然发生的异常事件引起的,例如内存不足或网络连接失败。
下图是一个偶发错误的处理代码,函数 av_frame_new_side_data 用于为新数据分配内存,当内存不足时会失败并返回空指针。 在这种情况下,变量 dst->side_data[i]->metadata 在 dst->side_data[i] 被释放后被释放,这会导致释放后使用错误。
-
输入错误可以由输入触发,但是偶发错误不能通过控制输入触发,而是与执行环境和系统资源 (如内存和网络连接) 的状态有关。用于处理错误的代码称为错误处理代码,如JAVA的try catch
-
error site : 将故障注入可能发生错误并触发错误处理代码的站点,我们将每个这样的站点称为 error site
-
对常用的软件做了调查统计,42%的site和偶发错误有关,又对现有的模糊测试工具发现的CVE做了统计调查,发现有31%的CVE是关于错误处理的,而只有9%于偶发错误有关。显然,这个比例与42%并不相符。于是,作者猜想现有的模糊测试工具可能遗漏了由偶然错误触发的错误处理代码中的许多实际错误。
3 Basic Idea and Approach
3.1 Basic Idea
error sequence:一系列 error point 组成的序列,本质上是0,1序列,不注入故障的点为0,注入故障的点为1
error point:可能触发错误处理程序的错误执行点
3.2 Error Sequence Model
现有的基于 SFI 的方法通常使用上下文不敏感的故障注入。 具体来说,他们只使用源代码中每个 error site 的位置来描述一个错误点。上下文敏感则使用 error site 的位置和上下文来描述错误点。
上下文敏感,具体来讲,就是考虑函数调用栈。
值得一提的是,一个 error site 在 n 个不同的上下文中执行时,每一个 error site 都是一个错误点(error point),即有n个错误点。
3.3 Context-Sensitive SFI-based Fuzzing
- 静态识别被测程序源代码中的 error site;
- 运行被测程序,收集每个执行的 error site 的调用上下文和代码覆盖率的运行时信息;
- 根据运行时信息创建关于已执行 error site 的 error sequences ;
- 运行程序后,对每个创建的 error sequences 进行变异,生成新的序列;
- 运行被测程序,根据变异后的 error sequences ,在特定的调用上下文中将错误注入到 error site ;
- 收集运行时信息,创建新的 error sequences 并再次对这些 error sequences 进行变异,从而构建一个模糊循环。 当没有新的 error sequences 产生或达到时间限制时,模糊循环结束。
4 FIFUZZ Framework
FIFUZZ主要包含两个阶段
4.1 Compile-Time Analysis 编译时分析
该阶段有两个主要任务
1)Error-site extraction
文章侧重于提取特定的函数调用作为 error site ,因为大多 error site 都与检查函数调用的错误指示返回值有关。分为三步:
- 识别候选 error site 。如果函数返回一个指针或整数,或者返回值被if语句检查是否为 0 或 NULL
- 选择库函数。被测程序的函数可能调用了库函数,如果在被测程序的函数库和调用的库函数中都注入了错误,则会重复。为了避免这种情况,从第一步识别出来的函数调用中,作者只选择了那些被调用函数为库函数的函数。
- 进行统计分析。首先将所有的函数调用按照调用的函数进行分类。然后,对于给定函数的函数调用,计算它的返回值被 if 语句检查所占的比例,如果高于阈值R,则将该函数标记为 error function
2)Code instrumentation 代码插桩
- 为了收集有关每个 error site 的运行时调用上下文的信息,在每个函数调用之前和之后以及每个函数的入口和出口处进行代码插桩
- 为了监控错误站点的执行并对其进行故障注入,在每个 error site 之前进行插桩
4.2 Runtime Fuzzing
将错误序列注入到程序中,执行程序时收集有关已执行的错误点、代码分支等的运行时信息。根据收集到的运行时信息,错误序列生成器创建错误序列并执行突变以生成新的错误序列,此外还有重组。
5 Evaluation
5.2 Error-Site Extraction
需要注意的是,作者设计的自动选择工具并不是完全智能的。首先,自动选择出一部分可能触发错误处理函数的函数调用9795个以及error function 287个,再手动从其中选择出能作为真实的 error site 的函数调用1822个以及 error function 150个。识别 error site 和 error function 的概率分别为18.6%和52.3% 。阈值R选择0.6.
发现了46个bug,但是只与18个 error site 有关,大多数是偶发错误。
6 Discussion
误报原因:
- 存在返回指针或是整形的函数从来不会触发错误,如strcmp和strstr
- 上下文将可能触发错误的数据已经处理成有效数据了
漏报原因:
- 只处理了库函数,没有考虑程序中定义的函数
- 一些 error site 只有在提供特定的程序输入和配置时才会执行,而FIFUZZ 无法提供所有可能的程序输入和配置。
- 只检测了造成crash的bug,只用了ASAN工具,还可以使用MASN等
提高性能:
- 丢弃无用的 error sequence
- 轻量级的运行时监控
- 多线程