diff options
Diffstat (limited to 'libs/binder/Parcel.cpp')
-rw-r--r-- | libs/binder/Parcel.cpp | 124 |
1 files changed, 82 insertions, 42 deletions
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index 1e83c350b1..9f5d822c55 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -180,7 +180,7 @@ static void acquire_object(const sp<ProcessState>& proc, const flat_binder_objec } } - ALOGD("Invalid object type 0x%08x", obj.hdr.type); + ALOGE("Invalid object type 0x%08x to acquire", obj.hdr.type); } static void release_object(const sp<ProcessState>& proc, const flat_binder_object& obj, @@ -210,7 +210,7 @@ static void release_object(const sp<ProcessState>& proc, const flat_binder_objec } } - ALOGE("Invalid object type 0x%08x", obj.hdr.type); + ALOGE("Invalid object type 0x%08x to release", obj.hdr.type); } #endif // BINDER_WITH_KERNEL_IPC @@ -1162,31 +1162,6 @@ status_t Parcel::finishWrite(size_t len) return NO_ERROR; } -status_t Parcel::writeUnpadded(const void* data, size_t len) -{ - if (len > INT32_MAX) { - // don't accept size_t values which may have come from an - // inadvertent conversion from a negative int. - return BAD_VALUE; - } - - size_t end = mDataPos + len; - if (end < mDataPos) { - // integer overflow - return BAD_VALUE; - } - - if (end <= mDataCapacity) { -restart_write: - memcpy(mData+mDataPos, data, len); - return finishWrite(len); - } - - status_t err = growData(len); - if (err == NO_ERROR) goto restart_write; - return err; -} - status_t Parcel::write(const void* data, size_t len) { if (len > INT32_MAX) { @@ -1223,6 +1198,10 @@ restart_write: //printf("Writing %ld bytes, padded to %ld\n", len, padded); uint8_t* const data = mData+mDataPos; + if (status_t status = validateReadData(mDataPos + padded); status != OK) { + return nullptr; // drops status + } + // Need to pad at end? if (padded != len) { #if BYTE_ORDER == BIG_ENDIAN @@ -1803,6 +1782,10 @@ status_t Parcel::writeObject(const flat_binder_object& val, bool nullMetaData) const bool enoughObjects = kernelFields->mObjectsSize < kernelFields->mObjectsCapacity; if (enoughData && enoughObjects) { restart_write: + if (status_t status = validateReadData(mDataPos + sizeof(val)); status != OK) { + return status; + } + *reinterpret_cast<flat_binder_object*>(mData+mDataPos) = val; // remember if it's a file descriptor @@ -1878,7 +1861,10 @@ status_t Parcel::validateReadData(size_t upperBound) const if (mDataPos < kernelFields->mObjects[nextObject] + sizeof(flat_binder_object)) { // Requested info overlaps with an object if (!mServiceFuzzing) { - ALOGE("Attempt to read from protected data in Parcel %p", this); + ALOGE("Attempt to read or write from protected data in Parcel %p. pos: " + "%zu, nextObject: %zu, object offset: %llu, object size: %zu", + this, mDataPos, nextObject, kernelFields->mObjects[nextObject], + sizeof(flat_binder_object)); } return PERMISSION_DENIED; } @@ -2046,6 +2032,10 @@ status_t Parcel::writeAligned(T val) { if ((mDataPos+sizeof(val)) <= mDataCapacity) { restart_write: + if (status_t status = validateReadData(mDataPos + sizeof(val)); status != OK) { + return status; + } + memcpy(mData + mDataPos, &val, sizeof(val)); return finishWrite(sizeof(val)); } @@ -2236,9 +2226,7 @@ const char* Parcel::readCString() const const char* eos = reinterpret_cast<const char*>(memchr(str, 0, avail)); if (eos) { const size_t len = eos - str; - mDataPos += pad_size(len+1); - ALOGV("readCString Setting data pos of %p to %zu", this, mDataPos); - return str; + return static_cast<const char*>(readInplace(len + 1)); } } return nullptr; @@ -2682,14 +2670,14 @@ const flat_binder_object* Parcel::readObject(bool nullMetaData) const } #endif // BINDER_WITH_KERNEL_IPC -void Parcel::closeFileDescriptors() { +void Parcel::closeFileDescriptors(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]); @@ -2700,6 +2688,7 @@ void Parcel::closeFileDescriptors() { } } #else // BINDER_WITH_KERNEL_IPC + (void)newObjectsSize; LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time"); (void)kernelFields; #endif // BINDER_WITH_KERNEL_IPC @@ -2925,7 +2914,7 @@ void Parcel::freeDataNoInit() //ALOGI("Freeing data ref of %p (pid=%d)", this, getpid()); auto* kernelFields = maybeKernelFields(); // Close FDs before freeing, otherwise they will leak for kernel binder. - closeFileDescriptors(); + closeFileDescriptors(/*newObjectsSize=*/0); mOwner(mData, mDataSize, kernelFields ? kernelFields->mObjects : nullptr, kernelFields ? kernelFields->mObjectsSize : 0); } else { @@ -2953,6 +2942,14 @@ status_t Parcel::growData(size_t len) return BAD_VALUE; } + if (mDataPos > mDataSize) { + // b/370831157 - this case used to abort. We also don't expect mDataPos < mDataSize, but + // this would only waste a bit of memory, so it's okay. + ALOGE("growData only expected at the end of a Parcel. pos: %zu, size: %zu, capacity: %zu", + mDataPos, len, mDataCapacity); + return BAD_VALUE; + } + if (len > SIZE_MAX - mDataSize) return NO_MEMORY; // overflow if (mDataSize + len > SIZE_MAX / 3) return NO_MEMORY; // overflow size_t newSize = ((mDataSize+len)*3)/2; @@ -3054,13 +3051,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--; } } @@ -3109,15 +3131,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(); + closeFileDescriptors(objectsSize); } +#endif // BINDER_WITH_KERNEL_IPC mOwner(mData, mDataSize, kernelFields ? kernelFields->mObjects : nullptr, kernelFields ? kernelFields->mObjectsSize : 0); mOwner = nullptr; @@ -3244,11 +3275,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", @@ -3258,6 +3297,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; } |