diff options
| -rw-r--r-- | libs/binder/Parcel.cpp | 23 | ||||
| -rw-r--r-- | libs/binder/include/binder/Parcel.h | 8 | ||||
| -rw-r--r-- | libs/binder/tests/parcel_fuzzer/binder.cpp | 12 |
3 files changed, 38 insertions, 5 deletions
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index e4dfa52189..9795348a0c 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -1466,6 +1466,29 @@ const void* Parcel::readInplace(size_t len) const return nullptr; } +status_t Parcel::readOutVectorSizeWithCheck(size_t elmSize, int32_t* size) const { + if (status_t status = readInt32(size); status != OK) return status; + if (*size < 0) return OK; // may be null, client to handle + + LOG_ALWAYS_FATAL_IF(elmSize > INT32_MAX, "Cannot have element as big as %zu", elmSize); + + // approximation, can't know max element size (e.g. if it makes heap + // allocations) + static_assert(sizeof(int) == sizeof(int32_t), "Android is LP64"); + int32_t allocationSize; + if (__builtin_smul_overflow(elmSize, *size, &allocationSize)) return NO_MEMORY; + + // High limit of 1MB since something this big could never be returned. Could + // probably scope this down, but might impact very specific usecases. + constexpr int32_t kMaxAllocationSize = 1 * 1000 * 1000; + + if (allocationSize >= kMaxAllocationSize) { + return NO_MEMORY; + } + + return OK; +} + template<class T> status_t Parcel::readAligned(T *pArg) const { static_assert(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T)); diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h index 5aaaa0c3d2..02052ad77e 100644 --- a/libs/binder/include/binder/Parcel.h +++ b/libs/binder/include/binder/Parcel.h @@ -561,6 +561,8 @@ private: status_t flattenBinder(const sp<IBinder>& binder); status_t unflattenBinder(sp<IBinder>* out) const; + status_t readOutVectorSizeWithCheck(size_t elmSize, int32_t* size) const; + template<class T> status_t readAligned(T *pArg) const; @@ -1315,7 +1317,7 @@ status_t Parcel::writeVectorSize(const std::unique_ptr<std::vector<T>>& val) { template<typename T> status_t Parcel::resizeOutVector(std::vector<T>* val) const { int32_t size; - status_t err = readInt32(&size); + status_t err = readOutVectorSizeWithCheck(sizeof(T), &size); if (err != NO_ERROR) { return err; } @@ -1330,7 +1332,7 @@ status_t Parcel::resizeOutVector(std::vector<T>* val) const { template<typename T> status_t Parcel::resizeOutVector(std::optional<std::vector<T>>* val) const { int32_t size; - status_t err = readInt32(&size); + status_t err = readOutVectorSizeWithCheck(sizeof(T), &size); if (err != NO_ERROR) { return err; } @@ -1346,7 +1348,7 @@ status_t Parcel::resizeOutVector(std::optional<std::vector<T>>* val) const { template<typename T> status_t Parcel::resizeOutVector(std::unique_ptr<std::vector<T>>* val) const { int32_t size; - status_t err = readInt32(&size); + status_t err = readOutVectorSizeWithCheck(sizeof(T), &size); if (err != NO_ERROR) { return err; } diff --git a/libs/binder/tests/parcel_fuzzer/binder.cpp b/libs/binder/tests/parcel_fuzzer/binder.cpp index cbb0a18b6f..5f2c17cdb7 100644 --- a/libs/binder/tests/parcel_fuzzer/binder.cpp +++ b/libs/binder/tests/parcel_fuzzer/binder.cpp @@ -66,6 +66,10 @@ struct ExampleLightFlattenable : public android::LightFlattenablePod<ExampleLigh int32_t mValue = 0; }; +struct BigStruct { + uint8_t data[1337]; +}; + #define PARCEL_READ_WITH_STATUS(T, FUN) \ [] (const ::android::Parcel& p, uint8_t /*data*/) {\ FUZZ_LOG() << "about to read " #T " using " #FUN " with status";\ @@ -231,8 +235,12 @@ std::vector<ParcelRead<::android::Parcel>> BINDER_PARCEL_READ_FUNCTIONS { FUZZ_LOG() << "read lite flattenable: " << status; }, - // TODO(b/131868573): can force read of arbitrarily sized vector - // TODO: resizeOutVector + PARCEL_READ_WITH_STATUS(std::vector<uint8_t>, resizeOutVector), + PARCEL_READ_WITH_STATUS(std::optional<std::vector<uint8_t>>, resizeOutVector), + PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<uint8_t>>, resizeOutVector), + PARCEL_READ_WITH_STATUS(std::vector<BigStruct>, resizeOutVector), + PARCEL_READ_WITH_STATUS(std::optional<std::vector<BigStruct>>, resizeOutVector), + PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<BigStruct>>, resizeOutVector), PARCEL_READ_NO_STATUS(int32_t, readExceptionCode), [] (const android::Parcel& p, uint8_t /*len*/) { |