diff options
-rw-r--r-- | libs/binder/Parcel.cpp | 61 | ||||
-rw-r--r-- | libs/binder/include/binder/Parcel.h | 7 | ||||
-rw-r--r-- | libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h | 3 | ||||
-rw-r--r-- | libs/binder/tests/parcel_fuzzer/main.cpp | 11 | ||||
-rw-r--r-- | libs/binder/tests/parcel_fuzzer/random_parcel.cpp | 24 | ||||
-rw-r--r-- | libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp | 6 |
6 files changed, 103 insertions, 9 deletions
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index e2eea6c458..0b7cd8154d 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -2728,6 +2728,65 @@ size_t Parcel::ipcObjectsCount() const return 0; } +static void do_nothing_release_func(const uint8_t* data, size_t dataSize, + const binder_size_t* objects, size_t objectsCount) { + (void)data; + (void)dataSize; + (void)objects; + (void)objectsCount; +} +static void delete_data_release_func(const uint8_t* data, size_t dataSize, + const binder_size_t* objects, size_t objectsCount) { + delete[] data; + (void)dataSize; + (void)objects; + (void)objectsCount; +} + +void Parcel::makeDangerousViewOf(Parcel* p) { + if (p->isForRpc()) { + // warning: this must match the logic in rpcSetDataReference + auto* rf = p->maybeRpcFields(); + LOG_ALWAYS_FATAL_IF(rf == nullptr); + std::vector<std::variant<binder::unique_fd, binder::borrowed_fd>> fds; + if (rf->mFds) { + fds.reserve(rf->mFds->size()); + for (const auto& fd : *rf->mFds) { + fds.push_back(binder::borrowed_fd(toRawFd(fd))); + } + } + status_t result = + rpcSetDataReference(rf->mSession, p->mData, p->mDataSize, + rf->mObjectPositions.data(), rf->mObjectPositions.size(), + std::move(fds), do_nothing_release_func); + LOG_ALWAYS_FATAL_IF(result != OK, "Failed: %s", statusToString(result).c_str()); + } else { +#ifdef BINDER_WITH_KERNEL_IPC + // warning: this must match the logic in ipcSetDataReference + auto* kf = p->maybeKernelFields(); + LOG_ALWAYS_FATAL_IF(kf == nullptr); + + // Ownership of FDs is passed to the Parcel from kernel binder. This should be refactored + // to move this ownership out of Parcel and into release_func. However, today, Parcel + // always assums it can own and close FDs today. So, for purposes of testing consistency, + // , create new FDs it can own. + + uint8_t* newData = new uint8_t[p->mDataSize]; // deleted by delete_data_release_func + memcpy(newData, p->mData, p->mDataSize); + for (size_t i = 0; i < kf->mObjectsSize; i++) { + flat_binder_object* flat = + reinterpret_cast<flat_binder_object*>(newData + kf->mObjects[i]); + if (flat->hdr.type == BINDER_TYPE_FD) { + flat->handle = fcntl(flat->handle, F_DUPFD_CLOEXEC, 0); + } + } + + ipcSetDataReference(newData, p->mDataSize, kf->mObjects, kf->mObjectsSize, + delete_data_release_func); +#endif // BINDER_WITH_KERNEL_IPC + } +} + void Parcel::ipcSetDataReference(const uint8_t* data, size_t dataSize, const binder_size_t* objects, size_t objectsCount, release_func relFunc) { // this code uses 'mOwner == nullptr' to understand whether it owns memory @@ -2738,6 +2797,7 @@ void Parcel::ipcSetDataReference(const uint8_t* data, size_t dataSize, const bin auto* kernelFields = maybeKernelFields(); LOG_ALWAYS_FATAL_IF(kernelFields == nullptr); // guaranteed by freeData. + // must match makeDangerousViewOf mData = const_cast<uint8_t*>(data); mDataSize = mDataCapacity = dataSize; kernelFields->mObjects = const_cast<binder_size_t*>(objects); @@ -2816,6 +2876,7 @@ status_t Parcel::rpcSetDataReference( auto* rpcFields = maybeRpcFields(); LOG_ALWAYS_FATAL_IF(rpcFields == nullptr); // guaranteed by markForRpc. + // must match makeDangerousViewOf mData = const_cast<uint8_t*>(data); mDataSize = mDataCapacity = dataSize; mOwner = relFunc; diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h index 42c5ebd096..b4efa0af6d 100644 --- a/libs/binder/include/binder/Parcel.h +++ b/libs/binder/include/binder/Parcel.h @@ -649,6 +649,11 @@ public: LIBBINDER_EXPORTED void print(std::ostream& to, uint32_t flags = 0) const; + // This API is to quickly become a view of another Parcel, so that we can also + // test 'owner' paths quickly. It's extremely dangerous to use this API in + // practice, and you should never ever do it. + LIBBINDER_EXPORTED void makeDangerousViewOf(Parcel* p); + private: // Close all file descriptors in the parcel at object positions >= newObjectsSize. void closeFileDescriptors(size_t newObjectsSize); @@ -664,7 +669,7 @@ private: void ipcSetDataReference(const uint8_t* data, size_t dataSize, const binder_size_t* objects, size_t objectsCount, release_func relFunc); // Takes ownership even when an error is returned. - status_t rpcSetDataReference( + [[nodiscard]] status_t rpcSetDataReference( const sp<RpcSession>& session, const uint8_t* data, size_t dataSize, const uint32_t* objectTable, size_t objectTableSize, std::vector<std::variant<binder::unique_fd, binder::borrowed_fd>>&& ancillaryFds, diff --git a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h index 2812da79fa..11fcb061f6 100644 --- a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h +++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h @@ -28,6 +28,9 @@ struct RandomParcelOptions { std::function<void(Parcel* p, FuzzedDataProvider& provider)> writeHeader; std::vector<sp<IBinder>> extraBinders; std::vector<binder::unique_fd> extraFds; + + // internal state owned by fillRandomParcel, for Parcel views + std::vector<std::unique_ptr<Parcel>> extraParcels; }; /** diff --git a/libs/binder/tests/parcel_fuzzer/main.cpp b/libs/binder/tests/parcel_fuzzer/main.cpp index 192f9d5dce..d06b2d9020 100644 --- a/libs/binder/tests/parcel_fuzzer/main.cpp +++ b/libs/binder/tests/parcel_fuzzer/main.cpp @@ -70,7 +70,7 @@ void doTransactFuzz(const char* backend, const sp<B>& binder, FuzzedDataProvider uint32_t code = provider.ConsumeIntegral<uint32_t>(); uint32_t flag = provider.ConsumeIntegral<uint32_t>(); - FUZZ_LOG() << "backend: " << backend; + FUZZ_LOG() << "doTransactFuzz backend: " << backend; RandomParcelOptions options; @@ -101,7 +101,7 @@ void doReadFuzz(const char* backend, const std::vector<ParcelRead<P>>& reads, // since we are only using a byte to index CHECK_LE(reads.size(), 255u) << reads.size(); - FUZZ_LOG() << "backend: " << backend; + FUZZ_LOG() << "doReadFuzz backend: " << backend; FUZZ_LOG() << "input: " << HexString(p.data(), p.dataSize()); FUZZ_LOG() << "instructions: " << HexString(instructions.data(), instructions.size()); @@ -122,10 +122,15 @@ void doReadWriteFuzz(const char* backend, const std::vector<ParcelRead<P>>& read RandomParcelOptions options; P p; + // small amount of initial Parcel data, since fillRandomParcel uses makeDangerousViewOf + std::vector<uint8_t> parcelData = + provider.ConsumeBytes<uint8_t>(provider.ConsumeIntegralInRange<size_t>(0, 20)); + fillRandomParcel(&p, FuzzedDataProvider(parcelData.data(), parcelData.size()), &options); + // since we are only using a byte to index CHECK_LE(reads.size() + writes.size(), 255u) << reads.size(); - FUZZ_LOG() << "backend: " << backend; + FUZZ_LOG() << "doReadWriteFuzz backend: " << backend; while (provider.remaining_bytes() > 0) { uint8_t idx = provider.ConsumeIntegralInRange<uint8_t>(0, reads.size() + writes.size() - 1); diff --git a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp index 7c196142e8..dfd178a450 100644 --- a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp +++ b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp @@ -17,6 +17,7 @@ #include <fuzzbinder/random_parcel.h> #include <android-base/logging.h> +#include <binder/Functional.h> #include <binder/RpcSession.h> #include <binder/RpcTransportRaw.h> #include <fuzzbinder/random_binder.h> @@ -32,10 +33,29 @@ static void fillRandomParcelData(Parcel* p, FuzzedDataProvider&& provider) { CHECK(OK == p->write(data.data(), data.size())); } -void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider, RandomParcelOptions* options) { +void fillRandomParcel(Parcel* outputParcel, FuzzedDataProvider&& provider, + RandomParcelOptions* options) { CHECK_NE(options, nullptr); - if (provider.ConsumeBool()) { + const uint8_t fuzzerParcelOptions = provider.ConsumeIntegral<uint8_t>(); + const bool resultShouldBeView = fuzzerParcelOptions & 1; + const bool resultShouldBeRpc = fuzzerParcelOptions & 2; + + Parcel* p; + if (resultShouldBeView) { + options->extraParcels.push_back(std::make_unique<Parcel>()); + // held for duration of test, so that view will be valid + p = options->extraParcels[options->extraParcels.size() - 1].get(); + } else { + p = outputParcel; // directly fill out the output Parcel + } + auto viewify_guard = binder::impl::make_scope_guard([&]() { + if (resultShouldBeView) { + outputParcel->makeDangerousViewOf(p); + } + }); + + if (resultShouldBeRpc) { auto session = RpcSession::make(RpcTransportCtxFactoryRaw::make()); CHECK_EQ(OK, session->addNullDebuggingClient()); // Set the protocol version so that we don't crash if the session diff --git a/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp b/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp index 0ed8a554ac..3cb628925c 100644 --- a/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp +++ b/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp @@ -281,9 +281,9 @@ void generateSeedsFromRecording(borrowed_fd fd, // This buffer holds the bytes which will be used for fillRandomParcel API std::vector<uint8_t> fillParcelBuffer; - // Don't take rpc path - uint8_t rpcBranch = 0; - impl::writeReversedBuffer(fillParcelBuffer, rpcBranch); + // Use all default options. + uint8_t parcelOptions = 0; + impl::writeReversedBuffer(fillParcelBuffer, parcelOptions); // Implicit branch on this path -> options->writeHeader(p, provider) uint8_t writeHeaderInternal = 0; |