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
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 41856f9..cd3e7c0 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -77,6 +77,8 @@
     static_libs: [
         "binderRecordReplayTestIface-cpp",
         "binderReadParcelIface-cpp",
+        "libbinder_random_parcel_seeds",
+        "libbinder_random_parcel",
     ],
     test_suites: ["general-tests"],
     require_root: true,
diff --git a/libs/binder/tests/binderRecordReplayTest.cpp b/libs/binder/tests/binderRecordReplayTest.cpp
index 17d5c8a..6773c95 100644
--- a/libs/binder/tests/binderRecordReplayTest.cpp
+++ b/libs/binder/tests/binderRecordReplayTest.cpp
@@ -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 @@
     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,48 +143,46 @@
     template <typename T, typename U>
     void recordReplay(Status (IBinderRecordReplayTest::*set)(T), U recordedValue,
                       Status (IBinderRecordReplayTest::*get)(U*), U changedValue) {
-        base::unique_fd fd(open("/data/local/tmp/binderRecordReplayTest.rec",
-                                O_RDWR | O_CREAT | O_CLOEXEC, 0666));
-        ASSERT_TRUE(fd.ok());
+        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());
 
-        // record a transaction
-        mBpBinder->startRecordingBinder(fd);
-        auto status = (*mInterface.*set)(recordedValue);
-        EXPECT_TRUE(status.isOk());
-        mBpBinder->stopRecordingBinder();
+            // record a transaction
+            mBpBinder->startRecordingBinder(fd);
+            auto status = (*mInterface.*set)(recordedValue);
+            EXPECT_TRUE(status.isOk());
+            mBpBinder->stopRecordingBinder();
 
-        // test transaction does the thing we expect it to do
-        U output;
-        status = (*mInterface.*get)(&output);
-        EXPECT_TRUE(status.isOk());
-        EXPECT_EQ(output, recordedValue);
+            // test transaction does the thing we expect it to do
+            U output;
+            status = (*mInterface.*get)(&output);
+            EXPECT_TRUE(status.isOk());
+            EXPECT_EQ(output, recordedValue);
 
-        // write over the existing state
-        status = (*mInterface.*set)(changedValue);
-        EXPECT_TRUE(status.isOk());
+            // write over the existing state
+            status = (*mInterface.*set)(changedValue);
+            EXPECT_TRUE(status.isOk());
 
-        status = (*mInterface.*get)(&output);
-        EXPECT_TRUE(status.isOk());
+            status = (*mInterface.*get)(&output);
+            EXPECT_TRUE(status.isOk());
 
-        EXPECT_EQ(output, changedValue);
+            EXPECT_EQ(output, changedValue);
 
-        // replay transaction
-        ASSERT_EQ(0, lseek(fd.get(), 0, SEEK_SET));
-        std::optional<RecordedTransaction> transaction = RecordedTransaction::fromFile(fd);
-        ASSERT_NE(transaction, std::nullopt);
+            // replay transaction
+            ASSERT_EQ(0, lseek(fd.get(), 0, SEEK_SET));
+            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());
+            const RecordedTransaction& recordedTransaction = *transaction;
+            // call replay function with recorded transaction
+            (*replayFunc)(mBpBinder, recordedTransaction);
 
-        // make sure recording does the thing we expect it to do
-        EXPECT_EQ(OK, result);
-
-        status = (*mInterface.*get)(&output);
-        EXPECT_TRUE(status.isOk());
-        EXPECT_EQ(output, recordedValue);
+            status = (*mInterface.*get)(&output);
+            EXPECT_TRUE(status.isOk());
+            EXPECT_EQ(output, recordedValue);
+        }
     }
 
 private:
diff --git a/libs/binder/tests/parcel_fuzzer/include_random_parcel_seeds/fuzzseeds/random_parcel_seeds.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel_seeds/fuzzseeds/random_parcel_seeds.h
index 6cceb06..5755239 100644
--- a/libs/binder/tests/parcel_fuzzer/include_random_parcel_seeds/fuzzseeds/random_parcel_seeds.h
+++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel_seeds/fuzzseeds/random_parcel_seeds.h
@@ -43,5 +43,5 @@
 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
diff --git a/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp b/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp
index 7c66683..9e3e2ab 100644
--- a/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp
+++ b/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp
@@ -65,7 +65,7 @@
 } // 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();