From b09a1d237f1a881c82c4cd9381a9fc3d56cb22e2 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Sat, 7 Dec 2024 03:23:57 +0000 Subject: binder_parcel_fuzzer: support owned Parcels Some codepaths in Parcel are different when the Parcel is owned. This allows fillRandomParcel to also sometimes cause the returned Parcel be a view of a filled out Parcel. This increases the possible impact and bug finding abilities of all of our AIDL fuzzers as well. Ignore-AOSP-First: fuzzing Bug: 369404061 Test: binder_parcel_fuzzer Change-Id: Ib19a0cbd74d48e18ba36cff56202541105ef9163 --- libs/binder/Parcel.cpp | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) (limited to 'libs/binder/Parcel.cpp') 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> 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(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(data); mDataSize = mDataCapacity = dataSize; kernelFields->mObjects = const_cast(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(data); mDataSize = mDataCapacity = dataSize; mOwner = relFunc; -- cgit v1.2.3-59-g8ed1b