模糊测试模块

Rust 模糊测试通过 libfuzzer-sys crate 得到支持,此 crate 可提供与 LLVM libFuzzer 模糊引擎的绑定。如需了解详情,请参阅 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 B 数据未产生新的执行路径时,就会对有问题的长度快速进行收敛。

在树内的以下位置可找到此示例:tools/security/fuzzing/example_rust_fuzzer/。 如需查看树内另一个模糊测试工具(对 rustlib 依赖项进行模糊测试)的稍微复杂一些的示例,请参阅 legacy_blob_fuzzer

如需有关如何编写结构感知型 Rust 模糊测试工具的指导,请参阅 Rust 模糊测试项目的官方文档 Rust Fuzz Book