Fuzzer 通过导入或调用生成的桩代码,充当远程服务的客户端。
使用 C++ API
#include <fuzzbinder/libbinder_ndk_driver.h>
#include <fuzzer/FuzzedDataProvider.h>
#include <android-base/logging.h>
#include <android/binder_interface_utils.h>
using android::fuzzService;
using ndk::SharedRefBase;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
auto binder = ndk::SharedRefBase::make<MyService>(...);
fuzzService(binder->asBinder().get(), FuzzedDataProvider(data, size));
return 0;
}
使用 Rust API
#![allow(missing_docs)]
#![no_main]
#[macro_use]
extern crate libfuzzer_sys;
use binder::{self, BinderFeatures, Interface};
use binder_random_parcel_rs::fuzz_service;
fuzz_target!(|data: &[u8]| {
let service = BnTestService::new_binder(MyService, BinderFeatures::default());
fuzz_service(&mut service.as_binder(), data);
});
Fuzz AIDL 服务的框架
如上面的示例所示,fuzzService 在 fuzzer 中被调用,并接受 IBinder (Service) 和 dataProvider 作为输入参数。它首先使用数据提供程序初始化一个随机 Parcel 对象,然后通过使用输入 parcel 调用远程服务上的 transact 方法,最后将回复获取到回复 parcel 中。
构建并运行 fuzzer
Fuzzer 默认情况下使用覆盖率构建。
建议使用以下 sanitizers 来发现内存问题。 hwaddress
sanitizers 仅在 arm
架构上运行
SANITIZE_HOST=address SANITIZE_TARGET=hwaddress
当使用 libFuzzer
运行 fuzzer 时,可以在 Android.bp
文件中指定语料库(一个目录),您可以将此目录传递给 fuzzer。一些 fuzzer 还在其 Android.bp
文件中指定 dictionary:
,您可以使用 -dict path/to/dict
将其传递给 libFuzzer。有关更多选项,请参阅 官方 libFuzzer 文档。
要在设备上运行 fuzzer,请运行 adb sync data
,然后运行 adb shell data/fuzz/arch/name/name
。要在主机上运行 fuzzer,请运行 $ANDROID_HOST_OUT/fuzz/arch/name/name
。
为新的或现有服务推荐 fuzzer
构建系统检查每个 AOSP binder 服务是否在 service fuzzer bindings 中都有一个 fuzzer 条目。Fuzzer 绑定测试检查 service_contexts
中的每个服务是否都有一个 fuzzer。如果未为新服务找到 fuzzer 或异常,则会出现构建错误。
可以通过添加以下内容来编写自动 C++ 服务 fuzzer(尚不支持 Java 和 Rust fuzzer)
- 在
Android.bp
中添加一个cc_fuzz
条目以定义 fuzzer 模块。cc_default
模块service_fuzzer_defaults
具有fuzzService
所需的依赖项。 - 服务特定的依赖项应作为库或源文件添加。
- 一个构建您的服务并调用
fuzzService
的主文件
有关使用 cc_fuzz
的详细说明,请参阅 使用 libFuzzer 进行 Fuzzing 文档。要解决构建错误,请使用新的服务和 fuzzer 名称更新绑定。对于 Java 或 Rust 服务,fuzzer 列表可以为空。