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

Commit fb4f247c authored by Steven Moreland's avatar Steven Moreland
Browse files

binder_parcel_fuzzer: instrs w/ FuzzedDataProvider

Use FuzzedDataProvider to process instructions to various functions.
Before, we had one byte of data to go with each function. This makes
more efficient use of input data when we don't need that extra
information, and in other cases, it gives us options to
do more complicated things with more than a byte of data. As a result,
this test now covers more state space.

Bug: 202528015
Test: binder_parcel_fuzzer
Change-Id: I5942ce78631f7f4fe1e401b6c50210747f9c80a4
parent 97c1356a
Loading
Loading
Loading
Loading
+39 −34
Original line number Diff line number Diff line
@@ -74,7 +74,7 @@ struct BigStruct {
};

#define PARCEL_READ_WITH_STATUS(T, FUN)                                  \
    [] (const ::android::Parcel& p, uint8_t /*data*/) {\
    [](const ::android::Parcel& p, FuzzedDataProvider& /*provider*/) {   \
        FUZZ_LOG() << "about to read " #T " using " #FUN " with status"; \
        T t{};                                                           \
        status_t status = p.FUN(&t);                                     \
@@ -82,7 +82,7 @@ struct BigStruct {
    }

#define PARCEL_READ_NO_STATUS(T, FUN)                                       \
    [] (const ::android::Parcel& p, uint8_t /*data*/) {\
    [](const ::android::Parcel& p, FuzzedDataProvider& /*provider*/) {      \
        FUZZ_LOG() << "about to read " #T " using " #FUN " with no status"; \
        T t = p.FUN();                                                      \
        (void)t;                                                            \
@@ -102,7 +102,9 @@ std::vector<ParcelRead<::android::Parcel>> BINDER_PARCEL_READ_FUNCTIONS {
    PARCEL_READ_NO_STATUS(size_t, dataPosition),
    PARCEL_READ_NO_STATUS(size_t, dataCapacity),
    PARCEL_READ_NO_STATUS(::android::binder::Status, enforceNoDataAvail),
    [] (const ::android::Parcel& p, uint8_t pos) {
    [] (const ::android::Parcel& p, FuzzedDataProvider& provider) {
        // aborts on larger values
        size_t pos = provider.ConsumeIntegralInRange<size_t>(0, INT32_MAX);
        FUZZ_LOG() << "about to setDataPosition: " << pos;
        p.setDataPosition(pos);
        FUZZ_LOG() << "setDataPosition done";
@@ -111,13 +113,13 @@ std::vector<ParcelRead<::android::Parcel>> BINDER_PARCEL_READ_FUNCTIONS {
    PARCEL_READ_NO_STATUS(size_t, hasFileDescriptors),
    PARCEL_READ_NO_STATUS(std::vector<android::sp<android::IBinder>>, debugReadAllStrongBinders),
    PARCEL_READ_NO_STATUS(std::vector<int>, debugReadAllFileDescriptors),
    [] (const ::android::Parcel& p, uint8_t len) {
        std::string interface(len, 'a');
    [] (const ::android::Parcel& p, FuzzedDataProvider& provider) {
        std::string interface = provider.ConsumeRandomLengthString();
        FUZZ_LOG() << "about to enforceInterface: " << interface;
        bool b = p.enforceInterface(::android::String16(interface.c_str()));
        FUZZ_LOG() << "enforced interface: " << b;
    },
    [] (const ::android::Parcel& p, uint8_t /*len*/) {
    [] (const ::android::Parcel& p, FuzzedDataProvider& /*provider*/) {
        FUZZ_LOG() << "about to checkInterface";
        android::sp<android::IBinder> aBinder = new android::BBinder();
        bool b = p.checkInterface(aBinder.get());
@@ -125,13 +127,16 @@ std::vector<ParcelRead<::android::Parcel>> BINDER_PARCEL_READ_FUNCTIONS {
    },
    PARCEL_READ_NO_STATUS(size_t, objectsCount),
    PARCEL_READ_NO_STATUS(status_t, errorCheck),
    [] (const ::android::Parcel& p, uint8_t len) {
    [] (const ::android::Parcel& p, FuzzedDataProvider& provider) {
        // Read at least a bit. Unbounded allocation would OOM.
        size_t len = provider.ConsumeIntegralInRange<size_t>(0, 1024);
        FUZZ_LOG() << "about to read void*";
        std::vector<uint8_t> data(len);
        status_t status = p.read(data.data(), len);
        FUZZ_LOG() << "read status: " << status;
    },
    [] (const ::android::Parcel& p, uint8_t len) {
    [] (const ::android::Parcel& p, FuzzedDataProvider& provider) {
        size_t len = provider.ConsumeIntegral<size_t>();
        FUZZ_LOG() << "about to readInplace";
        const void* r = p.readInplace(len);
        FUZZ_LOG() << "readInplace done. pointer: " << r << " bytes: " << (r ? HexString(r, len) : "null");
@@ -149,13 +154,13 @@ std::vector<ParcelRead<::android::Parcel>> BINDER_PARCEL_READ_FUNCTIONS {
    PARCEL_READ_WITH_STATUS(std::string, readUtf8FromUtf16),
    PARCEL_READ_WITH_STATUS(std::unique_ptr<std::string>, readUtf8FromUtf16),
    PARCEL_READ_WITH_STATUS(std::optional<std::string>, readUtf8FromUtf16),
    [] (const ::android::Parcel& p, uint8_t /*data*/) {
    [] (const ::android::Parcel& p, FuzzedDataProvider& /*provider*/) {
        FUZZ_LOG() << "about to read c-str";
        const char* str = p.readCString();
        FUZZ_LOG() << "read c-str: " << (str ? str : "<empty string>");
    },
    PARCEL_READ_OPT_STATUS(android::String8, readString8),
    [] (const ::android::Parcel& p, uint8_t /*data*/) {
    [] (const ::android::Parcel& p, FuzzedDataProvider& /*provider*/) {
        FUZZ_LOG() << "about to readString8Inplace";
        size_t outLen = 0;
        const char* str = p.readString8Inplace(&outLen);
@@ -165,7 +170,7 @@ std::vector<ParcelRead<::android::Parcel>> BINDER_PARCEL_READ_FUNCTIONS {
    PARCEL_READ_OPT_STATUS(android::String16, readString16),
    PARCEL_READ_WITH_STATUS(std::unique_ptr<android::String16>, readString16),
    PARCEL_READ_WITH_STATUS(std::optional<android::String16>, readString16),
    [] (const ::android::Parcel& p, uint8_t /*data*/) {
    [] (const ::android::Parcel& p, FuzzedDataProvider& /*provider*/) {
        FUZZ_LOG() << "about to readString16Inplace";
        size_t outLen = 0;
        const char16_t* str = p.readString16Inplace(&outLen);
@@ -263,13 +268,13 @@ std::vector<ParcelRead<::android::Parcel>> BINDER_PARCEL_READ_FUNCTIONS {
    PARCEL_READ_WITH_STATUS(std::optional<std::array<std::array<std::optional<ExampleParcelable> COMMA 3> COMMA 4>>, readFixedArray),
#undef COMMA

    [] (const android::Parcel& p, uint8_t /*len*/) {
    [] (const ::android::Parcel& p, FuzzedDataProvider& /*provider*/) {
        FUZZ_LOG() << "about to read flattenable";
        ExampleFlattenable f;
        status_t status = p.read(f);
        FUZZ_LOG() << "read flattenable: " << status;
    },
    [] (const android::Parcel& p, uint8_t /*len*/) {
    [] (const ::android::Parcel& p, FuzzedDataProvider& /*provider*/) {
        FUZZ_LOG() << "about to read lite flattenable";
        ExampleLightFlattenable f;
        status_t status = p.read(f);
@@ -284,7 +289,7 @@ std::vector<ParcelRead<::android::Parcel>> BINDER_PARCEL_READ_FUNCTIONS {
    PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<BigStruct>>, resizeOutVector),

    PARCEL_READ_NO_STATUS(int32_t, readExceptionCode),
    [] (const android::Parcel& p, uint8_t /*len*/) {
    [] (const ::android::Parcel& p, FuzzedDataProvider& /*provider*/) {
        FUZZ_LOG() << "about to readNativeHandle";
        native_handle_t* t = p.readNativeHandle();
        FUZZ_LOG() << "readNativeHandle: " << t;
@@ -303,15 +308,16 @@ std::vector<ParcelRead<::android::Parcel>> BINDER_PARCEL_READ_FUNCTIONS {
    PARCEL_READ_WITH_STATUS(std::optional<std::vector<android::base::unique_fd>>, readUniqueFileDescriptorVector),
    PARCEL_READ_WITH_STATUS(std::vector<android::base::unique_fd>, readUniqueFileDescriptorVector),

    [] (const android::Parcel& p, uint8_t len) {
    [] (const ::android::Parcel& p, FuzzedDataProvider& provider) {
        size_t len = provider.ConsumeIntegral<size_t>();
        FUZZ_LOG() << "about to readBlob";
        ::android::Parcel::ReadableBlob blob;
        status_t status = p.readBlob(len, &blob);
        FUZZ_LOG() << "readBlob status: " << status;
    },
    [] (const android::Parcel& p, uint8_t options) {
    [] (const ::android::Parcel& p, FuzzedDataProvider& provider) {
        FUZZ_LOG() << "about to readObject";
        bool nullMetaData = options & 0x1;
        bool nullMetaData = provider.ConsumeBool();
        const void* obj = static_cast<const void*>(p.readObject(nullMetaData));
        FUZZ_LOG() << "readObject: " << obj;
    },
@@ -319,20 +325,19 @@ std::vector<ParcelRead<::android::Parcel>> BINDER_PARCEL_READ_FUNCTIONS {
    PARCEL_READ_NO_STATUS(size_t, getOpenAshmemSize),

    // additional parcelable objects defined in libbinder
    [] (const ::android::Parcel& p, uint8_t data) {
    [] (const ::android::Parcel& p, FuzzedDataProvider& provider) {
        using ::android::os::ParcelableHolder;
        using ::android::Parcelable;
        FUZZ_LOG() << "about to read ParcelableHolder using readParcelable with status";
        Parcelable::Stability stability = Parcelable::Stability::STABILITY_LOCAL;
        if ( (data & 1) == 1 ) {
            stability = Parcelable::Stability::STABILITY_VINTF;
        }
        Parcelable::Stability stability = provider.ConsumeBool()
            ? Parcelable::Stability::STABILITY_LOCAL
            : Parcelable::Stability::STABILITY_VINTF;
        ParcelableHolder t = ParcelableHolder(stability);
        status_t status = p.readParcelable(&t);
        FUZZ_LOG() << "ParcelableHolder status: " << status;
    },
    PARCEL_READ_WITH_STATUS(android::os::PersistableBundle, readParcelable),
    [] (const ::android::Parcel& p, uint8_t /* data */) {
    [] (const ::android::Parcel& p, FuzzedDataProvider& /*provider*/) {
        FUZZ_LOG() << "about to call hasFileDescriptorsInRange() with status";
        size_t offset = p.readUint32();
        size_t length = p.readUint32();
@@ -340,7 +345,7 @@ std::vector<ParcelRead<::android::Parcel>> BINDER_PARCEL_READ_FUNCTIONS {
        status_t status = p.hasFileDescriptorsInRange(offset, length, &result);
        FUZZ_LOG() << " status: " << status  << " result: " << result;
    },
    [] (const ::android::Parcel& p, uint8_t /* data */) {
    [] (const ::android::Parcel& p, FuzzedDataProvider& /*provider*/) {
        FUZZ_LOG() << "about to call compareDataInRange() with status";
        size_t thisOffset = p.readUint32();
        size_t otherOffset = p.readUint32();
+14 −9
Original line number Diff line number Diff line
@@ -70,7 +70,7 @@ binder_status_t ISomeInterface::readFromParcel(const AParcel* parcel,
}

#define PARCEL_READ(T, FUN)                                              \
    [](const NdkParcelAdapter& p, uint8_t /*data*/) {                    \
    [](const NdkParcelAdapter& p, FuzzedDataProvider& /*provider*/) {    \
        FUZZ_LOG() << "about to read " #T " using " #FUN " with status"; \
        T t{};                                                           \
        binder_status_t status = FUN(p.aParcel(), &t);                   \
@@ -80,32 +80,37 @@ binder_status_t ISomeInterface::readFromParcel(const AParcel* parcel,
// clang-format off
std::vector<ParcelRead<NdkParcelAdapter>> BINDER_NDK_PARCEL_READ_FUNCTIONS{
        // methods from binder_parcel.h
        [](const NdkParcelAdapter& p, uint8_t pos) {
        [](const NdkParcelAdapter& p, FuzzedDataProvider& provider) {
            // aborts on larger values
            size_t pos = provider.ConsumeIntegralInRange<size_t>(0, INT32_MAX);
            FUZZ_LOG() << "about to set data position to " << pos;
            binder_status_t status = AParcel_setDataPosition(p.aParcel(), pos);
            FUZZ_LOG() << "set data position: " << status;
        },
        [](const NdkParcelAdapter& p, uint8_t /*data*/) {
        [](const NdkParcelAdapter& p, FuzzedDataProvider& /*provider*/) {
            FUZZ_LOG() << "about to read status header";
            ndk::ScopedAStatus t;
            binder_status_t status = AParcel_readStatusHeader(p.aParcel(), t.getR());
            FUZZ_LOG() << "read status header: " << status;
        },
        [](const NdkParcelAdapter& p, uint8_t /*data*/) {
        [](const NdkParcelAdapter& p, FuzzedDataProvider& /*provider*/) {
            FUZZ_LOG() << "about to getDataSize the parcel";
            AParcel_getDataSize(p.aParcel());
            FUZZ_LOG() << "getDataSize done";
        },
        [](const NdkParcelAdapter& p, uint8_t data) {
        [](const NdkParcelAdapter& p, FuzzedDataProvider& provider) {
            FUZZ_LOG() << "about to read a ParcelableHolder";
            ndk::AParcelableHolder ph {(data % 2 == 1) ? ndk::STABILITY_LOCAL : ndk::STABILITY_VINTF};
            ndk::AParcelableHolder ph {provider.ConsumeBool() ? ndk::STABILITY_LOCAL : ndk::STABILITY_VINTF};
            binder_status_t status = AParcel_readParcelable(p.aParcel(), &ph);
            FUZZ_LOG() << "read the ParcelableHolder: " << status;
        },
        [](const NdkParcelAdapter& p, uint8_t data) {
            FUZZ_LOG() << "about to appendFrom";
        [](const NdkParcelAdapter& p, FuzzedDataProvider& provider) {
            size_t offset = provider.ConsumeIntegral<size_t>();
            size_t pos = provider.ConsumeIntegral<size_t>();
            FUZZ_LOG() << "about to appendFrom " << pos;
            // TODO: create random parcel
            AParcel* parcel = AParcel_create();
            binder_status_t status = AParcel_appendFrom(p.aParcel(), parcel, 0, data);
            binder_status_t status = AParcel_appendFrom(p.aParcel(), parcel, offset, pos);
            AParcel_delete(parcel);
            FUZZ_LOG() << "appendFrom: " << status;
        },
+32 −25
Original line number Diff line number Diff line
@@ -36,14 +36,14 @@ std::ostream& operator<<(std::ostream& os, const ::android::sp<::android::hardwa
    PARCEL_READ_NO_STATUS(T, FUN), PARCEL_READ_WITH_STATUS(T, FUN)

#define PARCEL_READ_NO_STATUS(T, FUN)                                            \
    [] (const ::android::hardware::Parcel& p, uint8_t /*data*/) {\
    [](const ::android::hardware::Parcel& p, FuzzedDataProvider& /*provider*/) { \
        FUZZ_LOG() << "about to read " #T " using " #FUN " with no status";      \
        T t = p.FUN();                                                           \
        FUZZ_LOG() << #T " value: " << t;                                        \
    }

#define PARCEL_READ_WITH_STATUS(T, FUN)                                          \
    [] (const ::android::hardware::Parcel& p, uint8_t /*data*/) {\
    [](const ::android::hardware::Parcel& p, FuzzedDataProvider& /*provider*/) { \
        FUZZ_LOG() << "about to read " #T " using " #FUN " with status";         \
        T t;                                                                     \
        status_t status = p.FUN(&t);                                             \
@@ -56,27 +56,30 @@ std::vector<ParcelRead<::android::hardware::Parcel>> HWBINDER_PARCEL_READ_FUNCTI
    PARCEL_READ_NO_STATUS(size_t, dataAvail),
    PARCEL_READ_NO_STATUS(size_t, dataPosition),
    PARCEL_READ_NO_STATUS(size_t, dataCapacity),
    [] (const ::android::hardware::Parcel& p, uint8_t pos) {
    [] (const ::android::hardware::Parcel& p, FuzzedDataProvider& provider) {
        // aborts on larger values
        size_t pos = provider.ConsumeIntegralInRange<size_t>(0, INT32_MAX);
        FUZZ_LOG() << "about to setDataPosition: " << pos;
        p.setDataPosition(pos);
        FUZZ_LOG() << "setDataPosition done";
    },
    [] (const ::android::hardware::Parcel& p, uint8_t length) {
    [] (const ::android::hardware::Parcel& p, FuzzedDataProvider& provider) {
        FUZZ_LOG() << "about to enforceInterface";
        std::string interfaceName(length, 'a');
        bool okay = p.enforceInterface(interfaceName.c_str());
        bool okay = p.enforceInterface(provider.ConsumeRandomLengthString().c_str());
        FUZZ_LOG() << "enforceInterface status: " << okay;
    },
    PARCEL_READ_NO_STATUS(size_t, objectsCount),
    [] (const ::android::hardware::Parcel& p, uint8_t length) {
    [] (const ::android::hardware::Parcel& p, FuzzedDataProvider& provider) {
        // Read at least a bit. Unbounded allocation would OOM.
        size_t length = provider.ConsumeIntegralInRange<size_t>(0, 1024);
        FUZZ_LOG() << "about to read";
        std::vector<uint8_t> data (length);
        status_t status = p.read(data.data(), length);
        FUZZ_LOG() << "read status: " << status << " data: " << HexString(data.data(), data.size());
    },
    [] (const ::android::hardware::Parcel& p, uint8_t length) {
    [] (const ::android::hardware::Parcel& p, FuzzedDataProvider& provider) {
        size_t length = provider.ConsumeIntegral<size_t>();
        FUZZ_LOG() << "about to read";
        std::vector<uint8_t> data (length);
        const void* inplace = p.readInplace(length);
        FUZZ_LOG() << "read status: " << (inplace ? HexString(inplace, length) : "null");
    },
@@ -91,14 +94,14 @@ std::vector<ParcelRead<::android::hardware::Parcel>> HWBINDER_PARCEL_READ_FUNCTI
    PARCEL_READ_OPT_STATUS(float, readFloat),
    PARCEL_READ_OPT_STATUS(double, readDouble),
    PARCEL_READ_OPT_STATUS(bool, readBool),
    [] (const ::android::hardware::Parcel& p, uint8_t /*data*/) {
    [] (const ::android::hardware::Parcel& p, FuzzedDataProvider& /*provider*/) {
        FUZZ_LOG() << "about to readCString";
        const char* str = p.readCString();
        FUZZ_LOG() << "readCString " << (str ? str : "<null>");
    },
    PARCEL_READ_OPT_STATUS(::android::String16, readString16),
    PARCEL_READ_WITH_STATUS(std::unique_ptr<::android::String16>, readString16),
    [] (const ::android::hardware::Parcel& p, uint8_t /*data*/) {
    [] (const ::android::hardware::Parcel& p, FuzzedDataProvider& /*provider*/) {
        FUZZ_LOG() << "about to readString16Inplace";
        size_t outSize = 0;
        const char16_t* str = p.readString16Inplace(&outSize);
@@ -106,7 +109,8 @@ std::vector<ParcelRead<::android::hardware::Parcel>> HWBINDER_PARCEL_READ_FUNCTI
    },
    PARCEL_READ_OPT_STATUS(::android::sp<::android::hardware::IBinder>, readStrongBinder),
    PARCEL_READ_WITH_STATUS(::android::sp<::android::hardware::IBinder>, readNullableStrongBinder),
    [] (const ::android::hardware::Parcel& p, uint8_t size) {
    [] (const ::android::hardware::Parcel& p, FuzzedDataProvider& provider) {
        size_t size = provider.ConsumeIntegral<size_t>();
        FUZZ_LOG() << "about to readBuffer";
        size_t handle = 0;
        const void* data = nullptr;
@@ -116,7 +120,8 @@ std::vector<ParcelRead<::android::hardware::Parcel>> HWBINDER_PARCEL_READ_FUNCTI
        // should be null since we don't create any IPC objects
        CHECK(data == nullptr) << data;
    },
    [] (const ::android::hardware::Parcel& p, uint8_t size) {
    [] (const ::android::hardware::Parcel& p, FuzzedDataProvider& provider) {
        size_t size = provider.ConsumeIntegral<size_t>();
        FUZZ_LOG() << "about to readNullableBuffer";
        size_t handle = 0;
        const void* data = nullptr;
@@ -126,7 +131,8 @@ std::vector<ParcelRead<::android::hardware::Parcel>> HWBINDER_PARCEL_READ_FUNCTI
        // should be null since we don't create any IPC objects
        CHECK(data == nullptr) << data;
    },
    [] (const ::android::hardware::Parcel& p, uint8_t size) {
    [] (const ::android::hardware::Parcel& p, FuzzedDataProvider& provider) {
        size_t size = provider.ConsumeIntegral<size_t>();
        FUZZ_LOG() << "about to readEmbeddedBuffer";
        size_t handle = 0;
        size_t parent_buffer_handle = 0;
@@ -138,7 +144,8 @@ std::vector<ParcelRead<::android::hardware::Parcel>> HWBINDER_PARCEL_READ_FUNCTI
        // should be null since we don't create any IPC objects
        CHECK(data == nullptr) << data;
    },
    [] (const ::android::hardware::Parcel& p, uint8_t size) {
    [] (const ::android::hardware::Parcel& p, FuzzedDataProvider& provider) {
        size_t size = provider.ConsumeIntegral<size_t>();
        FUZZ_LOG() << "about to readNullableEmbeddedBuffer";
        size_t handle = 0;
        size_t parent_buffer_handle = 0;
@@ -150,7 +157,7 @@ std::vector<ParcelRead<::android::hardware::Parcel>> HWBINDER_PARCEL_READ_FUNCTI
        // should be null since we don't create any IPC objects
        CHECK(data == nullptr) << data;
    },
    [] (const ::android::hardware::Parcel& p, uint8_t /*data*/) {
    [] (const ::android::hardware::Parcel& p, FuzzedDataProvider& /*provider*/) {
        FUZZ_LOG() << "about to readNativeHandleNoDup";
        const native_handle_t* handle = nullptr;
        status_t status = p.readNativeHandleNoDup(&handle);
+6 −11
Original line number Diff line number Diff line
@@ -83,19 +83,14 @@ void doReadFuzz(const char* backend, const std::vector<ParcelRead<P>>& reads,
    FUZZ_LOG() << "input: " << HexString(p.data(), p.dataSize());
    FUZZ_LOG() << "instructions: " << HexString(instructions.data(), instructions.size());

    for (size_t i = 0; i + 1 < instructions.size(); i += 2) {
        uint8_t a = instructions[i];
        uint8_t readIdx = a % reads.size();
    FuzzedDataProvider instructionsProvider(instructions.data(), instructions.size());
    while (instructionsProvider.remaining_bytes() > 0) {
        uint8_t idx = instructionsProvider.ConsumeIntegralInRange<uint8_t>(0, reads.size() - 1);

        uint8_t b = instructions[i + 1];
        FUZZ_LOG() << "Instruction " << idx << " avail: " << p.dataAvail()
                   << " pos: " << p.dataPosition() << " cap: " << p.dataCapacity();

        FUZZ_LOG() << "Instruction: " << (i / 2) + 1 << "/" << instructions.size() / 2
                   << " cmd: " << static_cast<size_t>(a) << " (" << static_cast<size_t>(readIdx)
                   << ") arg: " << static_cast<size_t>(b) << " size: " << p.dataSize()
                   << " avail: " << p.dataAvail() << " pos: " << p.dataPosition()
                   << " cap: " << p.dataCapacity();

        reads[readIdx](p, b);
        reads[idx](p, instructionsProvider);
    }
}

+5 −1
Original line number Diff line number Diff line
@@ -15,5 +15,9 @@
 */
#pragma once

#include <fuzzer/FuzzedDataProvider.h>

#include <functional>

template <typename P>
using ParcelRead = std::function<void(const P& p, uint8_t data)>;
using ParcelRead = std::function<void(const P& p, FuzzedDataProvider& provider)>;