libFuzzer测试stbi harness时生成的崩溃样本无法复现问题
问题描述
我打算对stbi harness这个现有fuzzing测试用例进行fuzz测试,仅做了一处小修改:将原代码中的free(img)改为if(img) free(img)。
我使用如下命令编译:clang -fsanitize=fuzzer,address -ggdb -O0 stbi_read_fuzzer.c -o fuzzer
随后使用如下命令启动fuzz:./fuzzer corpus -fork=1 -ignore_crashes=1 -dict=jpeg.dict -seed=123
运行数小时后工具报告生成了若干崩溃,类型包括全局缓冲区溢出、堆释放后使用、缓冲区溢出。但我单独运行生成的崩溃样本时却没有触发崩溃,执行日志如下:
aldo@vps:~/stb/tests$ ./fuzzer crash-edab9036233c269e258fe93c2a46d46d5d6e7112 INFO: Running with entropic power schedule (0xFF, 100). INFO: Seed: 2279336272 INFO: Loaded 1 modules (2132 inline 8-bit counters): 2132 [0x61b510, 0x61bd64), INFO: Loaded 1 PC tables (2132 PCs): 2132 [0x5d0258,0x5d8798), ./fuzzer: Running 1 inputs 1 time(s) each. Running: crash-edab9036233c269e258fe93c2a46d46d5d6e7112 Executed crash-edab9036233c269e258fe93c2a46d46d5d6e7112 in 3 ms *** *** NOTE: fuzzing was not performed, you have only *** executed the target code on a fixed set of inputs. ***
我的运行环境是Ubuntu 20.04,使用从apt.llvm.org安装的LLVM 12,请问为什么无法复现崩溃?
回答
核心原因
- 运行参数与环境不一致:你启动fuzz时使用了
-fork=1参数,libFuzzer的fork模式会自动启用更严格的ASAN检测规则,同时会配置特殊的ASAN环境变量,你单独运行样本时没有携带这些配置,就不会触发对应检测的崩溃。另外你fuzz时指定了-seed=123,但单独运行时的随机种子是自动生成的2279336272,不同种子会导致内存分配布局差异,刚好避开了崩溃触发条件。 -ignore_crashes=1参数的副作用:这个参数会让libFuzzer把ASAN报告的警告级别的内存问题也判定为崩溃并保存样本,这类问题在默认运行配置下不会触发程序终止,只会输出日志甚至不产生任何提示。- 内存问题的随机性:你遇到的全局缓冲区溢出、释放后使用这类内存问题本身就和运行时的内存布局强相关,单独运行一次时,溢出的内存可能刚好是未使用的无效区域、释放后的内存块还没被重新分配占用,就不会触发崩溃。
- 多轮累积触发的问题:部分崩溃是在fuzz多轮运行后内存状态累积异常才触发的,你单独运行样本时只会执行一次目标逻辑,不会触发这类累积导致的崩溃。
复现建议
- 运行样本时添加和fuzz阶段完全一致的参数和环境变量,示例命令:
ASAN_OPTIONS=$ASAN_OPTIONS ./fuzzer -seed=123 crash-edab9036233c269e258fe93c2a46d46d5d6e7112
- 增加样本运行次数,添加
-runs=1000参数让样本重复执行多轮,提高触发概率 - 确认复现用的二进制和fuzz阶段使用的是同一个,没有重新编译修改过代码或编译参数
内容的提问来源于stack exchange,提问作者Aldo
相关产品推荐
相关产品推荐

