cargo-fuzz について
cargo-fuzzは、Cargoを使うRustプロジェクト向けのlibFuzzerベースのファジング用CLIです。必要なビルドフラグを設定し、サニタイザー連携やカバレッジ確認も行えます。
主な機能
- 01libFuzzerによるファジング
- 02Cargoコマンドでのターゲット初期化
- 03AddressSanitizer連携
- 04arbitraryによる構造化入力
- 05カバレッジデータとレポートの生成
活用シーン
- 01Rustライブラリの任意入力処理のテスト
- 02パーサーなど入力処理コードのファジング
- 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-fuzz は、Cargo を使用する Rust プロジェクトのファジングにおけるデファクトスタンダードです。バックエンドとして libFuzzer を使用し、AddressSanitizer などのサニタイザーのサポートを含め、Rust プロジェクトに関連するコンパイルフラグを自動的に有効にする便利な Cargo サブコマンドを提供します。
使用する場面
cargo-fuzz は現在、Cargo を使用する Rust プロジェクト向けの主要かつ最も成熟したファジングソリューションです。
| ファザー | 最適な用途 | 複雑さ |
|---|---|---|
| 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
ハーネスの作成
プロジェクト構成
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
ハーネスの構造
#![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);
});
ハーネスのルール
| 推奨事項 | 避けること |
|---|---|
| コードをライブラリクレートとして構成する | すべてを main.rs に置く |
fuzz_target! マクロを使用する | カスタムの main 関数を書く |
Result::Err を適切に処理する | 想定されるエラーでパニックする |
| ハーネスの決定性を保つ | 乱数生成器を使用する |
関連項目: ハーネス作成の手法と、
arbitraryクレートを使った構造を考慮するファジングについて詳しくは、 fuzz-harness-writing 技術スキルを参照してください。
構造を考慮するファジング
cargo-fuzz は、構造を考慮するファジングのために arbitrary クレートと統合されています:
// 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 | ファザーの初期化に成功 |
| スタックトレース付きのクラッシュ | バグを検出。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 クレート
ogg クレート は、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」 | ライブラリクレートがない | コードを 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 のソースコード、課題トラッカー、サンプルを確認できます。