Testowanie automatyczne Rust jest obsługiwane za pomocą pakietu libfuzzer-sys
, który zapewnia powiązania z silnikiem testowania automatycznego libFuzzer w 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 kontrolowania fuzzingu. Są one wymienione w dokumentacji libFuzzer.
Moduł rust_fuzz
jest rozszerzeniem modułu rust_binary
, więc ma te same właściwości i wymagania. Ponadto implementują wiele takich samych właściwości i funkcji jak moduły cc_fuzz
.
Podczas kompilowania modułów rust_fuzz
generowany jest flaga --cfg fuzzing
, która może być używana do obsługi kompilacji warunkowej kodu biblioteki w celu poprawy fuzzingu.
Tworzenie prostego fuzzera w 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 fuzzer:
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 */ });
definiuje punkt wejścia do celu fuzzingu wywoływany przez mechanizm libFuzzer
. Argument data
to sekwencja bajtów udostępniana 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 zbiega się z problematycznym ciągiem znaków, ponieważ określa, że pierwsze 326 mld danych nie prowadzą do nowych ścieżek wykonania.
Znajdź ten przykład w drzewie w folderze 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 fuzzerów Rust z uwzględnieniem struktury znajdziesz w książce Rust Fuzz, czyli oficjalnej dokumentacji projektu Rust Fuzz.