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
| Étape | Commande |
|---|
| Installer | cargo install cargo-fuzz |
| Nightly requise | rustup install nightly (libFuzzer a besoin de nightly) |
| Initialiser | cargo fuzz init (dans votre crate) |
| Vérifier | cargo 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
| Commande | Description |
|---|
cargo fuzz run parse_input | Tester la cible |
cargo fuzz run parse_input -- -max_total_time=300 | Exécuter pendant 5 minutes |
cargo fuzz run parse_input -j 8 | 8 travaux parallèles |
cargo fuzz list | Lister les cibles |
cargo fuzz build | Construire 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éfice | Pourquoi |
|---|
| Entrées de forme valide | Atteint la logique plus profonde |
| Cibles typées | Tester les API, pas seulement les analyseurs |
Sortie Debug | Reproducteurs lisibles |
Sanitizers
| Sanitizer | Drapeau |
|---|
| AddressSanitizer (par défaut) | -s address |
| LeakSanitizer | inclus 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
| Commande | Objectif |
|---|
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 semence | Ajouter 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 cible | Pourquoi |
|---|
| Analyseurs / désérieurs | Entrée non fiable, état complexe |
Blocs unsafe | Vraiment en risque de sécurité mémoire |
| Frontières FFI | Code C derrière l’interface |
| Protocole/machines d’état | Bugs d’ordonnancement |
| Compression / encodage | Territoire classique des bugs |
| Moins utile | Pourquoi |
|---|
| Arithmétique pure sûre | Les paniques sont généralement évidentes |
| Wrappers minces | Peu de logique à explorer |
cargo-fuzz vs Autres Testeurs
| Aspect | cargo-fuzz | AFL++ (afl.rs) | LibAFL | honggfuzz-rs |
|---|
| Engine | libFuzzer | AFL++ | Personnalisé | honggfuzz |
| Configuration | La plus facile pour Rust | Modéré | Construire votre propre | Facile |
| Entrée structurée | arbitrary | arbitrary | Types personnalisés | arbitrary |
| Meilleur pour | Fuzzing Rust standard | Modes persistant/binaire | Cibles inhabituelles | Retour matériel |
Pour les cibles non-Rust, voir AFL++ ou honggfuzz ; pour les testeurs personnalisés, voir LibAFL.
Ressources