其他
对 Ruby 库/gem 或 Ruby C…
在 Linux 上用 Ruzzy 对纯 Ruby 代码或 Ruby C 扩展进行覆盖率引导 fuzzing,并集成 ASan/UBSan 检测内存错误与未定义行为。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 35/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 38/100 ×0.15
适用场景
对 Ruby 库/gem 或 Ruby 特定
解决思路
- 设置环境变量:`export ASAN_OPTIONS="allocator_may_return_null=1:detect_leaks=0:use_sigaltstack=0"`。
- 用内置 toy example 验证:`LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') ruby -e 'require "ruzzy"; Ruzzy.dummy'`,应快速发现 crash,证明 Ruzzy 正常工作。
- 平台选择:Ruzzy 支持 Linux x86-64 和 AArch64/ARM64;macOS 或 Windows 使用 Dockerfile 或 development environment。
- 确认前置条件:Linux x86-64 或 AArch64/ARM64;较新 clang(至少 14.0.0,推荐最新);Ruby 已安装 gem。
- 用 clang 编译标志安装 Ruzzy:`MAKE="make --environment-overrides V=1" CC="/path/to/clang" CXX="/path/to/clang++" LDSHARED="/path/to/clang -shared" LDSHAREDXX="/path/to/clang++ -shared" gem install ruzzy`。
- 理解安装环境变量:`MAKE` 覆盖 make 以尊重后续环境变量;`CC`、`CXX`、`LDSHARED`、`LDSHAREDXX` 确保使用正确的 clang 二进制以支持最新特性。
- 安装失败时开启调试:`RUZZY_DEBUG=1 gem install --verbose ruzzy`。
- 安装后通过运行 toy example 验证安装。
- 纯 Ruby fuzzing 需要两个脚本:tracer 脚本和 harness 脚本。
- 写 tracer 脚本 `test_tracer.rb`:`require 'ruzzy'`,然后 `Ruzzy.trace('test_harness.rb')`。
- 写纯 Ruby harness 脚本 `test_harness.rb`:`require 'ruzzy'`;定义 `fuzzing_target(input)`;在 `test_one_input = lambda do |data| ... return 0 end` 中调用目标;最后 `Ruzzy.fuzz(test_one_input)`。
- 运行纯 Ruby harness:`LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') ruby test_tracer.rb`。
- Ruby C 扩展 fuzzing 只需单个 harness 文件,不需要 tracer。
- 写 C 扩展 harness 示例 `fuzz_msgpack.rb`:`require 'msgpack'`;`require 'ruzzy'`;`test_one_input = lambda do |data| begin MessagePack.unpack(data) rescue Exception end return 0 end`;`Ruzzy.fuzz(test_one_input)`。
- 运行 C 扩展 harness:`LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') ruby fuzz_msgpack.rb`。
- Harness 规则:测试 C 扩展时捕获 Ruby 异常;从 `test_one_input` lambda 返回 0;保持 harness 确定性;纯 Ruby 代码使用 tracer 脚本。
- Harness 禁止:让 Ruby 异常使 fuzzer 崩溃;返回其他值;使用随机性或基于时间的逻辑;纯 Ruby 跳过 tracer。
- 安装带 sanitizer 的 Ruby gem(含 C 扩展)时用:`MAKE="make --environment-overrides V=1" CC="/path/to/clang" CXX="/path/to/clang++" LDSHARED="/path/to/clang -shared" LDSHAREDXX="/path/to/clang++ -shared" CFLAGS="-fsanitize=address,fuzzer-no-link -fno-omit-frame-pointer -fno-common -fPIC -g" CXXFLAGS="-fsanitize=address,fuzzer-no-link -fno-omit-frame-pointer -fno-common -fPIC -g" gem install <gem-name>`。
- 构建标志用途:`-fsanitize=address,fuzzer-no-link` 启用 AddressSanitizer 和 fuzzer instrumentation;`-fno-omit-frame-pointer` 改善栈回溯质量;`-fno-common` 提高 sanitizer 兼容性;`-fPIC` 为共享库生成位置无关代码;`-g` 包含调试符号。
- 运行任何 fuzzing campaign 前设置 `ASAN_OPTIONS`:`export ASAN_OPTIONS="allocator_may_return_null=1:detect_leaks=0:use_sigaltstack=0"`。
- 理解 `ASAN_OPTIONS`:`allocator_may_return_null=1` 跳过常见低影响分配失败(DoS);`detect_leaks=0` 忽略 Ruby 解释器数据泄漏;`use_sigaltstack=0` 因 Ruby 建议在 ASan 下禁用 sigaltstack。
- 基本运行:`LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') ruby harness.rb`。
- 注意 `LD_PRELOAD` 用于 sanitizer 注入;不要 export,否则可能干扰其他程序,应内联到 ruby 命令。
- 带 corpus 运行:`LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') ruby harness.rb /path/to/corpus`。
- 传递 libFuzzer 选项:`LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') ruby harness.rb /path/to/corpus -max_len=1024 -timeout=10`。
- 复现 crash:`LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') ruby harness.rb ./crash-253420c1158bc6382093d409ce2e9cff5806e980`。
- 解读输出:`INFO: Running with entropic power schedule` 表示 campaign 启动;`ERROR: AddressSanitizer: heap-use-after-free` 表示检测到内存破坏;`SUMMARY: libFuzzer: fuzz target exited` 表示发生 Ruby 异常;`artifact_prefix='./'; Test unit written to ./crash-*` 表示 crash 输入已保存;`Base64: ...` 是 crash 输入的 Base64 编码。
- 使用 AddressSanitizer(ASan):`LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') ruby harness.rb`。
- ASan 用于检测:堆缓冲区溢出、栈缓冲区溢出、use-after-free、double-free、内存泄漏(Ruzzy 默认禁用)。
- 使用 UndefinedBehaviorSanitizer(UBSan):`LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::UBSAN_PATH') ruby harness.rb`。
- UBSan 用于检测:有符号整数溢出、空指针解引用、未对齐内存访问、除以零。
- 常见 sanitizer 问题处理:Ruby 解释器泄漏警告用 `ASAN_OPTIONS=detect_leaks=0`;sigaltstack 冲突用 `ASAN_OPTIONS=use_sigaltstack=0`;分配失败刷屏用 `ASAN_OPTIONS=allocator_may_return_null=1`;`LD_PRELOAD` 干扰工具时不要 export,改为内联到 ruby 命令。
- 真实示例 msgpack-ruby:用 sanitizer 安装 msgpack,命令同安装带 sanitizer 的 Ruby gem,但结尾为 `gem install msgpack`。
- 写 `fuzz_msgpack.rb`:同 C 扩展 harness 示例。
- 运行 msgpack fuzzing:先 `export ASAN_OPTIONS="allocator_may_return_null=1:detect_leaks=0:use_sigaltstack=0"`,再 `LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') ruby fuzz_msgpack.rb`。
- 真实示例纯 Ruby target:写 tracer `test_tracer.rb`,同纯 Ruby tracer 写法。
- 写 `test_harness.rb`:`require 'ruzzy'`;`require_relative 'my_parser'`;`test_one_input = lambda do |data| begin MyParser.parse(data) rescue StandardError end return 0 end`;`Ruzzy.fuzz(test_one_input)`。
- 运行纯 Ruby target:先 export ASAN_OPTIONS,再 `LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') ruby test_tracer.rb`。
- 故障排查:安装失败则验证 clang 路径,使用 clang 14.0.0+;`cannot open shared object file` 则设置内联 LD_PRELOAD;fuzzer 立即退出则创建 corpus 目录或作为参数传入;无覆盖率进展则纯 Ruby 使用 tracer 脚本;泄漏检测刷屏则 `ASAN_OPTIONS=detect_leaks=0`;需要安装调试则 `RUZZY_DEBUG=1 gem install --verbose ruzzy`。
- 需要详细 harness 编写技巧、复杂输入处理模式、高级策略时,参考 `fuzz-harness-writing`。
- 需要详细 sanitizer 配置、常见问题、高级标志时,参考 `address-sanitizer` 和 `undefined-behavior-sanitizer`。
- 需要理解 libFuzzer 选项时参考 libFuzzer 文档(Ruzzy 构建于 libFuzzer 之上)。
- 相关 fuzzer 选择:直接对 Ruby C 扩展代码用 C/C++ fuzzing 时考虑 libfuzzer;通过插桩 Ruby 解释器作为替代方案时考虑 aflpp。
- 参考资源:Trail of Bits 博客 “Introducing Ruzzy, a coverage-guided Ruby fuzzer”;Ruzzy GitHub 仓库;libFuzzer 文档;Fuzzing Ruby C extensions 指南;Fuzzing pure Ruby code 指南。
适用边界 · 注意事项
- 不适用于没有 Linux x86-64/AArch64/ARM64 环境或无法运行 Docker/开发容器的场景。
- 不适用于不能安装 clang、Ruby gem 和 Ruzzy 的环境。
- 如果只需普通单元测试/属性测试,或目标不是 Ruby 代码/Ruby C 扩展,则不必使用 Ruzzy。