模糊测试是一种通过向程序提供海量半随机输入来发现软件缺陷的强大方法。虽然 AFL++ 是 Linux 上针对 C 和 C++ 目标的领先平台,但要实现高效测试,需要对 sanitizers 和环境变量进行刻意配置。同时使用 Address Sanitizer (ASan) 和 Undefined Behavior Sanitizer (UBSan) 是基本要求,但默认的 ASan 设置可能不足。例如,将 `max_malloc_fill_size` 增加到较大的值(如 1GB)可以确保未初始化的内存被填充为特定模式,防止模糊测试器错过程序读取超出 4KiB 默认缓冲区的未初始化数据时产生的缺陷。此外,启用 `detect_stack_use_after_return` 可以捕捉更复杂的内存错误,即使它可能会略微降低模糊测试速度。
架构选择显著影响模糊测试活动的速度和深度。最有效的优化之一是使用 AFL++ 的持久模式(persistent mode),由于它避免了重复重启目标进程带来的开销,其速度可能比原地模糊测试快一个数量级。为了实现这一点,开发人员可以使用自定义测试模板,将目标逻辑封装在循环中。此设置中的一个关键技术细节是避免将原始 AFL++ 缓冲区直接传递到目标程序中的常见错误。由于 AFL++ 缓冲区大于输入长度,ASan 可能无法检测到读取溢出。相反,测试模板应创建一个大小匹配的输入副本,确保程序的边界受到严格强制并可被 sanitizer 检测。
除了配置之外,“hacksaw”技术可以简化复杂、紧密耦合组件的测试。与其为每个测试管理复杂的构建系统,开发人员可以将目标的源文件直接包含在模糊测试模板中的单个翻译单元(TU)中。这允许模糊测试器直接访问静态函数和变量,从而能够测试那些未通过公共 API 暴露的内部接口。此外,对于需要文件系统路径的程序,使用内存文件描述符(通过 `memfd_create`)允许模糊测试器通过 `/proc/self/fd/` 路径提供数据。这种方法通过确保每个进程都有唯一的路径来支持并行模糊测试,同时还能防止对物理存储造成不必要的磨损。为了最大化整体性能,还建议保持测试用例较小并使用更简单的目标二进制文件,以确保模糊测试器花费更多时间探索新的执行路径,而不是解析大型、非必要的元数据。
