Le fuzzing Rust est pris en charge via le crate libfuzzer-sys
, qui fournit des liaisons au moteur de fuzzing libFuzzer de LLVM. Pour en savoir plus, consultez le dépôt libfuzzer-sys ainsi que la page du projet libFuzzer de LLVM.
Le module rust_fuzz
produit un binaire de fuzzing qui commence à générer des données aléatoires lorsqu'il est exécuté (comme les modules cc_fuzz
). Étant donné que le fuzzer exploite le moteur de fuzzing libFuzzer
, il peut nécessiter un certain nombre d'arguments pour le contrôler. Ils sont énumérés dans la documentation de libFuzzer.
Les modules rust_fuzz
sont une extension des modules rust_binary
et partagent donc les mêmes propriétés et considérations. De plus, ils implémentent un grand nombre des mêmes propriétés et fonctionnalités que les modules cc_fuzz
.
Lors de la création de modules rust_fuzz
, l'option --cfg fuzzing
est émise. Elle peut être utilisée pour prendre en charge la compilation conditionnelle du code de la bibliothèque afin d'améliorer le fuzzing.
Écrire un fuzzer Rust basique
Vous pouvez définir un module de fuzz dans un fichier de compilation Android.bp
à l'aide du code suivant :
rust_fuzz {
name: "example_rust_fuzzer",
srcs: ["fuzzer.rs"],
// Config for running the target on fuzzing infrastructure can be set under
// fuzz_config. This shares the same properties as cc_fuzz's fuzz_config.
fuzz_config: {
fuzz_on_haiku_device: true,
fuzz_on_haiku_host: false,
},
// Path to a corpus of sample inputs, optional. See https://llvm.org/docs/LibFuzzer.html#corpus
corpus: ["testdata/*"],
// Path to a dictionary of sample byte sequences, optional. See https://llvm.org/docs/LibFuzzer.html#dictionaries
dictionary: "example_rust_fuzzer.dict",
}
Le fichier fuzzer.rs
contient un fuzzer simple:
fn heap_oob() {
let xs = vec![0, 1, 2, 3];
let val = unsafe { *xs.as_ptr().offset(4) };
println!("Out-of-bounds heap value: {}", val);
}
fuzz_target!(|data: &[u8]| {
let magic_number = 327;
if data.len() == magic_number {
heap_oob();
}
});
Ici, fuzz_target!(|data: &[u8]| { /* fuzz using data here */ });
définit le point d'entrée de la cible à fuzz appelé par le moteur libFuzzer
. L'argument data
est une séquence d'octets fournie par le moteur libFuzzer
à manipuler en entrée pour fuzzer la fonction ciblée.
Dans cet exemple de fuzzer, seule la longueur des données est vérifiée pour déterminer s'il faut appeler la fonction heap_oob
, ce qui entraîne une lecture hors limites. libFuzzer
est un fuzzer orienté couverture. Il converge donc rapidement sur la longueur problématique, car il détermine que les 326 premiers octets de données n'entraînent pas de nouveaux chemins d'exécution.
Vous trouverez cet exemple dans le répertoire tools/security/fuzzing/example_rust_fuzzer/.
Pour afficher un exemple légèrement plus complexe d'un autre fuzzer (qui diffuse une dépendance de type rustlib
) dans l'arborescence, consultez l'élément legacy_blob_fuzzer.
Pour en savoir plus sur l'écriture de fuzzers compatibles avec la structure, consultez le livre Rust Fuzz, la documentation officielle du projet Rust Fuzz.