RuzzySkill ruzzy

Ruzzy是一个基于libFuzzer的覆盖引导Ruby模糊测试工具,用于检测Ruby代码和C扩展中的内存损坏和未定义行为。关键词:Ruby模糊测试,覆盖引导,内存安全,C扩展测试,软件测试,自动化测试。

测试 0 次安装 0 次浏览 更新于 3/24/2026

名称: ruzzy 类型: fuzzer 描述: > Ruzzy是Trail of Bits开发的一个覆盖引导的Ruby模糊测试工具。 用于模糊测试纯Ruby代码和Ruby C扩展。

Ruzzy

Ruzzy是一个基于libFuzzer的覆盖引导模糊测试工具,用于Ruby。它支持模糊测试纯Ruby代码和Ruby C扩展,并带有检测内存损坏和未定义行为的消毒剂支持。

何时使用

Ruzzy是目前唯一生产就绪的覆盖引导Ruby模糊测试工具。

选择Ruzzy当:

  • 模糊测试Ruby应用程序或库
  • 测试Ruby C扩展的内存安全问题
  • 您需要Ruby代码的覆盖引导模糊测试
  • 处理具有本地扩展的Ruby gems

快速开始

设置环境:

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 -e 'require "ruzzy"; Ruzzy.dummy'

这应该快速找到一个崩溃,证明Ruzzy正常工作。

安装

平台支持

Ruzzy支持Linux x86-64和AArch64/ARM64。对于macOS或Windows,使用Dockerfile开发环境

先决条件

  • Linux x86-64或AArch64/ARM64
  • 最近版本的clang(测试回溯到14.0.0,推荐最新版本)
  • 带有gem安装的Ruby

安装命令

使用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

验证

通过运行玩具示例验证安装(见快速开始部分)。

编写测试工具

模糊测试纯Ruby代码

纯Ruby模糊测试需要两个脚本,由于Ruby解释器实现细节。

跟踪脚本 (test_tracer.rb):

# frozen_string_literal: true

require 'ruzzy'

Ruzzy.trace('test_harness.rb')

测试工具脚本 (test_harness.rb):

# frozen_string_literal: true

require '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)

运行:

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

模糊测试Ruby C扩展

C扩展可以用单个测试工具文件模糊测试,无需跟踪器。

msgpack的示例测试工具 (fuzz_msgpack.rb):

# frozen_string_literal: true

require '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)

运行:

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

测试工具规则

不做
如果测试C扩展,捕获Ruby异常 让Ruby异常崩溃模糊测试器
从test_one_input lambda返回0 返回其他值
保持测试工具确定性 使用随机性或基于时间的逻辑
对纯Ruby使用跟踪脚本 对纯Ruby代码跳过跟踪器

另见: 对于详细的测试工具编写技术、处理复杂输入的策略和高级策略,参见fuzz-harness-writing技术技能。

编译

使用消毒剂安装Gems

当安装Ruby gems以进行模糊测试时,使用消毒剂标志编译:

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和模糊测试器仪器
-fno-omit-frame-pointer 提高堆栈跟踪质量
-fno-common 更好的消毒剂兼容性
-fPIC 共享库的位置无关代码
-g 包含调试符号

运行活动

环境设置

运行任何模糊测试活动前,设置ASAN_OPTIONS:

export ASAN_OPTIONS="allocator_may_return_null=1:detect_leaks=0:use_sigaltstack=0"

选项解释:

  1. allocator_may_return_null=1: 跳过常见的低影响分配失败(DoS)
  2. detect_leaks=0: Ruby解释器泄漏数据,暂时忽略这些
  3. use_sigaltstack=0: Ruby推荐在使用ASan时禁用sigaltstack

基本运行

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

注意: LD_PRELOAD 是消毒剂注入所必需的。与 ASAN_OPTIONS 不同,不要导出它,因为它可能干扰其他程序。

使用语料库

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

传递libFuzzer选项

所有libFuzzer选项可以作为参数传递:

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

参见libFuzzer选项获取完整参考。

复制崩溃

通过传递崩溃文件重新运行崩溃案例:

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

解释输出

输出 含义
INFO: Running with entropic power schedule 模糊测试活动开始
ERROR: AddressSanitizer: heap-use-after-free 检测到内存损坏
SUMMARY: libFuzzer: fuzz target exited 发生Ruby异常
artifact_prefix='./'; Test unit written to ./crash-* 崩溃输入保存
Base64: ... 崩溃输入的Base64编码

消毒剂集成

AddressSanitizer (ASan)

Ruzzy包含一个预编译的AddressSanitizer库:

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

使用ASan检测:

  • 堆缓冲区溢出
  • 栈缓冲区溢出
  • 使用后释放
  • 双重释放
  • 内存泄漏(在Ruzzy中默认禁用)

UndefinedBehaviorSanitizer (UBSan)

Ruzzy还包含UBSan:

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

使用UBSan检测:

  • 有符号整数溢出
  • 空指针解引用
  • 未对齐内存访问
  • 除以零

常见消毒剂问题

问题 解决方案
Ruby解释器泄漏警告 使用 ASAN_OPTIONS=detect_leaks=0
Sigaltstack冲突 使用 ASAN_OPTIONS=use_sigaltstack=0
分配失败垃圾邮件 使用 ASAN_OPTIONS=allocator_may_return_null=1
LD_PRELOAD干扰工具 不要导出它;在ruby命令中内联设置

另见: 对于详细的消毒剂配置、常见问题和高级标志,参见address-sanitizerundefined-behavior-sanitizer技术技能。

真实世界示例

示例: msgpack-ruby

模糊测试msgpack MessagePack解析器以检测内存损坏。

使用消毒剂安装:

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

测试工具 (fuzz_msgpack.rb):

# frozen_string_literal: true

require '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)

运行:

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目标

模糊测试纯Ruby代码与自定义解析器。

跟踪器 (test_tracer.rb):

# frozen_string_literal: true

require 'ruzzy'

Ruzzy.trace('test_harness.rb')

测试工具 (test_harness.rb):

# frozen_string_literal: true

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)

运行:

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

故障排除

问题 原因 解决方案
安装失败 错误的clang版本或路径 验证clang路径,使用clang 14.0.0+
cannot open shared object file LD_PRELOAD未设置 在ruby命令中内联设置LD_PRELOAD
模糊测试器立即退出 缺少语料库目录 创建语料库目录或作为参数传递
无覆盖进度 纯Ruby需要跟踪器 对纯Ruby代码使用跟踪脚本
泄漏检测垃圾邮件 Ruby解释器泄漏 设置 ASAN_OPTIONS=detect_leaks=0
安装调试需要 编译错误 使用 RUZZY_DEBUG=1 gem install --verbose ruzzy

相关技能

技术技能

技能 使用案例
fuzz-harness-writing 编写有效测试工具的详细指导
address-sanitizer 模糊测试期间的内存错误检测
undefined-behavior-sanitizer 检测C扩展中的未定义行为
libfuzzer 理解libFuzzer选项(Ruzzy基于libFuzzer)

相关模糊测试器

技能 何时考虑
libfuzzer 当直接在C/C++中模糊测试Ruby C扩展代码时
aflpp 通过仪器化Ruby解释器模糊测试Ruby的替代方法

资源

关键外部资源

介绍Ruzzy,一个覆盖引导Ruby模糊测试器 Trail of Bits官方博客文章宣布Ruzzy,涵盖动机、架构和初步结果。

Ruzzy GitHub仓库 源代码、额外示例和开发说明。

libFuzzer文档 由于Ruzzy基于libFuzzer,理解libFuzzer选项和行为是有价值的。

模糊测试Ruby C扩展 模糊测试C扩展的详细指南,包括编译标志和示例。

模糊测试纯Ruby代码 模糊测试纯Ruby代码所需的跟踪器模式的详细指南。