The fuzzer behaves as a client for the remote service by importing or invoking it through the generated stub:
Using 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;
}
Using 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);
});
Framework to fuzz AIDL services
As shown in the example above, fuzzService is called in the fuzzer and takes in an IBinder (Service) and dataProvider as input parameters. It first initializes a random Parcel object using the data provider and call the transact method on the remote service by using the input parcel, and finally get the reply into a reply parcel.
Build and run fuzzers
Fuzzers are built with coverage by default.
The following sanitizers are recommended to discover memory issues.
hwaddress
sanitizers only run on arm
architecture:
SANITIZE_HOST=address SANITIZE_TARGET=hwaddress
When running with libFuzzer
, a corpus, which is a directory, may be specified
in the Android.bp
file, and you can pass this directory to the fuzzer. Some
fuzzers also specify a dictionary:
in their Android.bp
file, and you can
pass this to libFuzzer with -dict path/to/dict
. For
more options, see the
official libFuzzer documentation.
To run fuzzers on device, run adb sync data
and then
adb shell data/fuzz/arch/name/name
.
To run fuzzers on host, run
$ANDROID_HOST_OUT/fuzz/arch/name/name
.
Recommend fuzzers for new or existing services
The build system checks whether every AOSP binder service has a fuzzer entry in
service fuzzer bindings.
The Fuzzer binding test checks that every service in service_contexts
has a
fuzzer. If a fuzzer or exception isn't found for a new service, there's a build
error.
An automatic C++ service fuzzer can be written by adding the following (Java and Rust fuzzers are not yet supported):
- A
cc_fuzz
entry inAndroid.bp
to define the fuzzer module. Thecc_default
moduleservice_fuzzer_defaults
has dependencies required forfuzzService
. - Service-specific dependencies should be added as a library or as sources.
- A main file that constructs your service and calls
fuzzService
For detailed instructions on using cc_fuzz
, see the
Fuzzing with libFuzzer
documentation. To resolve build error, update bindings with the new service and
fuzzer names. For Java or Rust services, the fuzzer list can be empty.