summaryrefslogtreecommitdiff
path: root/libs/binder/tests/parcel_fuzzer
diff options
context:
space:
mode:
Diffstat (limited to 'libs/binder/tests/parcel_fuzzer')
-rw-r--r--libs/binder/tests/parcel_fuzzer/Android.bp12
-rw-r--r--libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_binder.h14
-rw-r--r--libs/binder/tests/parcel_fuzzer/random_binder.cpp66
-rw-r--r--libs/binder/tests/parcel_fuzzer/random_parcel.cpp4
-rw-r--r--libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp180
5 files changed, 228 insertions, 48 deletions
diff --git a/libs/binder/tests/parcel_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/Android.bp
index 83db6c9b6d..fbab8f08a9 100644
--- a/libs/binder/tests/parcel_fuzzer/Android.bp
+++ b/libs/binder/tests/parcel_fuzzer/Android.bp
@@ -131,6 +131,13 @@ cc_library {
"libcutils",
"libutils",
],
+ static_libs: [
+ "libbinder_random_parcel",
+ ],
+ include_dirs: [
+ "bionic/libc/kernel/android/uapi/",
+ "bionic/libc/kernel/uapi/",
+ ],
local_include_dirs: [
"include_random_parcel_seeds",
],
@@ -140,8 +147,12 @@ cc_library {
cc_binary_host {
name: "binder2corpus",
static_libs: [
+ "libbinder_random_parcel",
"libbinder_random_parcel_seeds",
],
+ cflags: [
+ "-DBINDER_WITH_KERNEL_IPC",
+ ],
srcs: [
"binder2corpus/binder2corpus.cpp",
],
@@ -149,5 +160,6 @@ cc_binary_host {
"libbase",
"libbinder",
"libutils",
+ "libcutils",
],
}
diff --git a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_binder.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_binder.h
index 8fc9263b98..7a1688b7b7 100644
--- a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_binder.h
+++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_binder.h
@@ -16,11 +16,25 @@
#pragma once
+#include <binder/Binder.h>
#include <binder/IBinder.h>
#include <fuzzer/FuzzedDataProvider.h>
namespace android {
+class RandomBinder : public BBinder {
+public:
+ RandomBinder(const String16& descriptor, std::vector<uint8_t>&& bytes);
+ const String16& getInterfaceDescriptor() const override;
+ status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) override;
+
+private:
+ String16 mDescriptor;
+ // note may not all be used
+ std::vector<uint8_t> mBytes;
+ FuzzedDataProvider mProvider;
+};
+
// Get a random binder object for use in fuzzing.
//
// May return nullptr.
diff --git a/libs/binder/tests/parcel_fuzzer/random_binder.cpp b/libs/binder/tests/parcel_fuzzer/random_binder.cpp
index 8a1fecb212..f41c35bfbe 100644
--- a/libs/binder/tests/parcel_fuzzer/random_binder.cpp
+++ b/libs/binder/tests/parcel_fuzzer/random_binder.cpp
@@ -21,56 +21,52 @@
#include <binder/IInterface.h>
#include <binder/IServiceManager.h>
+size_t kRandomInterfaceLength = 50;
namespace android {
-class RandomBinder : public BBinder {
-public:
- RandomBinder(const String16& descriptor, std::vector<uint8_t>&& bytes)
- : mDescriptor(descriptor),
- mBytes(std::move(bytes)),
- mProvider(mBytes.data(), mBytes.size()) {}
- const String16& getInterfaceDescriptor() const override { return mDescriptor; }
+RandomBinder::RandomBinder(const String16& descriptor, std::vector<uint8_t>&& bytes)
+ : mDescriptor(descriptor),
+ mBytes(std::move(bytes)),
+ mProvider(mBytes.data(), mBytes.size()) {}
- status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) override {
- (void)code;
- (void)data;
- (void)reply;
- (void)flags; // note - for maximum coverage even ignore if oneway
+const String16& RandomBinder::getInterfaceDescriptor() const {
+ return mDescriptor;
+}
- if (mProvider.ConsumeBool()) {
- return mProvider.ConsumeIntegral<status_t>();
- }
+status_t RandomBinder::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t flags) {
+ (void)code;
+ (void)data;
+ (void)reply;
+ (void)flags; // note - for maximum coverage even ignore if oneway
- if (reply == nullptr) return OK;
+ if (mProvider.ConsumeBool()) {
+ return mProvider.ConsumeIntegral<status_t>();
+ }
- // TODO: things we could do to increase state space
- // - also pull FDs and binders from 'data'
- // (optionally combine these into random parcel 'options')
- // - also pull FDs and binders from random parcel 'options'
- RandomParcelOptions options;
+ if (reply == nullptr) return OK;
- // random output
- std::vector<uint8_t> subData = mProvider.ConsumeBytes<uint8_t>(
- mProvider.ConsumeIntegralInRange<size_t>(0, mProvider.remaining_bytes()));
- fillRandomParcel(reply, FuzzedDataProvider(subData.data(), subData.size()), &options);
+ // TODO: things we could do to increase state space
+ // - also pull FDs and binders from 'data'
+ // (optionally combine these into random parcel 'options')
+ // - also pull FDs and binders from random parcel 'options'
+ RandomParcelOptions options;
- return OK;
- }
+ // random output
+ std::vector<uint8_t> subData = mProvider.ConsumeBytes<uint8_t>(
+ mProvider.ConsumeIntegralInRange<size_t>(0, mProvider.remaining_bytes()));
+ fillRandomParcel(reply, FuzzedDataProvider(subData.data(), subData.size()), &options);
-private:
- String16 mDescriptor;
-
- // note may not all be used
- std::vector<uint8_t> mBytes;
- FuzzedDataProvider mProvider;
-};
+ return OK;
+}
sp<IBinder> getRandomBinder(FuzzedDataProvider* provider) {
auto makeFunc = provider->PickValueInArray<const std::function<sp<IBinder>()>>({
[&]() {
// descriptor is the length of a class name, e.g.
// "some.package.Foo"
- std::string str = provider->ConsumeRandomLengthString(100 /*max length*/);
+ std::string str =
+ provider->ConsumeRandomLengthString(kRandomInterfaceLength /*max length*/);
// arbitrarily consume remaining data to create a binder that can return
// random results - coverage guided fuzzer should ensure all of the remaining
diff --git a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
index 4e58dc4899..62b84330cd 100644
--- a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
+++ b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
@@ -73,7 +73,7 @@ void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider, RandomParcelOpti
return;
}
- if (options->extraFds.size() > 0 && provider.ConsumeBool()) {
+ if (provider.ConsumeBool() && options->extraFds.size() > 0) {
const unique_fd& fd = options->extraFds.at(
provider.ConsumeIntegralInRange<size_t>(0,
options->extraFds.size() -
@@ -102,7 +102,7 @@ void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider, RandomParcelOpti
}
sp<IBinder> binder;
- if (options->extraBinders.size() > 0 && provider.ConsumeBool()) {
+ if (provider.ConsumeBool() && options->extraBinders.size() > 0) {
binder = options->extraBinders.at(
provider.ConsumeIntegralInRange<size_t>(0,
options->extraBinders
diff --git a/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp b/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp
index 7b3c80642b..fd9777a916 100644
--- a/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp
+++ b/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp
@@ -14,16 +14,26 @@
* limitations under the License.
*/
+#include <linux/android/binder.h>
+
#include <android-base/logging.h>
+#include <binder/Parcel.h>
#include <binder/RecordedTransaction.h>
#include <fuzzseeds/random_parcel_seeds.h>
+#include <stack>
+#include <string>
#include "../../file.h"
using android::binder::borrowed_fd;
using android::binder::WriteFully;
+using std::stack;
+
+extern size_t kRandomInterfaceLength;
+// Keep this in sync with max_length in random_binder.cpp while creating a RandomBinder
+std::string kRandomInterfaceName(kRandomInterfaceLength, 'i');
namespace android {
namespace impl {
@@ -66,6 +76,162 @@ void writeReversedBuffer(std::vector<uint8_t>& integralBuffer, T val) {
} // namespace impl
+struct ProviderMetadata {
+ size_t position;
+ size_t value;
+
+ ProviderMetadata() {
+ value = 0;
+ position = 0;
+ }
+};
+
+// Assuming current seed path is inside the fillRandomParcel function, start of the loop.
+void writeRandomBinder(borrowed_fd fd, vector<uint8_t>& fillParcelBuffer,
+ stack<ProviderMetadata>& remainingPositions) {
+ // Choose 2 index in array
+ size_t fillFuncIndex = 2;
+ impl::writeReversedBuffer(fillParcelBuffer, static_cast<size_t>(0), static_cast<size_t>(2),
+ fillFuncIndex);
+
+ // navigate to getRandomBinder. provide consume bool false
+ bool flag = false;
+ impl::writeReversedBuffer(fillParcelBuffer, flag);
+
+ // selecting RandomBinder, other binders in the list are not recorded as KernelObjects
+ size_t randomBinderIndex = 0;
+ impl::writeReversedBuffer(fillParcelBuffer, static_cast<size_t>(0), static_cast<size_t>(2),
+ randomBinderIndex);
+
+ // write random string of length 100 in actual buffer array.
+ CHECK(WriteFully(fd, kRandomInterfaceName.c_str(), kRandomInterfaceName.size())) << fd.get();
+
+ // These will be bytes which are used inside of RandomBinder
+ // simplest path for these bytes is going to be consume bool -> return random status
+ vector<uint8_t> randomBinderBuffer;
+
+ bool returnRandomInt = true;
+ impl::writeReversedBuffer(randomBinderBuffer, returnRandomInt);
+
+ status_t randomStatus = 0;
+ impl::writeReversedBuffer(randomBinderBuffer, randomStatus);
+
+ // write integral in range to consume bytes for random binder
+ ProviderMetadata providerData;
+ providerData.position = fillParcelBuffer.size();
+ providerData.value = randomBinderBuffer.size();
+ remainingPositions.push(providerData);
+
+ // Write to fd
+ CHECK(WriteFully(fd, randomBinderBuffer.data(), randomBinderBuffer.size())) << fd.get();
+}
+
+// Assuming current seed path is inside the fillRandomParcelFunction, start of the loop.
+void writeRandomFd(vector<uint8_t>& fillParcelBuffer) {
+ // path to random fd
+ size_t fillFuncIndex = 1;
+ impl::writeReversedBuffer(fillParcelBuffer, static_cast<size_t>(0), static_cast<size_t>(2),
+ fillFuncIndex);
+
+ bool flag = false;
+ impl::writeReversedBuffer(fillParcelBuffer, flag);
+
+ // go for /dev/null index 1
+ size_t fdIndex = 1;
+ impl::writeReversedBuffer(fillParcelBuffer, static_cast<size_t>(0), static_cast<size_t>(3),
+ fdIndex);
+}
+
+void writeParcelData(borrowed_fd fd, vector<uint8_t>& fillParcelBuffer,
+ stack<ProviderMetadata>& remainingPositions, const uint8_t* data, size_t start,
+ size_t length) {
+ // need to write parcel data till next offset with instructions to pick random bytes till offset
+ size_t fillFuncIndex = 0;
+ impl::writeReversedBuffer(fillParcelBuffer, static_cast<size_t>(0), static_cast<size_t>(2),
+ fillFuncIndex);
+
+ // provide how much bytes to read in control buffer
+ ProviderMetadata providerData;
+ providerData.position = fillParcelBuffer.size();
+ providerData.value = length;
+ remainingPositions.push(providerData);
+
+ // provide actual bytes
+ CHECK(WriteFully(fd, data + start, length)) << fd.get();
+}
+
+/**
+ * Generate sequence of copy data, write fd and write binder instructions and required data.
+ * Data which will be read using consumeBytes is written to fd directly. Data which is read in
+ * form integer is consumed from rear end FuzzedDataProvider. So insert it in fillParcelBuffer and
+ * then write to fd
+ */
+size_t regenerateParcel(borrowed_fd fd, vector<uint8_t>& fillParcelBuffer, const Parcel& p,
+ size_t dataSize, const vector<uint64_t>& objectOffsets) {
+ stack<ProviderMetadata> remainingPositions;
+ size_t copiedDataPosition = 0;
+ const uint8_t* parcelData = p.data();
+ size_t numBinders = 0;
+ size_t numFds = 0;
+
+ for (auto offset : objectOffsets) {
+ // Check what type of object is present here
+ const flat_binder_object* flatObject =
+ reinterpret_cast<const flat_binder_object*>(parcelData + offset);
+ // Copy till the object offset
+ writeParcelData(fd, fillParcelBuffer, remainingPositions, parcelData, copiedDataPosition,
+ offset - copiedDataPosition);
+ copiedDataPosition = offset;
+ if (flatObject->hdr.type == BINDER_TYPE_BINDER ||
+ flatObject->hdr.type == BINDER_TYPE_HANDLE) {
+ writeRandomBinder(fd, fillParcelBuffer, remainingPositions);
+ numBinders++;
+ // In case of binder, stability is written after the binder object.
+ // We want to move the copiedDataPosition further to account for this stability field
+ copiedDataPosition += sizeof(int32_t) + sizeof(flat_binder_object);
+ } else if (flatObject->hdr.type == BINDER_TYPE_FD) {
+ writeRandomFd(fillParcelBuffer);
+ numFds++;
+ copiedDataPosition += sizeof(flat_binder_object);
+ }
+ }
+
+ if (copiedDataPosition < dataSize) {
+ // copy remaining data from recorded parcel -> last Object to end of the data
+ writeParcelData(fd, fillParcelBuffer, remainingPositions, parcelData, copiedDataPosition,
+ dataSize - copiedDataPosition);
+ }
+
+ // We need to write bytes for selecting integer within range of 0 to provide.remaining_bytes()
+ // is called.
+ size_t totalWrittenBytes = dataSize - (sizeof(flat_binder_object) * objectOffsets.size()) -
+ (sizeof(int32_t) * numBinders) +
+ (kRandomInterfaceName.size() /*Interface String*/ + sizeof(bool) + sizeof(status_t)) *
+ numBinders;
+
+ // Code in fuzzService relies on provider.remaining_bytes() to select random bytes using
+ // consume integer. use the calculated remaining_bytes to generate byte buffer which can
+ // generate required fds and binders in fillRandomParcel function.
+ while (!remainingPositions.empty()) {
+ auto meta = remainingPositions.top();
+ remainingPositions.pop();
+ size_t remainingBytes = totalWrittenBytes + fillParcelBuffer.size() - meta.position;
+
+ vector<uint8_t> remReversedBytes;
+ impl::writeReversedBuffer(remReversedBytes, static_cast<size_t>(0), remainingBytes,
+ meta.value);
+ // Check the order of buffer which is being written
+ fillParcelBuffer.insert(fillParcelBuffer.end() - meta.position, remReversedBytes.begin(),
+ remReversedBytes.end());
+ }
+
+ return totalWrittenBytes;
+}
+
+/**
+ * Current corpus format
+ * |Reserved bytes(8)|parcel data|fillParcelBuffer|integralBuffer|
+ */
void generateSeedsFromRecording(borrowed_fd fd,
const binder::debug::RecordedTransaction& transaction) {
// Write Reserved bytes for future use
@@ -123,17 +289,9 @@ void generateSeedsFromRecording(borrowed_fd fd,
uint8_t writeHeaderInternal = 0;
impl::writeReversedBuffer(fillParcelBuffer, writeHeaderInternal);
- // Choose to write data in parcel
- size_t fillFuncIndex = 0;
- impl::writeReversedBuffer(fillParcelBuffer, static_cast<size_t>(0), static_cast<size_t>(2),
- fillFuncIndex);
-
- // Write parcel data size from recorded transaction
- size_t toWrite = transaction.getDataParcel().dataBufferSize();
- impl::writeReversedBuffer(fillParcelBuffer, static_cast<size_t>(0), toWrite, toWrite);
-
- // Write parcel data with size towrite from recorded transaction
- CHECK(WriteFully(fd, dataParcel.data(), toWrite)) << fd.get();
+ auto objectMetadata = transaction.getObjectOffsets();
+ size_t toWrite = regenerateParcel(fd, fillParcelBuffer, dataParcel, dataParcel.dataBufferSize(),
+ objectMetadata);
// Write Fill Parcel buffer size in integralBuffer so that fuzzService knows size of data
size_t subDataSize = toWrite + fillParcelBuffer.size();