Modules fuzz

Le fuzzing Rust est pris en charge via la caisse libfuzzer-sys , qui fournit des liaisons au moteur de fuzzing libFuzzer de LLVM. Pour plus d'informations, consultez le référentiel libfuzzer-sys ainsi que la page du projet LLVM libFuzzer .

Le module rust_fuzz produit un binaire fuzzer qui commence à fuzzer lors de son exécution (similaire aux modules cc_fuzz ). Comme le fuzzer exploite le moteur de fuzzing libFuzzer , un certain nombre d'arguments peuvent être nécessaires pour contrôler le fuzzing. Ceux-ci sont énumérés dans la documentation de libFuzzer .

Les modules rust_fuzz sont une extension des modules rust_binary et, en tant que tels, partagent les mêmes propriétés et considérations. De plus, ils implémentent bon nombre des mêmes propriétés et fonctionnalités que les modules cc_fuzz .

Lors de la construction de modules rust_fuzz , l'indicateur --cfg fuzzing est émis et peut être utilisé pour prendre en charge la compilation conditionnelle du code de la bibliothèque afin d'améliorer le fuzzing.

Écrire un fuzzer Rust de base

Vous pouvez définir un module fuzz dans un fichier de build Android.bp avec ce code :

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 fuzz-target 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 , dont l'appel entraîne une lecture hors limites. libFuzzer est un fuzzer guidé par la couverture, il converge donc rapidement vers la longueur problématique car il détermine que les 326 premiers B de données n'entraînent pas de nouveaux chemins d'exécution.

Localisez cet exemple, dans l'arborescence, dans tools/security/fuzzing/example_rust_fuzzer/ . Pour voir un exemple légèrement plus complexe d'un autre fuzzer (qui fuzze une dépendance rustlib ) dans l'arborescence, consultez le fichier Legacy_blob_fuzzer .

Pour obtenir des conseils sur la façon d'écrire des fuzzers Rust sensibles à la structure , consultez le livre Rust Fuzz , la documentation officielle du projet Rust Fuzz.