Ruzzy

作者 trailofbits82fe82262526無授權條款7.4K 個星標收錄於 2026年10月8日更新於 2026年10月8日儲存庫昨天更新

Sets up and runs Ruzzy, Trail of Bits' coverage-guided Ruby fuzzer and the only production-ready one for the language. Covers harness structure, fuzzing pure Ruby and the native C extensions in gems, and sanitizer builds. Use when fuzzing a Ruby library or gem, testing a Ruby C extension for memory safety, or asking how to fuzz Ruby at all.

AI 產生的概覽

指導安裝與使用 Ruzzy——Trail of Bits 針對 Ruby 程式碼與 C 擴充功能的覆蓋率導向模糊測試器。

功能
說明如何以 clang 和 sanitizer 旗標安裝 Ruzzy、撰寫 tracer 與 harness 指令碼,並執行覆蓋率導向的模糊測試活動。內容涵蓋純 Ruby 與 Ruby C 擴充功能的模糊測試、以 AddressSanitizer 和 UBSan 編譯 gem、傳遞 libFuzzer 選項、重現當機,以及解讀模糊測試輸出。此技能僅提供說明,本身不產生檔案。
適用情境
適用於對 Ruby 函式庫或 gem 進行模糊測試、測試 Ruby C 擴充功能的記憶體安全,或想了解如何對 Ruby 做模糊測試時。
執行需求
Linux x86-64 或 AArch64/ARM64、較新的 clang(14.0.0 以上)、含 gem 的 Ruby,以及以 sanitizer 旗標安裝的 ruzzy gem。執行測試活動需要設定 LD_PRELOAD 與 ASAN_OPTIONS 環境變數。此技能不附帶指令碼。

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.

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

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.

Installation

Platform Support

Ruzzy supports Linux x86-64 and AArch64/ARM64. For macOS or Windows, use the Dockerfile or development environment.

Prerequisites

  • Linux x86-64 or AArch64/ARM64
  • Recent version of clang (tested back to 14.0.0, latest release recommended)
  • Ruby with gem installed

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 ruzzy

Environment variables explained:

  • MAKE: Overrides make to respect subsequent environment variables
  • CC, CXX, LDSHARED, LDSHAREDXX: Ensure proper clang binaries are used for latest features

Troubleshooting Installation

If installation fails, enable debug output:

bash
RUZZY_DEBUG=1 gem install --verbose ruzzy

Verification

Verify installation by running the toy example (see Quick Start section).

Writing a Harness

Fuzzing Pure Ruby Code

Pure Ruby fuzzing requires two scripts due to Ruby interpreter implementation details.

Tracer script (test_tracer.rb):

ruby
# frozen_string_literal: true
require 'ruzzy'
Ruzzy.trace('test_harness.rb')

Harness script (test_harness.rb):

ruby
# 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  endend
test_one_input = lambda do |data|  fuzzing_target(data)  return 0end
Ruzzy.fuzz(test_one_input)

Run with:

bash
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \    ruby test_tracer.rb

Fuzzing Ruby C Extensions

C extensions can be fuzzed with a single harness file, no tracer needed.

Example harness for msgpack (fuzz_msgpack.rb):

ruby
# 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 0end
Ruzzy.fuzz(test_one_input)

Run with:

bash
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \    ruby fuzz_msgpack.rb

Harness Rules

DoDon't
Catch Ruby exceptions if testing C extensionsLet Ruby exceptions crash the fuzzer
Return 0 from test_one_input lambdaReturn other values
Keep harness deterministicUse randomness or time-based logic
Use tracer script for pure RubySkip 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.

Compilation

Installing Gems with Sanitizers

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>

Build Flags

FlagPurpose
-fsanitize=address,fuzzer-no-linkEnable AddressSanitizer and fuzzer instrumentation
-fno-omit-frame-pointerImprove stack trace quality
-fno-commonBetter compatibility with sanitizers
-fPICPosition-independent code for shared libraries
-gInclude debug symbols

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:

  1. allocator_may_return_null=1: Skip common low-impact allocation failures (DoS)
  2. detect_leaks=0: Ruby interpreter leaks data, ignore these for now
  3. use_sigaltstack=0: Ruby recommends disabling sigaltstack with ASan

Basic Run

bash
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \    ruby harness.rb

Note: LD_PRELOAD is required for sanitizer injection. Unlike ASAN_OPTIONS, do not export it as it may interfere with other programs.

With Corpus

bash
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \    ruby harness.rb /path/to/corpus

Passing libFuzzer Options

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=10

See libFuzzer options for full reference.

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

Interpreting Output

OutputMeaning
INFO: Running with entropic power scheduleFuzzing campaign started
ERROR: AddressSanitizer: heap-use-after-freeMemory corruption detected
SUMMARY: libFuzzer: fuzz target exitedRuby exception occurred
artifact_prefix='./'; Test unit written to ./crash-*Crash input saved
Base64: ...Base64 encoding of crash input

Sanitizer Integration

AddressSanitizer (ASan)

Ruzzy includes a pre-compiled AddressSanitizer library:

bash
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \    ruby harness.rb

Use ASan for detecting:

  • Heap buffer overflows
  • Stack buffer overflows
  • Use-after-free
  • Double-free
  • Memory leaks (disabled by default in Ruzzy)

UndefinedBehaviorSanitizer (UBSan)

Ruzzy also includes UBSan:

bash
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::UBSAN_PATH') \    ruby harness.rb

Use UBSan for detecting:

  • Signed integer overflow
  • Null pointer dereferences
  • Misaligned memory access
  • Division by zero

Common Sanitizer Issues

IssueSolution
Ruby interpreter leak warningsUse ASAN_OPTIONS=detect_leaks=0
Sigaltstack conflictsUse ASAN_OPTIONS=use_sigaltstack=0
Allocation failure spamUse ASAN_OPTIONS=allocator_may_return_null=1
LD_PRELOAD interferes with toolsDon'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.

Real-World Examples

Example: 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 msgpack

Harness (fuzz_msgpack.rb):

ruby
# 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 0end
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.rb

Example: Pure Ruby Target

Fuzzing pure Ruby code with a custom parser.

Tracer (test_tracer.rb):

ruby
# frozen_string_literal: true
require 'ruzzy'
Ruzzy.trace('test_harness.rb')

Harness (test_harness.rb):

ruby
# 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 0end
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.rb

Troubleshooting

ProblemCauseSolution
Installation failsWrong clang version or pathVerify clang path, use clang 14.0.0+
cannot open shared object fileLD_PRELOAD not setSet LD_PRELOAD inline with ruby command
Fuzzer immediately exitsMissing corpus directoryCreate corpus directory or pass as argument
No coverage progressPure Ruby needs tracerUse tracer script for pure Ruby code
Leak detection spamRuby interpreter leaksSet ASAN_OPTIONS=detect_leaks=0
Installation debug neededCompilation errorsUse RUZZY_DEBUG=1 gem install --verbose ruzzy

Related Skills

Technique Skills

SkillUse Case
fuzz-harness-writingDetailed guidance on writing effective harnesses
address-sanitizerMemory error detection during fuzzing
undefined-behavior-sanitizerDetecting undefined behavior in C extensions
libfuzzerUnderstanding libFuzzer options (Ruzzy is built on libFuzzer)

Related Fuzzers

SkillWhen to Consider
libfuzzerWhen fuzzing Ruby C extension code directly in C/C++
aflppAlternative approach for fuzzing Ruby by instrumenting Ruby interpreter

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.

來源與署名

來源:trailofbits/skills位於plugins/testing-handbook-skills/skills/ruzzy提交82fe822

授權條款: 無授權條款

內容歸原作者所有。SourceWeft 從公開儲存庫中收錄這些內容。

檢舉或申請下架