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

Commit 94bf3033 authored by Pawan Wagh's avatar Pawan Wagh
Browse files

Adding tests for fuzzer corpus in binderRecordReplay

Expanding binderRecordReplay tests to test generated
fuzzer corpus from recorded transactions.

Test: atest binderRecordReplayTest
Bug: 278975837
Change-Id: I12f19fbeee22131b920c9b0ae5da51f2a14876ab
parent ee6bf58e
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -77,6 +77,8 @@ cc_test {
    static_libs: [
        "binderRecordReplayTestIface-cpp",
        "binderReadParcelIface-cpp",
        "libbinder_random_parcel_seeds",
        "libbinder_random_parcel",
    ],
    test_suites: ["general-tests"],
    require_root: true,
+85 −42
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
 */

#include <BnBinderRecordReplayTest.h>
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
#include <binder/Binder.h>
@@ -23,6 +24,11 @@
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/RecordedTransaction.h>

#include <fuzzbinder/libbinder_driver.h>
#include <fuzzer/FuzzedDataProvider.h>
#include <fuzzseeds/random_parcel_seeds.h>

#include <gtest/gtest.h>

#include <sys/prctl.h>
@@ -30,6 +36,7 @@
#include "parcelables/SingleDataParcelable.h"

using namespace android;
using android::generateSeedsFromRecording;
using android::binder::Status;
using android::binder::debug::RecordedTransaction;
using parcelables::SingleDataParcelable;
@@ -84,6 +91,44 @@ public:
    GENERATE_GETTER_SETTER(SingleDataParcelableArray, std::vector<SingleDataParcelable>);
};

std::vector<uint8_t> retrieveData(base::borrowed_fd fd) {
    struct stat fdStat;
    EXPECT_TRUE(fstat(fd.get(), &fdStat) != -1);
    EXPECT_TRUE(fdStat.st_size != 0);

    std::vector<uint8_t> buffer(fdStat.st_size);
    auto readResult = android::base::ReadFully(fd, buffer.data(), fdStat.st_size);
    EXPECT_TRUE(readResult != 0);
    return std::move(buffer);
}

void replayFuzzService(const sp<BpBinder>& binder, const RecordedTransaction& transaction) {
    base::unique_fd seedFd(open("/data/local/tmp/replayFuzzService",
                                O_RDWR | O_CREAT | O_CLOEXEC | O_TRUNC, 0666));
    ASSERT_TRUE(seedFd.ok());

    // generate corpus from this transaction.
    generateSeedsFromRecording(seedFd, transaction);

    // Read the data which has been written to seed corpus
    ASSERT_EQ(0, lseek(seedFd.get(), 0, SEEK_SET));
    std::vector<uint8_t> seedData = retrieveData(seedFd);

    // use fuzzService to replay the corpus
    FuzzedDataProvider provider(seedData.data(), seedData.size());
    fuzzService(binder, std::move(provider));
}

void replayBinder(const sp<BpBinder>& binder, const RecordedTransaction& transaction) {
    // TODO: move logic to replay RecordedTransaction into RecordedTransaction
    Parcel data;
    data.setData(transaction.getDataParcel().data(), transaction.getDataParcel().dataSize());
    auto result = binder->transact(transaction.getCode(), data, nullptr, transaction.getFlags());

    // make sure recording does the thing we expect it to do
    EXPECT_EQ(OK, result);
}

class BinderRecordReplayTest : public ::testing::Test {
public:
    void SetUp() override {
@@ -98,6 +143,8 @@ public:
    template <typename T, typename U>
    void recordReplay(Status (IBinderRecordReplayTest::*set)(T), U recordedValue,
                      Status (IBinderRecordReplayTest::*get)(U*), U changedValue) {
        auto replayFunctions = {&replayBinder, &replayFuzzService};
        for (auto replayFunc : replayFunctions) {
            base::unique_fd fd(open("/data/local/tmp/binderRecordReplayTest.rec",
                                    O_RDWR | O_CREAT | O_CLOEXEC, 0666));
            ASSERT_TRUE(fd.ok());
@@ -128,19 +175,15 @@ public:
            std::optional<RecordedTransaction> transaction = RecordedTransaction::fromFile(fd);
            ASSERT_NE(transaction, std::nullopt);

        // TODO: move logic to replay RecordedTransaction into RecordedTransaction
        Parcel data;
        data.setData(transaction->getDataParcel().data(), transaction->getDataParcel().dataSize());
        auto result =
                mBpBinder->transact(transaction->getCode(), data, nullptr, transaction->getFlags());

        // make sure recording does the thing we expect it to do
        EXPECT_EQ(OK, result);
            const RecordedTransaction& recordedTransaction = *transaction;
            // call replay function with recorded transaction
            (*replayFunc)(mBpBinder, recordedTransaction);

            status = (*mInterface.*get)(&output);
            EXPECT_TRUE(status.isOk());
            EXPECT_EQ(output, recordedValue);
        }
    }

private:
    sp<BpBinder> mBpBinder;
+1 −1
Original line number Diff line number Diff line
@@ -43,5 +43,5 @@ template <typename T>
void writeReversedBuffer(std::vector<std::byte>& integralBuffer, T val);
} // namespace impl
void generateSeedsFromRecording(base::borrowed_fd fd,
                                binder::debug::RecordedTransaction&& transaction);
                                const binder::debug::RecordedTransaction& transaction);
} // namespace android
+1 −1
Original line number Diff line number Diff line
@@ -65,7 +65,7 @@ void writeReversedBuffer(std::vector<uint8_t>& integralBuffer, T val) {
} // namespace impl

void generateSeedsFromRecording(base::borrowed_fd fd,
                                binder::debug::RecordedTransaction&& transaction) {
                                const binder::debug::RecordedTransaction& transaction) {
    // Write Reserved bytes for future use
    std::vector<uint8_t> reservedBytes(8);
    CHECK(WriteFully(fd, reservedBytes.data(), reservedBytes.size())) << fd.get();