LibFuzzer是LLVM项目中的一个进程内、覆盖率引导的进化式模糊测试库,用于测试其他库的健壮性与安全性。它没有独立的执行程序,而是与被测代码链接在同一个进程里,通过一个由用户编写的模糊测试入口函数反复接收字节输入,并依据代码覆盖率信息不断变异输入,使测试逐渐深入到更多代码路径。因为省去了每个测试用例启动新进程的开销,它的执行速度通常远高于传统的进程外模糊测试工具。
定义
LibFuzzer是一个用于对其他库进行进程内、覆盖率引导、进化式模糊测试的库。它的代码位于LLVM源码仓库中,随Clang编译器一同分发,因此使用时不需要额外安装。它本身并不提供独立的命令行模糊测试程序,而是把模糊测试所需的入口函数、输入变异逻辑和语料库管理代码与待测代码一起链接进同一个可执行文件[1]。
与之功能相近的概念是美国模糊测试工具American Fuzzy Lop,两者的输入语料库组织方式相互兼容,但AFL默认以进程外方式运行,而LibFuzzer的所有模糊测试动作都在单一进程内完成。
原理
使用LibFuzzer的第一步是编写一个模糊测试目标函数,其固定签名为LLVMFuzzerTestOneInput,接收一个字节数组和长度,并把这些字节送入待测代码。该函数返回0表示接受输入,返回-1表示拒绝,除此之外的返回值目前保留[1]。模糊测试目标不依赖LibFuzzer本身,因此同一份目标函数也可以交给其他模糊测试引擎运行[1]。
代码覆盖率信息由LLVM提供的SanitizerCoverage插桩功能获得。编译时启用-fsanitize=fuzzer后,Clang会向目标代码插入覆盖率探针,并在链接阶段接入LibFuzzer库[1]。模糊测试过程可以概括为一个反复执行的循环。
flowchart LR
A[语料库语料] --> B[变异引擎]
B --> C[模糊测试目标函数]
C --> D[被测代码]
D --> E[SanitizerCoverage 覆盖率探针]
E --> F{是否触发新覆盖}
F -- 是 --> A
F -- 否 --> B
在得到新覆盖的输入会被写入语料库目录,作为后续变异的基础;未带来新覆盖的输入通常被丢弃[1]。为提升对结构化输入的处理能力,LibFuzzer支持用户提供的字典,把输入语言的关键字或幻数等字节序列加入变异素材,语法与AFL的字典格式类似[2]。此外,配合编译器标志-fsanitize-coverage=trace-cmp与运行时选项-use_value_profile=1,模糊测试器可以收集比较指令参数的值特征,并把部分新出现的值当作新的覆盖处理[2]。
每个LibFuzzer进程都是单线程的,但可以让多个进程共享同一个语料库目录并行工作:默认情况下各进程会定期重新读取该目录,从而获取其他进程新发现的输入[1]。
发展历程
LibFuzzer的代码长期存放在LLVM源码仓库中,早期以lib/Fuzzer为路径,需要在已有Clang的环境下单独编译成静态库,再与模糊测试目标链接[3]。2015年3月31日,该项目的文档文件LibFuzzer.rst由Kostya Serebryany提交扩充,补充了介绍、示例与常见问题等内容[3]。
从Clang 6.0起,LibFuzzer被包含在Clang发行版中,不再需要额外安装,只要在编译和链接时使用-fsanitize=fuzzer标志即可生成可用的模糊测试程序[1]。Windows平台的支持在LLVM的r341082版本中加入,Clang 9及之后的构建可以使用,但不支持在没有AddressSanitizer的Windows环境下使用[1]。
LibFuzzer需要与Clang版本相匹配[1]。它的原始作者后来把主要精力转向另一个模糊测试引擎Centipede,LibFuzzer转为完全支持但仅修复重要缺陷的维护状态,不再预期有除缺陷修复之外的新功能[1]。
应用
LibFuzzer适合测试输入规模较小、单次输入执行时间在毫秒级、且在非法输入下不会主动终止进程的库,典型的适用对象包括正则表达式匹配器、文本或二进制格式解析器、压缩库、网络协议和加密库[1]。在谷歌的OSS-Fuzz持续模糊测试服务中,LibFuzzer与AFL一同作为模糊测试引擎运行,并配合AddressSanitizer、MemorySanitizer、UndefinedBehaviorSanitizer等工具检测缺陷[4]。
LibFuzzer在多个实际项目中发现了缺陷,官方文档列出的例子包括musl libc、PCRE、OpenSSL与BoringSSL、libxml2、Capstone、Radare2、WOFF2、TensorFlow以及FFmpeg等[1]。文档同时给出了一套用LibFuzzer复现Heartbleed漏洞的操作步骤[2]。在Chrome浏览器的组件测试中,谷歌安全团队也使用LibFuzzer对单个函数或内部接口直接进行模糊测试,而不必启动整个浏览器[5]。
局限
进程内运行的方式带来若干限制。如果被测库会校验输入、并在遇到无效输入时断言失败或崩溃,那么进程内模糊测试就不适用[1]。被测代码中未被当场检测到的缺陷可能累积,例如内存损坏在最初没有报错,却在处理另一个输入时引发崩溃,因此通常需要开启各类sanitizer以便即时发现大多数错误[1]。
进程内模糊测试器也更难防范被测库过度的内存占用和死循环;被测库还不应存在运行之间未复位的显著全局状态。许多有价值的库在设计上并不支持字节数组式的进程内接口,例如它们要求传入文件路径[1]。
如果单次测试运行耗时较长,进程内方式的吞吐量优势就会变得不明显;若被测库运行了生命周期超过单次测试的持久线程,模糊测试结果将不可靠[1]。此外,LibFuzzer目前不支持调用dlclose的目标[1]。
在功能特性上,启用值特征收集可能带来最多约2倍的额外减速,语料库规模也可能增长数倍[2]。Windows平台上的使用仍有限制,不支持用动态运行时库选项构建模糊测试程序[1]。
参见
-
模糊测试 —— LibFuzzer所实现的测试技术类别,通过自动生成输入来发现程序缺陷。
-
American Fuzzy Lop —— 与LibFuzzer思路相近的覆盖率引导模糊测试工具,默认采用进程外方式运行。
-
LLVM —— LibFuzzer所在的编译器项目,为其提供SanitizerCoverage插桩支持。
-
Clang —— 随发行版一同提供LibFuzzer的C/C++编译器,通过编译标志启用。
-
AddressSanitizer —— 常与LibFuzzer配合使用的内存错误检测工具。
参考资料
- libFuzzer – 用于覆盖率引导的模糊测试的库。¶ [引用日期2026-10-14]
- libFuzzer – a library for coverage-guided fuzz testing.¶ [引用日期2026-10-14]
- [llvm] r233763 - [fuzzer] more documentation [引用日期2026-10-14]
- Coverage-guided fuzzing [引用日期2026-10-14]
- Google Online Security Blog: 8月 2016 [引用日期2026-10-14]