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

Commit 76b1815f authored by Pawan Wagh's avatar Pawan Wagh
Browse files

Replay recorded fds and binders in fuzzers

Save object offsets in RecordedTransaction and generate seed
corpus so that objects will be replaced by random binders and
random fds. Adding tests to replay fds and binders in
binderRecordReplayTests.

Test: m binderRecordReplayTest && adb sync && atest -c  binderRecordReplayTest
Bug: 299650657
Change-Id: Ib9e1827b31194d8ea85def5dd3089a98b207da25
parent aea65bc9
Loading
Loading
Loading
Loading
+47 −12
Original line number Diff line number Diff line
@@ -114,8 +114,8 @@ static_assert(PADDING8(8) == 0);

RecordedTransaction::RecordedTransaction(RecordedTransaction&& t) noexcept {
    mData = t.mData;
    mSent.setData(t.getDataParcel().data(), t.getDataParcel().dataSize());
    mReply.setData(t.getReplyParcel().data(), t.getReplyParcel().dataSize());
    mSentDataOnly.setData(t.getDataParcel().data(), t.getDataParcel().dataSize());
    mReplyDataOnly.setData(t.getReplyParcel().data(), t.getReplyParcel().dataSize());
}

std::optional<RecordedTransaction> RecordedTransaction::fromDetails(
@@ -136,12 +136,21 @@ std::optional<RecordedTransaction> RecordedTransaction::fromDetails(
        return std::nullopt;
    }

    if (t.mSent.setData(dataParcel.data(), dataParcel.dataBufferSize()) != android::NO_ERROR) {
    if (const auto* kernelFields = dataParcel.maybeKernelFields()) {
        for (size_t i = 0; i < kernelFields->mObjectsSize; i++) {
            uint64_t offset = kernelFields->mObjects[i];
            t.mData.mSentObjectData.push_back(offset);
        }
    }

    if (t.mSentDataOnly.setData(dataParcel.data(), dataParcel.dataBufferSize()) !=
        android::NO_ERROR) {
        ALOGE("Failed to set sent parcel data.");
        return std::nullopt;
    }

    if (t.mReply.setData(replyParcel.data(), replyParcel.dataBufferSize()) != android::NO_ERROR) {
    if (t.mReplyDataOnly.setData(replyParcel.data(), replyParcel.dataBufferSize()) !=
        android::NO_ERROR) {
        ALOGE("Failed to set reply parcel data.");
        return std::nullopt;
    }
@@ -154,6 +163,7 @@ enum {
    DATA_PARCEL_CHUNK = 2,
    REPLY_PARCEL_CHUNK = 3,
    INTERFACE_NAME_CHUNK = 4,
    DATA_PARCEL_OBJECT_CHUNK = 5,
    END_CHUNK = 0x00ffffff,
};

@@ -265,7 +275,7 @@ std::optional<RecordedTransaction> RecordedTransaction::fromFile(const unique_fd
                break;
            }
            case DATA_PARCEL_CHUNK: {
                if (t.mSent.setData(reinterpret_cast<const unsigned char*>(payloadMap),
                if (t.mSentDataOnly.setData(reinterpret_cast<const unsigned char*>(payloadMap),
                                            chunk.dataSize) != android::NO_ERROR) {
                    ALOGE("Failed to set sent parcel data.");
                    return std::nullopt;
@@ -273,13 +283,22 @@ std::optional<RecordedTransaction> RecordedTransaction::fromFile(const unique_fd
                break;
            }
            case REPLY_PARCEL_CHUNK: {
                if (t.mReply.setData(reinterpret_cast<const unsigned char*>(payloadMap),
                if (t.mReplyDataOnly.setData(reinterpret_cast<const unsigned char*>(payloadMap),
                                             chunk.dataSize) != android::NO_ERROR) {
                    ALOGE("Failed to set reply parcel data.");
                    return std::nullopt;
                }
                break;
            }
            case DATA_PARCEL_OBJECT_CHUNK: {
                const uint64_t* objects = reinterpret_cast<const uint64_t*>(payloadMap);
                size_t metaDataSize = (chunk.dataSize / sizeof(uint64_t));
                ALOGI("Total objects found in saved parcel %zu", metaDataSize);
                for (size_t index = 0; index < metaDataSize; ++index) {
                    t.mData.mSentObjectData.push_back(objects[index]);
                }
                break;
            }
            case END_CHUNK:
                break;
            default:
@@ -343,14 +362,26 @@ android::status_t RecordedTransaction::dumpToFile(const unique_fd& fd) const {
        return UNKNOWN_ERROR;
    }

    if (NO_ERROR != writeChunk(fd, DATA_PARCEL_CHUNK, mSent.dataBufferSize(), mSent.data())) {
    if (NO_ERROR !=
        writeChunk(fd, DATA_PARCEL_CHUNK, mSentDataOnly.dataBufferSize(), mSentDataOnly.data())) {
        ALOGE("Failed to write sent Parcel to fd %d", fd.get());
        return UNKNOWN_ERROR;
    }
    if (NO_ERROR != writeChunk(fd, REPLY_PARCEL_CHUNK, mReply.dataBufferSize(), mReply.data())) {

    if (NO_ERROR !=
        writeChunk(fd, REPLY_PARCEL_CHUNK, mReplyDataOnly.dataBufferSize(),
                   mReplyDataOnly.data())) {
        ALOGE("Failed to write reply Parcel to fd %d", fd.get());
        return UNKNOWN_ERROR;
    }

    if (NO_ERROR !=
        writeChunk(fd, DATA_PARCEL_OBJECT_CHUNK, mData.mSentObjectData.size() * sizeof(uint64_t),
                   reinterpret_cast<const uint8_t*>(mData.mSentObjectData.data()))) {
        ALOGE("Failed to write sent parcel object metadata to fd %d", fd.get());
        return UNKNOWN_ERROR;
    }

    if (NO_ERROR != writeChunk(fd, END_CHUNK, 0, NULL)) {
        ALOGE("Failed to write end chunk to fd %d", fd.get());
        return UNKNOWN_ERROR;
@@ -384,10 +415,14 @@ uint32_t RecordedTransaction::getVersion() const {
    return mData.mHeader.version;
}

const std::vector<uint64_t>& RecordedTransaction::getObjectOffsets() const {
    return mData.mSentObjectData;
}

const Parcel& RecordedTransaction::getDataParcel() const {
    return mSent;
    return mSentDataOnly;
}

const Parcel& RecordedTransaction::getReplyParcel() const {
    return mReply;
    return mReplyDataOnly;
}
+6 −0
Original line number Diff line number Diff line
@@ -55,6 +55,9 @@ class String8;
class TextOutput;
namespace binder {
class Status;
namespace debug {
class RecordedTransaction;
}
}

class Parcel {
@@ -1443,6 +1446,9 @@ private:
    // TODO(b/202029388): Remove 'getBlobAshmemSize' once no prebuilts reference
    // this
    size_t getBlobAshmemSize() const;

    // Needed so that we can save object metadata to the disk
    friend class android::binder::debug::RecordedTransaction;
};

// ---------------------------------------------------------------------------
+4 −2
Original line number Diff line number Diff line
@@ -50,6 +50,7 @@ public:
    uint32_t getVersion() const;
    const Parcel& getDataParcel() const;
    const Parcel& getReplyParcel() const;
    const std::vector<uint64_t>& getObjectOffsets() const;

private:
    RecordedTransaction() = default;
@@ -75,10 +76,11 @@ private:
    struct MovableData { // movable
        TransactionHeader mHeader;
        std::string mInterfaceName;
        std::vector<uint64_t> mSentObjectData; /* Object Offsets */
    };
    MovableData mData;
    Parcel mSent;
    Parcel mReply;
    Parcel mSentDataOnly;
    Parcel mReplyDataOnly;
};

} // namespace binder::debug
+7 −0
Original line number Diff line number Diff line
@@ -69,10 +69,14 @@ cc_test {
cc_test {
    name: "binderRecordReplayTest",
    srcs: ["binderRecordReplayTest.cpp"],
    cflags: [
        "-DBINDER_WITH_KERNEL_IPC",
    ],
    shared_libs: [
        "libbinder",
        "libcutils",
        "libutils",
        "liblog",
    ],
    static_libs: [
        "binderRecordReplayTestIface-cpp",
@@ -96,6 +100,9 @@ aidl_interface {
            enabled: true,
            platform_apis: true,
        },
        ndk: {
            enabled: false,
        },
    },
}

+6 −0
Original line number Diff line number Diff line
@@ -69,4 +69,10 @@ interface IBinderRecordReplayTest {

    void setSingleDataParcelableArray(in SingleDataParcelable[] input);
    SingleDataParcelable[] getSingleDataParcelableArray();

    void setBinder(in IBinder binder);
    IBinder getBinder();

    void setFileDescriptor(in FileDescriptor fd);
    FileDescriptor getFileDescriptor();
}
Loading