mcpField
C
cargo-fuzz

cargo-fuzz

github.com/trailofbits测试与质量7.9k5.4k 次安装今天更新
代码仓库

关于 cargo-fuzz

cargo-fuzz 是面向使用 Cargo 的 Rust 项目的模糊测试命令行工具,基于 libFuzzer,并自动设置相关编译选项及 AddressSanitizer 支持。

主要功能

  1. 01基于 libFuzzer 进行模糊测试
  2. 02Cargo 子命令快速初始化目标
  3. 03默认集成 AddressSanitizer
  4. 04支持 arbitrary 结构化输入
  5. 05生成覆盖率数据与报告

适用场景

  1. 01测试 Rust 库处理任意输入的能力
  2. 02对解析器等输入处理代码进行模糊测试
  3. 03重放崩溃用例并检查覆盖率

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/trailofbits/skills --skill cargo-fuzz

安装后在 Claude Code 中输入/cargo-fuzz确认已加载。

附带文件agents/openai.yamlassets/trail-of-bits-mark.svg

详细介绍

cargo-fuzz

在使用 Cargo 对 Rust 项目进行模糊测试时,cargo-fuzz 是事实上的首选。它使用 libFuzzer 作为后端,并提供便捷的 Cargo 子命令,自动为 Rust 项目启用相关编译标志,包括支持 AddressSanitizer 等消毒器。

适用场景

对于使用 Cargo 的 Rust 项目,cargo-fuzz 目前是主要且最成熟的模糊测试解决方案。

模糊测试器最适用场景复杂度
cargo-fuzz基于 Cargo 的 Rust 项目、快速设置低
AFL++多核模糊测试、非 Cargo 项目中
LibAFL自定义模糊测试器、研究、高级用例高

在以下情况下选择 cargo-fuzz:

  • 项目使用 Cargo(必需)
  • 希望轻松快速地完成设置,尽量减少配置
  • 需要集成的消毒器支持
  • 要对带有或不带有 unsafe 代码块的 Rust 代码进行模糊测试

快速入门

#![no_main]

use libfuzzer_sys::fuzz_target;

fn harness(data: &[u8]) {
    your_project::check_buf(data);
}

fuzz_target!(|data: &[u8]| {
    harness(data);
});

初始化并运行:

cargo fuzz init
# Edit fuzz/fuzz_targets/fuzz_target_1.rs with your harness
cargo +nightly fuzz run fuzz_target_1

安装

cargo-fuzz 需要 nightly Rust 工具链,因为它使用了仅在 nightly 中提供的功能。

先决条件
  • 通过 rustup 安装 Rust 和 Cargo
  • Nightly 工具链
Linux/macOS
# Install nightly toolchain
rustup install nightly

# Install cargo-fuzz
cargo install cargo-fuzz
验证
cargo +nightly --version
cargo fuzz --version

编写 Harness

项目结构

将代码组织为库 crate 时,cargo-fuzz 的效果最佳。如果你的项目是二进制项目,请将 main.rs 拆分为:

src/main.rs  # Entry point (main function)
src/lib.rs   # Code to fuzz (public functions)
Cargo.toml

初始化模糊测试:

cargo fuzz init

这会创建:

fuzz/
├── Cargo.toml
└── fuzz_targets/
    └── fuzz_target_1.rs
Harness 结构
#![no_main]

use libfuzzer_sys::fuzz_target;

fn harness(data: &[u8]) {
    // 1. Validate input size if needed
    if data.is_empty() {
        return;
    }

    // 2. Call target function with fuzz data
    your_project::target_function(data);
}

fuzz_target!(|data: &[u8]| {
    harness(data);
});
Harness 规则
应做不应做
将代码组织为库 crate将所有内容放在 main.rs 中
使用 fuzz_target! 宏编写自定义 main 函数
妥善处理 Result::Err对预期错误触发 panic
保持 harness 确定性使用随机数生成器

另请参阅: 有关详细的 harness 编写技巧和使用 arbitrary crate 进行的结构感知模糊测试,请参阅 fuzz-harness-writing 技巧技能。

结构感知模糊测试

cargo-fuzz 集成了 arbitrary crate,可进行结构感知模糊测试:

// In your library crate
use arbitrary::Arbitrary;

#[derive(Debug, Arbitrary)]
pub struct Name {
    data: String
}
// In your fuzz target
#![no_main]
use libfuzzer_sys::fuzz_target;

fuzz_target!(|data: your_project::Name| {
    data.check_buf();
});

在库的 Cargo.toml 中添加:

[dependencies]
arbitrary = { version = "1", features = ["derive"] }

运行测试活动

基本运行
cargo +nightly fuzz run fuzz_target_1
不使用消毒器(安全 Rust)

如果项目不使用 unsafe Rust,请禁用消毒器以提升 2 倍性能:

cargo +nightly fuzz run --sanitizer none fuzz_target_1

检查项目是否使用 unsafe 代码:

cargo install cargo-geiger
cargo geiger
重新执行测试用例
# Run a specific test case (e.g., a crash)
cargo +nightly fuzz run fuzz_target_1 fuzz/artifacts/fuzz_target_1/crash-<hash>

# Run all corpus entries without fuzzing
cargo +nightly fuzz run fuzz_target_1 fuzz/corpus/fuzz_target_1 -- -runs=0
使用字典
cargo +nightly fuzz run fuzz_target_1 -- -dict=./dict.dict
解读输出
输出含义
NEW发现了能够提高覆盖率的新输入
pulse定期状态更新
INITED模糊测试器已成功初始化
带堆栈跟踪的崩溃发现 Bug,已保存到 fuzz/artifacts/

语料库位置:fuzz/corpus/fuzz_target_1/ 崩溃文件位置:fuzz/artifacts/fuzz_target_1/

消毒器集成

AddressSanitizer (ASan)

ASan 默认启用,可检测内存错误:

cargo +nightly fuzz run fuzz_target_1
禁用消毒器

对于纯安全 Rust(你的代码或依赖项中没有 unsafe 代码块):

cargo +nightly fuzz run --sanitizer none fuzz_target_1

性能影响: ASan 会带来约 2 倍的开销。对于安全 Rust,禁用它可以提高模糊测试速度。

检查 unsafe 代码
cargo install cargo-geiger
cargo geiger

另请参阅: 有关详细的消毒器配置、标志和故障排查, 请参阅 address-sanitizer 技巧技能。

覆盖率分析

cargo-fuzz 集成了 Rust 的覆盖率工具,可分析模糊测试的有效性。

先决条件
rustup toolchain install nightly --component llvm-tools-preview
cargo install cargo-binutils
cargo install rustfilt
生成覆盖率报告
# Generate coverage data from corpus
cargo +nightly fuzz coverage fuzz_target_1

创建覆盖率生成脚本:

cat <<'EOF' > ./generate_html
#!/bin/sh
if [ $# -lt 1 ]; then
    echo "Error: Name of fuzz target is required."
    echo "Usage: $0 fuzz_target [sources...]"
    exit 1
fi
FUZZ_TARGET="$1"
shift
SRC_FILTER="$@"
TARGET=$(rustc -vV | sed -n 's|host: ||p')
cargo +nightly cov -- show -Xdemangler=rustfilt \
  "target/$TARGET/coverage/$TARGET/release/$FUZZ_TARGET" \
  -instr-profile="fuzz/coverage/$FUZZ_TARGET/coverage.profdata"  \
  -show-line-counts-or-regions -show-instantiations  \
  -format=html -o fuzz_html/ $SRC_FILTER
EOF
chmod +x ./generate_html

生成 HTML 报告:

./generate_html fuzz_target_1 src/lib.rs

HTML 报告已保存到:fuzz_html/

另请参阅: 有关详细的覆盖率分析技巧和系统化的覆盖率改进, 请参阅 coverage-analysis 技巧技能。

高级用法

提示与技巧
提示帮助原因
从种子语料库开始大幅加快初始覆盖率发现
对安全的 Rust 使用 --sanitizer none性能提升 2 倍
定期检查覆盖率找出测试框架或种子语料库中的缺口
为解析器使用字典帮助绕过魔数检查
将代码组织为库与 cargo-fuzz 集成的必要条件
libFuzzer 选项

在 -- 后向 libFuzzer 传递选项:

# See all options
cargo +nightly fuzz run fuzz_target_1 -- -help=1

# Set timeout per run
cargo +nightly fuzz run fuzz_target_1 -- -timeout=10

# Use dictionary
cargo +nightly fuzz run fuzz_target_1 -- -dict=dict.dict

# Limit maximum input size
cargo +nightly fuzz run fuzz_target_1 -- -max_len=1024
多核模糊测试
# Experimental forking support (not recommended)
cargo +nightly fuzz run --jobs 1 fuzz_target_1

注意:多核模糊测试功能仍处于实验阶段,不建议使用。如需并行模糊测试,可考虑手动运行多个实例,或使用 AFL++。

真实示例

示例:ogg Crate

ogg crate 用于解析 Ogg 媒体容器文件。解析器是很好的模糊测试目标,因为它们会处理不受信任的数据。

# Clone and initialize
git clone https://github.com/RustAudio/ogg.git
cd ogg/
cargo fuzz init

测试框架位于 fuzz/fuzz_targets/fuzz_target_1.rs:

#![no_main]

use ogg::{PacketReader, PacketWriter};
use ogg::writing::PacketWriteEndInfo;
use std::io::Cursor;
use libfuzzer_sys::fuzz_target;

fn harness(data: &[u8]) {
    let mut pck_rdr = PacketReader::new(Cursor::new(data.to_vec()));
    pck_rdr.delete_unread_packets();

    let output = Vec::new();
    let mut pck_wtr = PacketWriter::new(Cursor::new(output));

    if let Ok(_) = pck_rdr.read_packet() {
        if let Ok(r) = pck_rdr.read_packet() {
            match r {
                Some(pck) => {
                    let inf = if pck.last_in_stream() {
                        PacketWriteEndInfo::EndStream
                    } else if pck.last_in_page() {
                        PacketWriteEndInfo::EndPage
                    } else {
                        PacketWriteEndInfo::NormalPacket
                    };
                    let stream_serial = pck.stream_serial();
                    let absgp_page = pck.absgp_page();
                    let _ = pck_wtr.write_packet(
                        pck.data, stream_serial, inf, absgp_page
                    );
                }
                None => return,
            }
        }
    }
}

fuzz_target!(|data: &[u8]| {
    harness(data);
});

为语料库添加种子:

mkdir fuzz/corpus/fuzz_target_1/
curl -o fuzz/corpus/fuzz_target_1/320x240.ogg \
  https://commons.wikimedia.org/wiki/File:320x240.ogg

运行:

cargo +nightly fuzz run fuzz_target_1

分析覆盖率:

cargo +nightly fuzz coverage fuzz_target_1
./generate_html fuzz_target_1 src/lib.rs

故障排除

问题原因解决方案
出现 "requires nightly" 错误使用了 stable 工具链使用 cargo +nightly fuzz
模糊测试性能较慢对安全的 Rust 启用了 ASan添加 --sanitizer none 标志
出现 "cannot find binary"没有库 crate将代码从 main.rs 移至 lib.rs
Sanitizer 编译问题nightly 版本不正确尝试其他 nightly 版本:rustup install nightly-2024-01-01
覆盖率低缺少种子语料库将示例输入添加到 fuzz/corpus/fuzz_target_1/
未找到魔数没有字典创建包含魔数的字典文件

相关技能

技术技能
技能使用场景
fuzz-harness-writing使用 arbitrary crate 进行结构感知模糊测试
address-sanitizer理解 ASan 输出和配置
coverage-analysis衡量并提升模糊测试的有效性
fuzzing-corpus构建和管理种子语料库
fuzzing-dictionaries为格式感知模糊测试创建字典
相关模糊测试工具
技能适用场景
libfuzzer使用类似工作流对 C/C++ 代码进行模糊测试
aflpp多核模糊测试或非 Cargo Rust 项目
libafl高级模糊测试研究或自定义模糊测试工具开发

资源

Rust Fuzz Book - cargo-fuzz cargo-fuzz 官方文档,涵盖安装、使用和高级功能。

arbitrary crate 文档 介绍结构感知模糊测试,以及如何为 Rust 类型自动派生实现。

cargo-fuzz GitHub 仓库 cargo-fuzz 的源代码、问题跟踪器和示例。

评论

支持 Markdown