Rust ファジングは、LLVM の libFuzzer ファジング エンジンへのバインディングを提供する libfuzzer-sys
クレートを通じてサポートされています。詳しくは、libfuzzer-sys リポジトリと LLVM libFuzzer プロジェクトのページをご覧ください。
rust_fuzz
モジュールは、実行時にファジングを開始するファザー バイナリを生成します(cc_fuzz
モジュールと同様)。ファザーは libFuzzer
ファジング エンジンを利用しているため、ファジング制御のために多数の引数を取ることができます。これらは libFuzzer ドキュメントに記載されています。
rust_fuzz
モジュールは、rust_binary
モジュールの拡張であるため、同じプロパティと考慮事項を共有します。また、cc_fuzz
モジュールと同じプロパティと機能の多くが実装されています。
rust_fuzz
モジュールをビルドする際に、--cfg fuzzing
フラグが発行されます。これを使用してライブラリ コードの条件つきコンパイルをサポートし、ファジングを向上させることができます。
基本的な Rust ファザーを作成する
次のコードを使用して、Android.bp
ビルドファイルでファズ モジュールを定義できます。
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",
}
fuzzer.rs
ファイルには、単純なファザーが含まれています。
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 */ });
は、libFuzzer
エンジンによって呼び出されるファズ ターゲット エントリ ポイントを定義します。data
引数は、libFuzzer
エンジンにより提供されるバイト シーケンスであり、ターゲット関数をファジングするための入力として扱われます。
このファザーの例では、データの長さのみがチェックされて heap_oob
関数を呼び出すかどうかが判断されますが、この関数を呼び出すと、境界外の読み取りが発生します。libFuzzer
はカバレッジに基づくファザーであるため、データの最初の 326 バイトから新しい実行パスが得られないと判断すると、問題となる長さにすばやく収束します。
この例はツリーの tools/security/fuzzing/example_rust_fuzzer/ にあります。
もう少し複雑な別のファザー(rustlib
依存関係をファジングする)の例をツリー内で確認するには、legacy_blob_fuzzer をご覧ください。
構造に対応する Rust ファザーの作成方法については、Rust Fuzz プロジェクトの公式ドキュメントである Rust Fuzz Book をご覧ください。