Moduły Fuzz

Testowanie automatyczne Rust jest obsługiwane za pomocą pakietu libfuzzer-sys, który zapewnia powiązania z mechanizmem testowania automatycznego libFuzzer LLVM. Więcej informacji znajdziesz w repozytorium libfuzzer-sys oraz na stronie projektu LLVM libFuzzer.

Moduł rust_fuzz generuje binarny fuzzer, który rozpoczyna fuzzing po uruchomieniu (podobnie jak moduły cc_fuzz). Ponieważ fuzzer korzysta z silnika fuzzingu libFuzzer, może używać wielu argumentów do sterowania fuzzingiem. Są one wymienione w dokumentacji libFuzzer.

Moduły rust_fuzz są rozszerzeniem modułów rust_binary, dlatego mają te same właściwości i rozwiązania. Poza tym implementują wiele tych samych właściwości co moduły cc_fuzz.

Podczas kompilowania modułów rust_fuzz generowany jest flaga --cfg fuzzing, która może służyć do obsługi kompilacji warunkowej kodu biblioteki w celu poprawy fuzzingu.

Tworzenie prostego fuzzera w Rust

Moduł Fuzz możesz zdefiniować w pliku kompilacji Android.bp za pomocą tego kodu:

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",
}

Plik fuzzer.rs zawiera prosty zamazywanie:

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();
    }
});

fuzz_target!(|data: &[u8]| { /* fuzz using data here */ }); określa w tym miejscu punkt wejścia typu Fuzz-target wywołany przez wyszukiwarkę libFuzzer. Argument data to sekwencja bajtów udostępniona przez silnik libFuzzer, którą można manipulować jako dane wejściowe, aby zmienić docelową funkcję.

W tym przykładzie fuzzer sprawdza tylko długość danych, aby określić, czy wywołać funkcję heap_oob, której wywołanie powoduje odczyt poza zakresem. libFuzzer to fuzzer kierowany przez pokrycie, który szybko zbliża się do problematycznej długości, ponieważ określa, że pierwsze 326 mld danych nie powoduje nowych ścieżek wykonania.

Wyszukaj ten przykład w drzewie pod adresem tools/security/fuzzing/example_rust_fuzzer/. Aby zobaczyć nieco bardziej złożony przykład innego fuzzera (który fuzzuje zależność rustlib w drzewie), użyj polecenia legacy_blob_fuzzer.

Wskazówki dotyczące tworzenia rozwiązań Rusta z rozpoznawaniem struktury znajdziesz w książce Rusta Fuzz, która jest oficjalną dokumentacją projektu Rust Fuzz.