Aller au contenu

cargo-fuzz - Fuzzing Rust avec libFuzzer

cargo-fuzz - Fuzzing Rust avec libFuzzer

cargo-fuzz est le moyen standard de tester Rust. Il câble libFuzzer avec un flux de travail natif Cargo : écrire une cible de fuzzing en tant que fonction Rust ordinaire prenant des octets arbitraires, exécuter cargo fuzz run, et le fuzzing guidé par couverture chasse les paniques, les débordements arithmétiques, et — dans le code unsafe — les vraies erreurs mémoire. Rust sûr prévient la corruption mémoire, mais ne prévient pas les paniques, les boucles infinies ou les bugs logiques, et tout bloc unsafe ou dépendance C réintroduit la classe complète des problèmes mémoire.

Installation

ÉtapeCommande
Installercargo install cargo-fuzz
Nightly requiserustup install nightly (libFuzzer a besoin de nightly)
Initialisercargo fuzz init (dans votre crate)
Vérifiercargo fuzz --version

Créer une Cible de Fuzzing

cargo fuzz init                 # crée le répertoire fuzz
cargo fuzz add parse_input      # crée une nouvelle cible
// 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);   // les paniques ici deviennent des constatations
    }
});

Exécution

CommandeDescription
cargo fuzz run parse_inputTester la cible
cargo fuzz run parse_input -- -max_total_time=300Exécuter pendant 5 minutes
cargo fuzz run parse_input -j 88 travaux parallèles
cargo fuzz listLister les cibles
cargo fuzz buildConstruire sans exécuter

Entrée Structurée avec Arbitrary

Les octets bruts gaspillent du temps sur les entrées que votre analyseur rejette immédiatement. La crate arbitrary construit plutôt des valeurs typées :

use arbitrary::Arbitrary;

#[derive(Arbitrary, Debug)]
struct Config { name: String, retries: u8, enabled: bool }

fuzz_target!(|cfg: Config| {
    let _ = my_crate::apply_config(cfg);
});
BénéficePourquoi
Entrées de forme valideAtteint la logique plus profonde
Cibles typéesTester les API, pas seulement les analyseurs
Sortie DebugReproducteurs lisibles

Sanitizers

SanitizerDrapeau
AddressSanitizer (par défaut)-s address
LeakSanitizerinclus avec ASan
MemorySanitizer-s memory
ThreadSanitizer-s thread
Aucun (plus rapide)-s none
# Tester le code FFI unsafe avec ASan
cargo fuzz run ffi_target -s address

Corpus et Couverture

CommandeObjectif
fuzz/corpus/<target>/Où les entrées intéressantes s’accumulent
cargo fuzz cmin <target>Minimiser le corpus
cargo fuzz tmin <target> <input>Minimiser une entrée plantante
cargo fuzz coverage <target>Générer les données de couverture
Corpus de semenceAjouter des exemples valides pour amorcer

L’ensemencement du corpus avec des entrées réelles et valides est le moyen unique le plus efficace de rendre le fuzzing productif rapidement.

Reproduction des Plantages

# Les plantages atterrissent dans fuzz/artifacts/<target>/
cargo fuzz run parse_input fuzz/artifacts/parse_input/crash-abc123

# Le réduire à un cas minimal
cargo fuzz tmin parse_input fuzz/artifacts/parse_input/crash-abc123

Convertir l’entrée minimisée en #[test] régulier pour que le bug reste corrigé.

Ce à Tester dans Rust

Bonne ciblePourquoi
Analyseurs / désérieursEntrée non fiable, état complexe
Blocs unsafeVraiment en risque de sécurité mémoire
Frontières FFICode C derrière l’interface
Protocole/machines d’étatBugs d’ordonnancement
Compression / encodageTerritoire classique des bugs
Moins utilePourquoi
Arithmétique pure sûreLes paniques sont généralement évidentes
Wrappers mincesPeu de logique à explorer

cargo-fuzz vs Autres Testeurs

Aspectcargo-fuzzAFL++ (afl.rs)LibAFLhonggfuzz-rs
EnginelibFuzzerAFL++Personnaliséhonggfuzz
ConfigurationLa plus facile pour RustModéréConstruire votre propreFacile
Entrée structuréearbitraryarbitraryTypes personnalisésarbitrary
Meilleur pourFuzzing Rust standardModes persistant/binaireCibles inhabituellesRetour matériel

Pour les cibles non-Rust, voir AFL++ ou honggfuzz ; pour les testeurs personnalisés, voir LibAFL.

Ressources