ruzzy
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseRuzzy
Ruzzy
Ruzzy is a coverage-guided fuzzer for Ruby built on libFuzzer. It enables fuzzing both pure Ruby code and Ruby C extensions with sanitizer support for detecting memory corruption and undefined behavior.
Ruzzy是一款基于libFuzzer构建的、针对Ruby的覆盖率引导模糊测试工具。它支持对纯Ruby代码和Ruby C扩展进行模糊测试,同时集成了sanitizer以检测内存损坏和未定义行为。
When to Use
适用场景
Ruzzy is currently the only production-ready coverage-guided fuzzer for Ruby.
Choose Ruzzy when:
- Fuzzing Ruby applications or libraries
- Testing Ruby C extensions for memory safety issues
- You need coverage-guided fuzzing for Ruby code
- Working with Ruby gems that have native extensions
Ruzzy是目前唯一一款可用于生产环境的、针对Ruby的覆盖率引导模糊测试工具。
选择Ruzzy的场景:
- 对Ruby应用或库进行模糊测试
- 测试Ruby C扩展的内存安全性问题
- 需要为Ruby代码提供覆盖率引导的模糊测试
- 处理包含原生扩展的Ruby gem
Quick Start
快速开始
Set up environment:
bash
export ASAN_OPTIONS="allocator_may_return_null=1:detect_leaks=0:use_sigaltstack=0"Test with the included toy example:
bash
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
ruby -e 'require "ruzzy"; Ruzzy.dummy'This should quickly find a crash demonstrating that Ruzzy is working correctly.
设置环境:
bash
export ASAN_OPTIONS="allocator_may_return_null=1:detect_leaks=0:use_sigaltstack=0"使用内置的示例进行测试:
bash
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
ruby -e 'require "ruzzy"; Ruzzy.dummy'该命令应能快速发现崩溃问题,证明Ruzzy正常工作。
Installation
安装
Platform Support
平台支持
Ruzzy supports Linux x86-64 and AArch64/ARM64. For macOS or Windows, use the Dockerfile or development environment.
Ruzzy支持Linux x86-64和AArch64/ARM64架构。对于macOS或Windows系统,请使用Dockerfile或开发环境。
Prerequisites
前置要求
- Linux x86-64 or AArch64/ARM64
- Recent version of clang (tested back to 14.0.0, latest release recommended)
- Ruby with gem installed
- Linux x86-64或AArch64/ARM64架构
- 较新版本的clang(测试支持至14.0.0,推荐使用最新版本)
- 已安装gem的Ruby环境
Installation Command
安装命令
Install Ruzzy with clang compiler flags:
bash
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 ruzzyEnvironment variables explained:
- : Overrides make to respect subsequent environment variables
MAKE - ,
CC,CXX,LDSHARED: Ensure proper clang binaries are used for latest featuresLDSHAREDXX
使用clang编译器标志安装Ruzzy:
bash
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:确保使用正确的clang二进制文件以支持最新特性LDSHAREDXX
Troubleshooting Installation
安装故障排除
If installation fails, enable debug output:
bash
RUZZY_DEBUG=1 gem install --verbose ruzzy如果安装失败,启用调试输出:
bash
RUZZY_DEBUG=1 gem install --verbose ruzzyVerification
验证安装
Verify installation by running the toy example (see Quick Start section).
通过运行快速开始部分的示例来验证安装是否成功。
Writing a Harness
编写测试Harness
Fuzzing Pure Ruby Code
对纯Ruby代码进行模糊测试
Pure Ruby fuzzing requires two scripts due to Ruby interpreter implementation details.
Tracer script ():
test_tracer.rbruby
undefined由于Ruby解释器的实现细节,对纯Ruby代码进行模糊测试需要两个脚本。
追踪脚本():
test_tracer.rbruby
undefinedfrozen_string_literal: true
frozen_string_literal: true
require 'ruzzy'
Ruzzy.trace('test_harness.rb')
**Harness script (`test_harness.rb`):**
```rubyrequire 'ruzzy'
Ruzzy.trace('test_harness.rb')
**测试Harness脚本(`test_harness.rb`):**
```rubyfrozen_string_literal: true
frozen_string_literal: true
require 'ruzzy'
def fuzzing_target(input)
Your code to fuzz here
if input.length == 4
if input[0] == 'F'
if input[1] == 'U'
if input[2] == 'Z'
if input[3] == 'Z'
raise
end
end
end
end
end
end
test_one_input = lambda do |data|
fuzzing_target(data)
return 0
end
Ruzzy.fuzz(test_one_input)
Run with:
```bash
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
ruby test_tracer.rbrequire 'ruzzy'
def fuzzing_target(input)
此处放置待模糊测试的代码
if input.length == 4
if input[0] == 'F'
if input[1] == 'U'
if input[2] == 'Z'
if input[3] == 'Z'
raise
end
end
end
end
end
end
test_one_input = lambda do |data|
fuzzing_target(data)
return 0
end
Ruzzy.fuzz(test_one_input)
运行命令:
```bash
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
ruby test_tracer.rbFuzzing Ruby C Extensions
对Ruby C扩展进行模糊测试
C extensions can be fuzzed with a single harness file, no tracer needed.
Example harness for msgpack ():
fuzz_msgpack.rbruby
undefined对C扩展进行模糊测试只需一个Harness文件,无需追踪脚本。
针对msgpack的示例Harness():
fuzz_msgpack.rbruby
undefinedfrozen_string_literal: true
frozen_string_literal: true
require 'msgpack'
require 'ruzzy'
test_one_input = lambda do |data|
begin
MessagePack.unpack(data)
rescue Exception
# We're looking for memory corruption, not Ruby exceptions
end
return 0
end
Ruzzy.fuzz(test_one_input)
Run with:
```bash
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
ruby fuzz_msgpack.rbrequire 'msgpack'
require 'ruzzy'
test_one_input = lambda do |data|
begin
MessagePack.unpack(data)
rescue Exception
# 我们关注的是内存损坏,而非Ruby异常
end
return 0
end
Ruzzy.fuzz(test_one_input)
运行命令:
```bash
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
ruby fuzz_msgpack.rbHarness Rules
Harness编写规则
| Do | Don't |
|---|---|
| Catch Ruby exceptions if testing C extensions | Let Ruby exceptions crash the fuzzer |
| Return 0 from test_one_input lambda | Return other values |
| Keep harness deterministic | Use randomness or time-based logic |
| Use tracer script for pure Ruby | Skip tracer for pure Ruby code |
See Also: For detailed harness writing techniques, patterns for handling complex inputs, and advanced strategies, see the fuzz-harness-writing technique skill.
| 建议做法 | 禁止做法 |
|---|---|
| 测试C扩展时捕获Ruby异常 | 让Ruby异常导致模糊测试工具崩溃 |
| 从test_one_input lambda返回0 | 返回其他值 |
| 保持Harness的确定性 | 使用随机性或基于时间的逻辑 |
| 对纯Ruby代码使用追踪脚本 | 对纯Ruby代码跳过追踪脚本 |
另请参阅: 有关编写高效Harness的详细技巧、处理复杂输入的模式以及高级策略,请查看fuzz-harness-writing技术文档。
Compilation
编译
Installing Gems with Sanitizers
安装带Sanitizer的Gem
When installing Ruby gems with C extensions for fuzzing, compile with sanitizer flags:
bash
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>当安装用于模糊测试的、包含C扩展的Ruby gem时,需使用sanitizer标志进行编译:
bash
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>Build Flags
构建标志
| Flag | Purpose |
|---|---|
| Enable AddressSanitizer and fuzzer instrumentation |
| Improve stack trace quality |
| Better compatibility with sanitizers |
| Position-independent code for shared libraries |
| Include debug symbols |
| 标志 | 用途 |
|---|---|
| 启用AddressSanitizer和模糊测试工具插桩 |
| 提升栈跟踪的质量 |
| 提升与sanitizer的兼容性 |
| 为共享库生成位置无关代码 |
| 包含调试符号 |
Running Campaigns
运行测试任务
Environment Setup
环境设置
Before running any fuzzing campaign, set ASAN_OPTIONS:
bash
export ASAN_OPTIONS="allocator_may_return_null=1:detect_leaks=0:use_sigaltstack=0"Options explained:
- : Skip common low-impact allocation failures (DoS)
allocator_may_return_null=1 - : Ruby interpreter leaks data, ignore these for now
detect_leaks=0 - : Ruby recommends disabling sigaltstack with ASan
use_sigaltstack=0
在运行任何模糊测试任务前,设置ASAN_OPTIONS:
bash
export ASAN_OPTIONS="allocator_may_return_null=1:detect_leaks=0:use_sigaltstack=0"选项说明:
- :跳过常见的低影响分配失败(拒绝服务类问题)
allocator_may_return_null=1 - :Ruby解释器存在数据泄漏,暂时忽略此类问题
detect_leaks=0 - :Ruby官方建议在使用ASan时禁用sigaltstack
use_sigaltstack=0
Basic Run
基础运行
bash
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
ruby harness.rbNote: is required for sanitizer injection. Unlike , do not export it as it may interfere with other programs.
LD_PRELOADASAN_OPTIONSbash
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
ruby harness.rb注意: 是注入sanitizer所必需的。与不同,请勿导出该变量,否则可能会干扰其他程序。
LD_PRELOADASAN_OPTIONSWith Corpus
使用语料库
bash
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
ruby harness.rb /path/to/corpusbash
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
ruby harness.rb /path/to/corpusPassing libFuzzer Options
传递libFuzzer选项
All libFuzzer options can be passed as arguments:
bash
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
ruby harness.rb /path/to/corpus -max_len=1024 -timeout=10See libFuzzer options for full reference.
所有libFuzzer选项均可作为参数传递:
bash
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
ruby harness.rb /path/to/corpus -max_len=1024 -timeout=10有关完整选项列表,请参阅libFuzzer文档。
Reproducing Crashes
复现崩溃
Re-run a crash case by passing the crash file:
bash
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
ruby harness.rb ./crash-253420c1158bc6382093d409ce2e9cff5806e980通过传递崩溃文件来重新运行崩溃案例:
bash
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
ruby harness.rb ./crash-253420c1158bc6382093d409ce2e9cff5806e980Interpreting Output
输出解读
| Output | Meaning |
|---|---|
| Fuzzing campaign started |
| Memory corruption detected |
| Ruby exception occurred |
| Crash input saved |
| Base64 encoding of crash input |
| 输出内容 | 含义 |
|---|---|
| 模糊测试任务已启动 |
| 检测到内存损坏 |
| 发生Ruby异常 |
| 已保存崩溃输入 |
| 崩溃输入的Base64编码 |
Sanitizer Integration
Sanitizer集成
AddressSanitizer (ASan)
AddressSanitizer (ASan)
Ruzzy includes a pre-compiled AddressSanitizer library:
bash
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
ruby harness.rbUse ASan for detecting:
- Heap buffer overflows
- Stack buffer overflows
- Use-after-free
- Double-free
- Memory leaks (disabled by default in Ruzzy)
Ruzzy包含预编译的AddressSanitizer库:
bash
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
ruby harness.rb使用ASan可检测:
- 堆缓冲区溢出
- 栈缓冲区溢出
- 释放后使用
- 重复释放
- 内存泄漏(Ruzzy中默认禁用)
UndefinedBehaviorSanitizer (UBSan)
UndefinedBehaviorSanitizer (UBSan)
Ruzzy also includes UBSan:
bash
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::UBSAN_PATH') \
ruby harness.rbUse UBSan for detecting:
- Signed integer overflow
- Null pointer dereferences
- Misaligned memory access
- Division by zero
Ruzzy同样集成了UBSan:
bash
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::UBSAN_PATH') \
ruby harness.rb使用UBSan可检测:
- 有符号整数溢出
- 空指针解引用
- 内存访问未对齐
- 除零错误
Common Sanitizer Issues
常见Sanitizer问题
| Issue | Solution |
|---|---|
| Ruby interpreter leak warnings | Use |
| Sigaltstack conflicts | Use |
| Allocation failure spam | Use |
| LD_PRELOAD interferes with tools | Don't export it; set inline with ruby command |
See Also: For detailed sanitizer configuration, common issues, and advanced flags, see the address-sanitizer and undefined-behavior-sanitizer technique skills.
| 问题 | 原因 | 解决方案 |
|-------|----------|
| Ruby解释器泄漏警告 | Ruby解释器本身存在数据泄漏 | 设置 |
| Sigaltstack冲突 | Ruby与ASan的sigaltstack设置不兼容 | 设置 |
| 分配失败信息泛滥 | 低影响分配失败被频繁报告 | 设置 |
| LD_PRELOAD干扰其他工具 | 导出了LD_PRELOAD变量 | 不要导出LD_PRELOAD,仅在运行Ruby命令时内联设置 |
ASAN_OPTIONS=detect_leaks=0ASAN_OPTIONS=use_sigaltstack=0ASAN_OPTIONS=allocator_may_return_null=1另请参阅: 有关sanitizer的详细配置、常见问题及高级标志,请查看address-sanitizer和undefined-behavior-sanitizer技术文档。
Real-World Examples
实际案例
Example: msgpack-ruby
案例:msgpack-ruby
Fuzzing the msgpack MessagePack parser for memory corruption.
Install with sanitizers:
bash
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 msgpackHarness ():
fuzz_msgpack.rbruby
undefined对msgpack的MessagePack解析器进行模糊测试以检测内存损坏。
安装带sanitizer的msgpack:
bash
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 msgpack测试Harness():
fuzz_msgpack.rbruby
undefinedfrozen_string_literal: true
frozen_string_literal: true
require 'msgpack'
require 'ruzzy'
test_one_input = lambda do |data|
begin
MessagePack.unpack(data)
rescue Exception
# We're looking for memory corruption, not Ruby exceptions
end
return 0
end
Ruzzy.fuzz(test_one_input)
**Run:**
```bash
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.rbrequire 'msgpack'
require 'ruzzy'
test_one_input = lambda do |data|
begin
MessagePack.unpack(data)
rescue Exception
# 我们关注的是内存损坏,而非Ruby异常
end
return 0
end
Ruzzy.fuzz(test_one_input)
**运行命令:**
```bash
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.rbExample: Pure Ruby Target
案例:纯Ruby目标
Fuzzing pure Ruby code with a custom parser.
Tracer ():
test_tracer.rbruby
undefined对包含自定义解析器的纯Ruby代码进行模糊测试。
追踪脚本():
test_tracer.rbruby
undefinedfrozen_string_literal: true
frozen_string_literal: true
require 'ruzzy'
Ruzzy.trace('test_harness.rb')
**Harness (`test_harness.rb`):**
```rubyrequire 'ruzzy'
Ruzzy.trace('test_harness.rb')
**测试Harness(`test_harness.rb`):**
```rubyfrozen_string_literal: true
frozen_string_literal: true
require 'ruzzy'
require_relative 'my_parser'
test_one_input = lambda do |data|
begin
MyParser.parse(data)
rescue StandardError
# Expected exceptions from malformed input
end
return 0
end
Ruzzy.fuzz(test_one_input)
**Run:**
```bash
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 test_tracer.rbrequire '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)
**运行命令:**
```bash
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 test_tracer.rbTroubleshooting
故障排除
| Problem | Cause | Solution |
|---|---|---|
| Installation fails | Wrong clang version or path | Verify clang path, use clang 14.0.0+ |
| LD_PRELOAD not set | Set LD_PRELOAD inline with ruby command |
| Fuzzer immediately exits | Missing corpus directory | Create corpus directory or pass as argument |
| No coverage progress | Pure Ruby needs tracer | Use tracer script for pure Ruby code |
| Leak detection spam | Ruby interpreter leaks | Set |
| Installation debug needed | Compilation errors | Use |
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 安装失败 | clang版本错误或路径不正确 | 验证clang路径,使用clang 14.0.0+版本 |
| 未设置LD_PRELOAD | 在运行Ruby命令时内联设置LD_PRELOAD |
| 模糊测试工具立即退出 | 缺少语料库目录 | 创建语料库目录或作为参数传递 |
| 覆盖率无进展 | 纯Ruby代码未使用追踪脚本 | 对纯Ruby代码使用追踪脚本 |
| 泄漏检测信息泛滥 | Ruby解释器存在泄漏 | 设置 |
| 需要安装调试信息 | 编译错误 | 使用 |
Related Skills
相关技术
Technique Skills
技术文档
| Skill | Use Case |
|---|---|
| fuzz-harness-writing | Detailed guidance on writing effective harnesses |
| address-sanitizer | Memory error detection during fuzzing |
| undefined-behavior-sanitizer | Detecting undefined behavior in C extensions |
| libfuzzer | Understanding libFuzzer options (Ruzzy is built on libFuzzer) |
| 技术 | 适用场景 |
|---|---|
| fuzz-harness-writing | 编写高效测试Harness的详细指南 |
| address-sanitizer | 模糊测试期间的内存错误检测 |
| undefined-behavior-sanitizer | 检测C扩展中的未定义行为 |
| libfuzzer | 理解libFuzzer选项(Ruzzy基于libFuzzer构建) |
Related Fuzzers
相关模糊测试工具
| Skill | When to Consider |
|---|---|
| libfuzzer | When fuzzing Ruby C extension code directly in C/C++ |
| aflpp | Alternative approach for fuzzing Ruby by instrumenting Ruby interpreter |
| 工具 | 适用场景 |
|---|---|
| libfuzzer | 直接在C/C++中对Ruby C扩展进行模糊测试时 |
| aflpp | 通过插桩Ruby解释器对Ruby进行模糊测试的替代方案 |
Resources
资源
Key External Resources
关键外部资源
Introducing Ruzzy, a coverage-guided Ruby fuzzer
Official Trail of Bits blog post announcing Ruzzy, covering motivation, architecture, and initial results.
Ruzzy GitHub Repository
Source code, additional examples, and development instructions.
libFuzzer Documentation
Since Ruzzy is built on libFuzzer, understanding libFuzzer options and behavior is valuable.
Fuzzing Ruby C extensions
Detailed guide on fuzzing C extensions with compilation flags and examples.
Fuzzing pure Ruby code
Detailed guide on the tracer pattern required for pure Ruby fuzzing.
Introducing Ruzzy, a coverage-guided Ruby fuzzer
Trail of Bits官方博客文章,介绍Ruzzy的开发动机、架构和初始测试结果。
Ruzzy GitHub Repository
源代码、更多示例及开发说明。
libFuzzer Documentation
由于Ruzzy基于libFuzzer构建,了解libFuzzer的选项和行为非常重要。
Fuzzing Ruby C extensions
关于使用编译标志和示例对C扩展进行模糊测试的详细指南。
Fuzzing pure Ruby code
关于对纯Ruby代码进行模糊测试所需的追踪模式的详细指南。