ファズ モジュール

Rust ファジングは、LLVM の libFuzzer ファジング エンジンへのバインディングを提供する libfuzzer-sys クレートを通じてサポートされています。詳しくは、libfuzzer-sys リポジトリと LLVM libFuzzer プロジェクトのページをご覧ください。

rust_fuzz モジュールは、実行時にファジングを開始するファザー バイナリを生成します(cc_fuzz モジュールと同様)。ファザーは libFuzzer ファジング エンジンを利用しているため、ファジング制御のために多数の引数を取ることができます。これらは libFuzzer ドキュメントに記載されています。

rust_fuzz モジュールは、rust_binary モジュールの拡張であるため、同じプロパティと考慮事項を共有します。また、cc_fuzz モジュールと同じプロパティと機能の多くが実装されています。

基本的な 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 をご覧ください。