Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 391ead5b authored by Pawan Wagh's avatar Pawan Wagh
Browse files

Adding binder2corpus to generate fuzzer corpus

Tool will take recording file generated from
record_binder and convert each transaction as seed corpus
for fuzzService.

Usage:
binder2corpus <recording_file> <dest_dir>

Test: m binder2corpus && $ANDROID_HOST_OUT/bin/binder2corpus recordings/manager service_manager_corpus/
Bug: 278975837
Change-Id: If6b2560113b0da1d3458a775a36a677570221fac
parent e88ec57f
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -129,3 +129,18 @@ cc_library {
    ],
    export_include_dirs: ["include_random_parcel_seeds"],
}

cc_binary_host {
    name: "binder2corpus",
    static_libs: [
        "libbinder_random_parcel_seeds",
    ],
    srcs: [
        "binder2corpus/binder2corpus.cpp",
    ],
    shared_libs: [
        "libbase",
        "libbinder",
        "libutils",
    ],
}
+31 −0
Original line number Diff line number Diff line
# binder2corpus

This tool converts recordings generated by record_binder tool to fuzzer seeds for fuzzService.

# Steps to add corpus:

## Start recording the service binder
ex. record_binder start manager

## Run test on device or keep device idle
ex. atest servicemanager_test

## Stop the recording
record_binder stop manager

## Pull the recording on host
Recordings are present on device at /data/local/recordings/<service_name>. Use adb pull.
Use inspect command of record_binder to check if there are some transactions captured.
ex. record_binder inspect manager

## run corpus generator tool
binder2corpus <recording_path> <dir_to_write_corpus>

## Build fuzzer and sync data directory
ex. m servicemanager_fuzzer && adb sync data

## Push corpus on device
ex. adb push servicemanager_fuzzer_corpus/ /data/fuzz/x86_64/servicemanager_fuzzer/

## Run fuzzer with corpus directory as argument
ex. adb shell /data/fuzz/x86_64/servicemanager_fuzzer/servicemanager_fuzzer /data/fuzz/x86_64/servicemanager_fuzzer/servicemanager_fuzzer_corpus
 No newline at end of file
+90 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
#include <binder/RecordedTransaction.h>

#include <fuzzseeds/random_parcel_seeds.h>

#include <sys/prctl.h>

using android::generateSeedsFromRecording;
using android::status_t;
using android::base::unique_fd;
using android::binder::debug::RecordedTransaction;

status_t generateCorpus(const char* recordingPath, const char* corpusDir) {
    unique_fd fd(open(recordingPath, O_RDONLY));
    if (!fd.ok()) {
        std::cerr << "Failed to open recording file at path " << recordingPath
                  << " with error: " << strerror(errno) << '\n';
        return android::BAD_VALUE;
    }

    if (auto res = mkdir(corpusDir, 0766); res != 0) {
        std::cerr
                << "Failed to create corpus directory at path. Delete directory if already exists: "
                << corpusDir << std::endl;
        return android::BAD_VALUE;
    }

    int transactionNumber = 0;
    while (auto transaction = RecordedTransaction::fromFile(fd)) {
        ++transactionNumber;
        std::string filePath = std::string(corpusDir) + std::string("transaction_") +
                std::to_string(transactionNumber);
        constexpr int openFlags = O_WRONLY | O_CREAT | O_BINARY | O_CLOEXEC;
        android::base::unique_fd corpusFd(open(filePath.c_str(), openFlags, 0666));
        if (!corpusFd.ok()) {
            std::cerr << "Failed to open fd. Path " << filePath
                      << " with error: " << strerror(errno) << std::endl;
            return android::UNKNOWN_ERROR;
        }
        generateSeedsFromRecording(corpusFd, transaction.value());
    }

    if (transactionNumber == 0) {
        std::cerr << "No valid transaction has been found in recording file:  " << recordingPath
                  << std::endl;
        return android::BAD_VALUE;
    }

    return android::NO_ERROR;
}

void printHelp(const char* toolName) {
    std::cout << "Usage: \n\n"
              << toolName
              << " <recording_path> <destination_directory> \n\n*Use "
                 "record_binder tool for recording binder transactions."
              << std::endl;
}

int main(int argc, char** argv) {
    if (argc != 3) {
        printHelp(argv[0]);
        return 1;
    }
    const char* sourcePath = argv[1];
    const char* corpusDir = argv[2];
    if (android::NO_ERROR != generateCorpus(sourcePath, corpusDir)) {
        std::cerr << "Failed to generate fuzzer corpus." << std::endl;
        return 1;
    }
    return 0;
}