这是关于使用 Nix 自动化模糊测试工作流程的帖子的后半部分。
下载棘手的 PDF
- 手动从 IRS 网站下载 PDF 用于临时模糊测试,现开始自动化此步骤。
- 目标是获取各种不同的 PDF 以测试 PDF 文件格式的不同部分。
- Mozilla 的 pdf.js 项目中有 700 个导致其工具解析错误的 PDF,将其下载到 Nix flake 中。
- 新的构建步骤可获取初始的边缘情况 PDF 语料库,用于测试 PDF 解析代码的不常见路径。
下载更多棘手的 PDF
- pdf.js 仓库中除了 PDF 文件还有几百个包含外部 PDF URL 的
.link文件。 - 无法直接从
.link文件 URL 下载 PDF,因mkDerivation步骤阻止互联网访问。 - Anton Mosich 提供了一种优雅的方法,通过指定
outputHash等参数让 Nix 在构建期间允许互联网访问。 - 使用
aria2c工具并行下载.link文件中的 PDF,使下载过程更快。 - 运行更新后的
sample-pdfs步骤后,./result目录中的文件数量增加到 1137 个。
自动化模糊运行
- 在系列的第 1 部分中展示了如何在 Nix dev shell 中手动运行 honggfuzz,现通过在 Nix flake 中定义启动命令使该过程更简单。
- 添加新的 shell 脚本用于启动 honggfuzz,包含复制源语料库、设置环境变量等操作。
- 构建 shell 脚本后,可通过
nix build或nix run启动模糊测试。 - 声明
fuzz-xpdf为默认应用,可使用更简单的命令nix run启动模糊测试。
用 ASAN 将微妙的内存错误转换为明显的崩溃
- 为使模糊测试更高效,添加 Address Sanitizer (ASAN) 工具,它能在程序尝试读取或写入超出变量内存位置时立即导致程序崩溃。
- 在 xpdf 的编译步骤中添加
-fsanitize=address以启用 ASAN。 - 运行
nix run启动模糊测试,honggfuzz 运行两小时后发现第一个崩溃。
找到第一个崩溃
- honggfuzz 保存导致崩溃的 PDF 文件,可通过特定命令重现崩溃。
- 程序崩溃时 ASAN 报告捕获到缓冲区溢出错误。
- 调试时发现调试符号输出仅为二进制偏移,难以调试,通过调整 Nix 配置和使用
llvm-symbolizer工具获取带有文件名和行号的丰富堆栈跟踪。 - 但仍存在路径问题,通过在编译时使用
clang的-fdebug-prefix-map标志修复了/build/source前缀问题。
理解崩溃
- 分析堆栈跟踪和源代码,确定崩溃是由于
GfxFont::readFontDescriptor函数中对空字符串的处理不当导致的越界内存读取。 - 函数在处理字体名称时未检查字符串长度,导致读取了分配给字符串的内存之外的字节。
修复 bug
- 在
readFontDescriptor函数中添加条件检查,确保在处理字符串之前字符串长度大于 0。 - 创建补丁文件并应用到 Nix flake 中,重新编译 xpdf 并运行测试,发现程序不再崩溃,修复成功。
总结
- 发现 Nix 是创建模糊测试工作流程的优秀工具,易于组合和替换不同组件。
- 此项目是学习模糊测试和 Nix 的好方法,帮助澄清了一些模糊的概念。
源代码
- 完整的模糊测试工作流程源代码可在 Gitlab 上获取:https://gitlab.com/mtlynch/fuzz-xpdf
- xpdf 的摘录使用 GPLv3 许可证,感谢 Anton Mosich 的协助。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用。你还可以使用@来通知其他用户。