cargo-fuzz - Fuzzing Rust mit libFuzzer Cheatsheet
cargo-fuzz ist die Standard-Weise, Rust-Code zu fuzzen. Sie verdrahtet libFuzzer mit einem Cargo-nativen Workflow: schreibe ein Fuzz-Ziel als gewöhnliche Rust-Funktion, die willkürliche Bytes nimmt, führe cargo fuzz run aus, und Coverage-gesteuertes Fuzzing jagt nach Panics, Arithmetik-Überläufen und — in unsafe-Code — echter Speicherfehler. Safe Rust verhindert Memory-Korruption, aber es verhindert nicht Panics, Endlosschleifen oder Logik-Bugs, und jeder unsafe-Block oder C-Abhängigkeit reintroduziert die vollständige Klasse von Speicherproblemen.
Installation
| Schritt | Befehl |
|---|
| Installieren | cargo install cargo-fuzz |
| Nightly erforderlich | rustup install nightly (libFuzzer braucht Nightly) |
| Initialisieren | cargo fuzz init (in deiner Crate) |
| Überprüfung | cargo fuzz --version |
Erstelle ein Fuzz-Ziel
cargo fuzz init # erstellt fuzz/ Verzeichnis
cargo fuzz add parse_input # erstellt ein neues Ziel
// fuzz/fuzz_targets/parse_input.rs
#![no_main]
use libfuzzer_sys::fuzz_target;
fuzz_target!(|data: &[u8]| {
if let Ok(s) = std::str::from_utf8(data) {
let _ = my_crate::parse(s); // Panics hier werden Befunde
}
});
Ausführung
| Befehl | Beschreibung |
|---|
cargo fuzz run parse_input | Fuzz das Ziel |
cargo fuzz run parse_input -- -max_total_time=300 | Laufe 5 Minuten |
cargo fuzz run parse_input -j 8 | 8 parallele Jobs |
cargo fuzz list | Liste Ziele auf |
cargo fuzz build | Bauen ohne zu laufen |
Raw-Bytes verschwenden Zeit mit Inputs, die dein Parser sofort ablehnt. Die arbitrary-Crate baut stattdessen getypte Werte:
use arbitrary::Arbitrary;
#[derive(Arbitrary, Debug)]
struct Config { name: String, retries: u8, enabled: bool }
fuzz_target!(|cfg: Config| {
let _ = my_crate::apply_config(cfg);
});
| Vorteil | Warum |
|---|
| Gültig-geformte Inputs | Erreicht tiefere Logik |
| Getypte Ziele | Fuzz APIs, nicht nur Parser |
Debug Output | Lesbare Reproducer |
Sanitizer
| Sanitizer | Flag |
|---|
| AddressSanitizer (Standard) | -s address |
| LeakSanitizer | Inklusive ASan |
| MemorySanitizer | -s memory |
| ThreadSanitizer | -s thread |
| Keine (Schneller) | -s none |
# Fuzz Unsafe-FFI-Code mit ASan
cargo fuzz run ffi_target -s address
Corpus und Coverage
| Befehl | Zweck |
|---|
fuzz/corpus/<target>/ | Wo interessante Inputs sich ansammeln |
cargo fuzz cmin <target> | Minimiere den Corpus |
cargo fuzz tmin <target> <input> | Minimiere einen Crashing-Input |
cargo fuzz coverage <target> | Generiere Coverage-Daten |
| Seed Corpus | Füge gültige Beispiele zum Bootstrappen hinzu |
Das Säen des Corpus mit echten, gültigen Inputs ist die einzelne wirksamste Weise, Fuzzing schnell produktiv zu machen.
Crashes reproduzieren
# Crashes landen in fuzz/artifacts/<target>/
cargo fuzz run parse_input fuzz/artifacts/parse_input/crash-abc123
# Schrumpfe es zu einem minimalen Fall
cargo fuzz tmin parse_input fuzz/artifacts/parse_input/crash-abc123
Konvertiere den minimierten Input zu einem gewöhnlichen #[test], sodass der Bug behoben bleibt.
Was zu fuzzen in Rust
| Gutes Ziel | Warum |
|---|
| Parser / Deserializer | Nicht vertrauenswürdiger Input, komplexer Zustand |
unsafe Blöcke | Speichersicherheit tatsächlich im Risiko |
| FFI-Grenzen | C-Code hinter der Schnittstelle |
| Protokoll/State-Machines | Reihenfolge-Bugs |
| Komprimierung / Encoding | Klassisches Bug-Gebiet |
| Weniger nützlich | Warum |
|---|
| Reine Safe-Arithmetik | Panics sind normalerweise offensichtlich |
| Dünne Wrapper | Wenig Logik zum Erkunden |
cargo-fuzz vs andere Fuzzer
| Aspekt | cargo-fuzz | AFL++ (afl.rs) | LibAFL | honggfuzz-rs |
|---|
| Engine | libFuzzer | AFL++ | Custom | honggfuzz |
| Setup | Einfachste für Rust | Moderat | Baue dein eigenes | Einfach |
| Strukturierter Input | arbitrary | arbitrary | Custom Typen | arbitrary |
| Bestes für | Standard Rust Fuzzing | Persistent/Binary-Modi | Ungewöhnliche Ziele | Hardware-Rückmeldung |
Für Non-Rust-Ziele siehe AFL++ oder honggfuzz; für benutzerdefinierte Fuzzer siehe LibAFL.
Ressourcen