cargo-fuzz
Rustプロジェクト向けの標準的なファジングツールで、Cargoと統合してlibFuzzerバックエンドによるファズテストを実行します。RustコードのバグやパニックをランダムなInputで自動的に発見したい場合に使用します。
description の原文を見る
> cargo-fuzz is the de facto fuzzing tool for Rust projects using Cargo. Use for fuzzing Rust code with libFuzzer backend.
SKILL.md 本文
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
# fuzz/fuzz_targets/fuzz_target_1.rs をハーネスで編集
cargo +nightly fuzz run fuzz_target_1
インストール
cargo-fuzz は nightly のみで利用可能な機能を使用するため、nightly Rust ツールチェーンが必要です。
前提条件
- rustup 経由でインストールされた Rust と Cargo
- Nightly ツールチェーン
Linux/macOS
# Nightly ツールチェーンをインストール
rustup install nightly
# cargo-fuzz をインストール
cargo install cargo-fuzz
確認
cargo +nightly --version
cargo fuzz --version
ハーネスの作成
プロジェクト構造
cargo-fuzz はコードがライブラリクレートとして構造化されているときに最適に機能します。バイナリプロジェクトがある場合は、main.rs を以下のように分割します:
src/main.rs # エントリーポイント(main 関数)
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);
});
ハーネスルール
| すること | してはいけないこと |
|---|---|
| コードをライブラリクレートとして構造化 | すべてを main.rs に保持 |
fuzz_target! マクロを使用 | カスタム main 関数を記述 |
Result::Err を優雅に処理 | 予想されるエラーでパニック |
| ハーネスを決定的に保つ | 乱数ジェネレーターを使用 |
参照: 詳細なハーネス作成テクニックと
arbitraryクレートを使用した構造認識ファジングについては、fuzz-harness-writing テクニックスキルを参照してください。
構造認識ファジング
cargo-fuzz は構造認識ファジング用に arbitrary クレートと統合されています:
// ライブラリクレート内
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)
プロジェクトが unsafe Rust を使用しない場合、サニタイザーを無効にして 2 倍のパフォーマンス向上を実現:
cargo +nightly fuzz run --sanitizer none fuzz_target_1
プロジェクトが unsafe コードを使用しているか確認:
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/
サニタイザー統合
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
カバレッジレポートの生成
# コーパスからカバレッジデータを生成
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 にオプションを渡します:
# すべてのオプションを表示
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 フラグを追加 |
| 「バイナリが見つからない」 | ライブラリクレートがない | コードを 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 のソースコード、イシュートラッカー、および例。
ライセンス: CC-BY-SA-4.0(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- trailofbits
- リポジトリ
- trailofbits/skills
- ライセンス
- CC-BY-SA-4.0
- 最終更新
- 不明
Source: https://github.com/trailofbits/skills / ライセンス: CC-BY-SA-4.0
関連スキル
doubt-driven-development
重要な判断はすべて、本番環境への展開前に新しい視点から対抗的レビューを実施します。速度より正確性が重要な場合、不慣れなコードを扱う場合、本番環境・セキュリティに関わるロジック・取り消し不可の操作など影響度が高い場合、または後でバグを修正するよりも今検証する方が効率的な場合に活用してください。
apprun-skills
TypeScriptを使用したAppRunアプリケーションのMVU設計に関する総合的なガイダンスが得られます。コンポーネントパターン、イベントハンドリング、状態管理(非同期ジェネレータを含む)、パラメータと保護機能を備えたルーティング・ナビゲーション、vistestを使用したテストに対応しています。AppRunコンポーネントの設計・レビュー、ルートの配線、状態フローの管理、AppRunテストの作成時に活用してください。
desloppify
コードベースのヘルスチェックと技術負債の追跡ツールです。コード品質、技術負債、デッドコード、大規模ファイル、ゴッドクラス、重複関数、コードスメル、命名規則の問題、インポートサイクル、結合度の問題についてユーザーが質問した場合に使用してください。また、ヘルススコアの確認、次の改善項目の提案、クリーンアップ計画の作成をリクエストされた際にも対応します。29言語に対応しています。
debugging-and-error-recovery
テストが失敗したり、ビルドが壊れたり、動作が期待と異なったり、予期しないエラーが発生したりした場合に、体系的な根本原因デバッグをガイドします。推測ではなく、根本原因を見つけて修正するための体系的なアプローチが必要な場合に使用してください。
test-driven-development
テスト駆動開発により実装を進めます。ロジックの実装、バグの修正、動作の変更など、あらゆる場面で活用できます。コードが正常に動作することを証明する必要がある場合、バグ報告を受けた場合、既存機能を修正する予定がある場合に使用してください。
incremental-implementation
変更を段階的に実施します。複数のファイルに影響する機能や変更を実装する場合に使用してください。大量のコードを一度に書こうとしている場合や、タスクが一度では完結できないほど大きい場合に活用します。