AIDL fuzzing

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.

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 in Android.bp to define the fuzzer module. The cc_default module service_fuzzer_defaults has dependencies required for fuzzService.
  • 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.