cargo-fuzzSkill cargo-fuzz

这个技能是关于使用 cargo-fuzz 工具进行 Rust 代码的模糊测试。它帮助开发者在 Cargo-based 项目中快速设置模糊测试,集成地址消毒器等安全工具,提高代码质量和安全性。关键词:模糊测试、Rust、Cargo、libFuzzer、安全测试、软件测试、漏洞挖掘。

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

name: cargo-fuzz type: fuzzer description: > cargo-fuzz 是使用 Cargo 的 Rust 项目的默认模糊测试工具。 用于通过 libFuzzer 后端进行 Rust 代码的模糊测试。

cargo-fuzz

cargo-fuzz 是使用 Cargo 时模糊测试 Rust 项目的首选工具。它使用 libFuzzer 作为后端,并提供一个方便的 Cargo 子命令,自动为你的 Rust 项目启用相关编译标志,包括对地址消毒器等消毒器的支持。

何时使用

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

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

选择 cargo-fuzz 当:

  • 你的项目使用 Cargo(必需)
  • 你想要简单、快速的设置,配置最少
  • 你需要集成消毒器支持
  • 你在模糊测试带有或不带有不安全块的 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
# 编辑 fuzz/fuzz_targets/fuzz_target_1.rs 以添加你的测试体
cargo +nightly fuzz run fuzz_target_1

安装

cargo-fuzz 需要 nightly Rust 工具链,因为它使用仅 nightly 可用的功能。

先决条件

  • 通过 rustup 安装的 Rust 和 Cargo
  • Nightly 工具链

Linux/macOS

# 安装 nightly 工具链
rustup install nightly

# 安装 cargo-fuzz
cargo install cargo-fuzz

验证

cargo +nightly --version
cargo fuzz --version

编写测试体

项目结构

cargo-fuzz 在代码结构为库 crate 时效果最佳。如果你有二进制项目,将 main.rs 拆分为:

src/main.rs  # 入口点(主函数)
src/lib.rs   # 要模糊测试的代码(公共函数)
Cargo.toml

初始化模糊测试:

cargo fuzz init

这会创建:

fuzz/
├── Cargo.toml
└── fuzz_targets/
    └── fuzz_target_1.rs

测试体结构

#![no_main]

use libfuzzer_sys::fuzz_target;

fn harness(data: &[u8]) {
    // 1. 如果需要,验证输入大小
    if data.is_empty() {
        return;
    }

    // 2. 用模糊数据调用目标函数
    your_project::target_function(data);
}

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

测试体规则

不要
将代码结构为库 crate 将所有内容保留在 main.rs
使用 fuzz_target! 编写自定义主函数
优雅地处理 Result::Err 在预期错误时恐慌
保持测试体确定性 使用随机数生成器

另请参阅: 对于详细的测试体编写技术和使用 arbitrary 库进行结构感知模糊测试,请参阅 fuzz-harness-writing 技术技能。

结构感知模糊测试

cargo-fuzz 集成了 arbitrary 库用于结构感知模糊测试:

// 在你的库 crate 中
use arbitrary::Arbitrary;

#[derive(Debug, Arbitrary)]
pub struct Name {
    data: String
}
// 在你的模糊测试目标中
#![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)

如果你的项目不使用不安全 Rust,禁用消毒器以获得 2 倍性能提升:

cargo +nightly fuzz run --sanitizer none fuzz_target_1

检查你的项目是否使用不安全代码:

cargo install cargo-geiger
cargo geiger

重新执行测试用例

# 运行特定测试用例(例如,崩溃)
cargo +nightly fuzz run fuzz_target_1 fuzz/artifacts/fuzz_target_1/crash-<hash>

# 运行所有语料库条目而不进行模糊测试
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 模糊测试器初始化成功
带有堆栈跟踪的崩溃 发现错误,保存到 fuzz/artifacts/

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

消毒器集成

地址消毒器(ASan)

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

cargo +nightly fuzz run fuzz_target_1

禁用消毒器

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

cargo +nightly fuzz run --sanitizer none fuzz_target_1

性能影响: ASan 添加约 2 倍开销。禁用以提升模糊测试速度。

检查不安全代码

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

生成覆盖率报告

# 从语料库生成覆盖率数据
cargo +nightly fuzz coverage fuzz_target_1

创建覆盖率生成脚本:

cat <<'EOF' > ./generate_html
#!/bin/sh
if [ $# -lt 1 ]; then
    echo "错误:模糊测试目标的名称是必需的。"
    echo "用法:$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:

# 查看所有选项
cargo +nightly fuzz run fuzz_target_1 -- -help=1

# 设置每次运行超时
cargo +nightly fuzz run fuzz_target_1 -- -timeout=10

# 使用字典
cargo +nightly fuzz run fuzz_target_1 -- -dict=dict.dict

# 限制最大输入大小
cargo +nightly fuzz run fuzz_target_1 -- -max_len=1024

多核模糊测试

# 实验性分支支持(不推荐)
cargo +nightly fuzz run --jobs 1 fuzz_target_1

注意:多核模糊测试功能是实验性的,不推荐。对于并行模糊测试,考虑手动运行多个实例或使用 AFL++。

真实世界示例

示例:ogg 库

ogg 库 解析 Ogg 媒体容器文件。解析器是优秀的模糊测试目标,因为它们处理不可信数据。

# 克隆和初始化
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

故障排除

问题 原因 解决方案
“需要 nightly” 错误 使用稳定工具链 使用 cargo +nightly fuzz
模糊测试性能慢 对安全 Rust 启用 ASan 添加 --sanitizer none 标志
“找不到二进制文件” 没有库 crate 将代码从 main.rs 移动到 lib.rs
消毒器编译问题 错误的 nightly 版本 尝试不同的 nightly:rustup install nightly-2024-01-01
低覆盖率 缺少种子语料库 添加样本输入到 fuzz/corpus/fuzz_target_1/
魔法值未找到 没有字典 创建包含魔法值的字典文件

相关技能

技术技能

技能 使用场景
fuzz-harness-writing 使用 arbitrary 库进行结构感知模糊测试
address-sanitizer 理解 ASan 输出和配置
coverage-analysis 测量和改善模糊测试效果
fuzzing-corpus 构建和管理种子语料库
fuzzing-dictionaries 为格式感知模糊测试创建字典

相关模糊测试器

技能 何时考虑
libfuzzer 用类似工作流程模糊测试 C/C++ 代码
aflpp 多核模糊测试或非 Cargo Rust 项目
libafl 高级模糊测试研究或自定义模糊测试器开发

资源

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

arbitrary 库文档 Rust 类型自动推导的结构感知模糊测试指南。

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