diff options
| author | 2024-10-23 19:06:14 +0000 | |
|---|---|---|
| committer | 2024-10-23 19:06:14 +0000 | |
| commit | c60bf843ebde99de49d2ee8c79389e38119a0a06 (patch) | |
| tree | 1fd53b166dd716163c4d5d147c0ef21d93d9e21e /libs/binder/Parcel.cpp | |
| parent | 0c0a920ac9472ee95935d0a1a93ec2b61e795b90 (diff) | |
| parent | e32c1ab25b3204e649e10743c239298f38203bc6 (diff) | |
binder: fix FD handling in continueWrite am: e32c1ab25b
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/native/+/29868448
Change-Id: I68e89c1ffb49122d1e9693e068bda3746c2ce588
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
Diffstat (limited to 'libs/binder/Parcel.cpp')
| -rw-r--r-- | libs/binder/Parcel.cpp | 66 |
1 files changed, 57 insertions, 9 deletions
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index 0aca163eab..15dad8e521 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -2505,13 +2505,17 @@ const flat_binder_object* Parcel::readObject(bool nullMetaData) const #endif // BINDER_WITH_KERNEL_IPC void Parcel::closeFileDescriptors() { + truncateFileDescriptors(0); +} + +void Parcel::truncateFileDescriptors(size_t newObjectsSize) { if (auto* kernelFields = maybeKernelFields()) { #ifdef BINDER_WITH_KERNEL_IPC size_t i = kernelFields->mObjectsSize; if (i > 0) { // ALOGI("Closing file descriptors for %zu objects...", i); } - while (i > 0) { + while (i > newObjectsSize) { i--; const flat_binder_object* flat = reinterpret_cast<flat_binder_object*>(mData + kernelFields->mObjects[i]); @@ -2521,6 +2525,7 @@ void Parcel::closeFileDescriptors() { } } #else // BINDER_WITH_KERNEL_IPC + (void)newObjectsSize; LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time"); #endif // BINDER_WITH_KERNEL_IPC } else if (auto* rpcFields = maybeRpcFields()) { @@ -2870,13 +2875,38 @@ status_t Parcel::continueWrite(size_t desired) objectsSize = 0; } else { if (kernelFields) { +#ifdef BINDER_WITH_KERNEL_IPC + validateReadData(mDataSize); // hack to sort the objects while (objectsSize > 0) { - if (kernelFields->mObjects[objectsSize - 1] < desired) break; + if (kernelFields->mObjects[objectsSize - 1] + sizeof(flat_binder_object) <= + desired) + break; objectsSize--; } +#endif // BINDER_WITH_KERNEL_IPC } else { while (objectsSize > 0) { - if (rpcFields->mObjectPositions[objectsSize - 1] < desired) break; + // Object size varies by type. + uint32_t pos = rpcFields->mObjectPositions[objectsSize - 1]; + size_t size = sizeof(RpcFields::ObjectType); + uint32_t minObjectEnd; + if (__builtin_add_overflow(pos, sizeof(RpcFields::ObjectType), &minObjectEnd) || + minObjectEnd > mDataSize) { + return BAD_VALUE; + } + const auto type = *reinterpret_cast<const RpcFields::ObjectType*>(mData + pos); + switch (type) { + case RpcFields::TYPE_BINDER_NULL: + break; + case RpcFields::TYPE_BINDER: + size += sizeof(uint64_t); // address + break; + case RpcFields::TYPE_NATIVE_FILE_DESCRIPTOR: + size += sizeof(int32_t); // fd index + break; + } + + if (pos + size <= desired) break; objectsSize--; } } @@ -2925,15 +2955,24 @@ status_t Parcel::continueWrite(size_t desired) if (mData) { memcpy(data, mData, mDataSize < desired ? mDataSize : desired); } +#ifdef BINDER_WITH_KERNEL_IPC if (objects && kernelFields && kernelFields->mObjects) { memcpy(objects, kernelFields->mObjects, objectsSize * sizeof(binder_size_t)); + // All FDs are owned when `mOwner`, even when `cookie == 0`. When + // we switch to `!mOwner`, we need to explicitly mark the FDs as + // owned. + for (size_t i = 0; i < objectsSize; i++) { + flat_binder_object* flat = reinterpret_cast<flat_binder_object*>(data + objects[i]); + if (flat->hdr.type == BINDER_TYPE_FD) { + flat->cookie = 1; + } + } } // ALOGI("Freeing data ref of %p (pid=%d)", this, getpid()); if (kernelFields) { - // TODO(b/239222407): This seems wrong. We should only free FDs when - // they are in a truncated section of the parcel. - closeFileDescriptors(); + truncateFileDescriptors(objectsSize); } +#endif // BINDER_WITH_KERNEL_IPC mOwner(mData, mDataSize, kernelFields ? kernelFields->mObjects : nullptr, kernelFields ? kernelFields->mObjectsSize : 0); mOwner = nullptr; @@ -3060,11 +3099,19 @@ status_t Parcel::truncateRpcObjects(size_t newObjectsSize) { } while (rpcFields->mObjectPositions.size() > newObjectsSize) { uint32_t pos = rpcFields->mObjectPositions.back(); - rpcFields->mObjectPositions.pop_back(); + uint32_t minObjectEnd; + if (__builtin_add_overflow(pos, sizeof(RpcFields::ObjectType), &minObjectEnd) || + minObjectEnd > mDataSize) { + return BAD_VALUE; + } const auto type = *reinterpret_cast<const RpcFields::ObjectType*>(mData + pos); if (type == RpcFields::TYPE_NATIVE_FILE_DESCRIPTOR) { - const auto fdIndex = - *reinterpret_cast<const int32_t*>(mData + pos + sizeof(RpcFields::ObjectType)); + uint32_t objectEnd; + if (__builtin_add_overflow(minObjectEnd, sizeof(int32_t), &objectEnd) || + objectEnd > mDataSize) { + return BAD_VALUE; + } + const auto fdIndex = *reinterpret_cast<const int32_t*>(mData + minObjectEnd); if (rpcFields->mFds == nullptr || fdIndex < 0 || static_cast<size_t>(fdIndex) >= rpcFields->mFds->size()) { ALOGE("RPC Parcel contains invalid file descriptor index. index=%d fd_count=%zu", @@ -3074,6 +3121,7 @@ status_t Parcel::truncateRpcObjects(size_t newObjectsSize) { // In practice, this always removes the last element. rpcFields->mFds->erase(rpcFields->mFds->begin() + fdIndex); } + rpcFields->mObjectPositions.pop_back(); } return OK; } |