使用 Nix 对 PDF 解析器进行模糊测试(第二部分)

这是关于使用 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 buildnix 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 的好方法,帮助澄清了一些模糊的概念。

源代码

阅读 19
0 条评论