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_fuzz
modułó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.