A caixa libfuzzer-sys
, que fornece
vinculações ao mecanismo de fuzzing libFuzzer do LLVM, também oferece suporte ao fuzzing do Rust. Para saber mais, consulte o repositório libfuzzer-sys
e a página do projeto libFuzzer do LLVM (links em inglês).
O módulo rust_fuzz
produz um binário fuzzer que inicia o fuzzing quando é
executado, de forma semelhante aos módulos cc_fuzz
. Como o fuzzer aproveita o mecanismo de fuzzing libFuzzer
,
ele pode usar vários argumentos para controlar o fuzzer. Eles estão
enumerados na documentação do libFuzzer (em inglês).
Os módulos rust_fuzz
são uma extensão dos módulos rust_binary
e, por isso, compartilham
as mesmas propriedades e considerações. Além disso, eles implementam muitas das
mesmas propriedades e funcionalidades que os módulos cc_fuzz
.
Ao criar módulos rust_fuzz
, a flag --cfg fuzzing
é emitida. Ela pode
ser usada para oferecer suporte à compilação condicional de código de biblioteca para melhorar o fuzzing.
Criar um fuzzer básico usando o Rust
Você pode definir um módulo fuzz em um arquivo de build Android.bp
com este código:
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",
}
O arquivo fuzzer.rs
contém um fuzzer simples:
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();
}
});
Aqui, o fuzz_target!(|data: &[u8]| { /* fuzz using data here */ });
define o
ponto de entrada de destino do fuzz chamado pelo mecanismo libFuzzer
. O argumento data
é
uma sequência de bytes fornecidos pelo mecanismo libFuzzer
a ser manipulado como entrada
para converter a função de destino.
Neste fuzzer de exemplo, apenas a quantidade de dados é verificada para determinar
se a função heap_oob
será chamada, o que resulta em uma
leitura fora dos limites. O libFuzzer
é um fuzzer guiado por cobertura. Portanto, ele converge rapidamente para o
tamanho problemático, porque determina que os primeiros 326 B de dados não
resultam em novos caminhos de execução.
Veja este exemplo, na árvore, em tools/security/fuzzing/example_rust_fuzzer/.
Para um exemplo um pouco mais complexo de outro fuzzer, que esmaece uma dependência
rustlib
na árvore, consulte o legacy_blob_fuzzer.
Para saber como programar fuzzers com reconhecimento da estrutura, consulte o livro Rust Fuzz, que é a documentação oficial para o projeto Rust Fuzz (links em inglês).