Moduł rozmywania

Testowanie fuzzingowe w Rust jest obsługiwane przez pakiet libfuzzer-sys, który zapewnia powiązania z silnikiem testowania fuzzingowego libFuzzer LLVM. Więcej informacji znajdziesz w repozytorium libfuzzer-sys oraz na stronie projektu LLVM libFuzzer.

Moduł rust_fuzz tworzy plik binarny narzędzia do testowania fuzzingowego, które rozpoczyna testowanie po uruchomieniu (podobnie jak moduły cc_fuzz). Fuzzer korzysta z libFuzzer silnika fuzzingu, dlatego może przyjmować wiele 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 wymagania. Wiele z nich ma takie same właściwości i funkcje jak moduły cc_fuzz.

Podczas tworzenia rust_fuzzmodułów--cfg fuzzing emitowana jest flaga, której można używać do obsługi kompilacji warunkowej kodu biblioteki w celu ulepszenia testowania fuzzingowego.

Pisanie podstawowego narzędzia do fuzzingu w języku Rust

Moduł fuzzingu 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 program do testowania:

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

Tutaj fuzz_target!(|data: &[u8]| { /* fuzz using data here */ }); określa punkt wejścia do testu fuzzingowego wywoływany przez silnik libFuzzer. Argument data to ciąg bajtów dostarczony przez silnik libFuzzer, który ma być manipulowany jako dane wejściowe do testowania funkcji docelowej.

W tym przykładzie narzędzia fuzzingowego sprawdzana jest tylko długość danych, aby określić, czy wywołać funkcję heap_oob, której wywołanie powoduje odczyt poza zakresem. libFuzzer to fuzzer oparty na pokryciu, więc szybko zbiega się do problematycznej długości, ponieważ stwierdza, że pierwsze 326 bajtów danych nie powoduje nowych ścieżek wykonania.

Ten przykład znajdziesz w repozytorium pod adresem tools/security/fuzzing/example_rust_fuzzer/. Nieco bardziej złożony przykład innego fuzzera (który testuje zależność) w drzewie znajdziesz w legacy_blob_fuzzer.rustlib

Wskazówki dotyczące pisania fuzzera Rust uwzględniającego strukturę znajdziesz w książce Rust Fuzz, czyli oficjalnej dokumentacji projektu Rust Fuzz.