diff options
Diffstat (limited to 'libs')
| -rw-r--r-- | libs/binder/Parcel.cpp | 31 | ||||
| -rw-r--r-- | libs/binder/include/binder/Parcel.h | 24 |
2 files changed, 44 insertions, 11 deletions
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index 9bba369ee4..8087443720 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -1477,6 +1477,31 @@ data_unsorted: goto data_sorted; } +status_t Parcel::readVectorSizeWithCoarseBoundCheck(int32_t *size) const { + int32_t requestedSize; + const status_t status = readInt32(&requestedSize); + if (status != NO_ERROR) return status; + + // We permit negative sizes, which indicate presence of a nullable vector, + // i.e. a vector embedded in std::optional, std::unique_ptr, or std::shared_ptr. + if (requestedSize > 0) { + // Check if there are fewer bytes than vector elements. + // A lower bound is 1 byte per element, satisfied by some enum and int8_t and uint8_t. + const size_t availableBytes = dataAvail(); + if (static_cast<size_t>(requestedSize) > availableBytes) { + // We have a size that is greater than the number of bytes available. + // On bounds failure we do not 'rewind' position by 4 bytes of the size already read. + ALOGW("%s: rejecting out of bounds vector size (requestedSize):%d " + "Parcel{dataAvail:%zu mDataSize:%zu mDataPos:%zu mDataCapacity:%zu}", + __func__, requestedSize, availableBytes, mDataSize, mDataPos, mDataCapacity); + return BAD_VALUE; + } + } + + *size = requestedSize; + return NO_ERROR; +} + status_t Parcel::read(void* outData, size_t len) const { if (len > INT32_MAX) { @@ -1699,7 +1724,7 @@ status_t Parcel::readDoubleVector(std::vector<double>* val) const { status_t Parcel::readBoolVector(std::optional<std::vector<bool>>* val) const { const int32_t start = dataPosition(); int32_t size; - status_t status = readInt32(&size); + status_t status = readVectorSizeWithCoarseBoundCheck(&size); val->reset(); if (status != OK || size < 0) { @@ -1721,7 +1746,7 @@ status_t Parcel::readBoolVector(std::optional<std::vector<bool>>* val) const { status_t Parcel::readBoolVector(std::unique_ptr<std::vector<bool>>* val) const { const int32_t start = dataPosition(); int32_t size; - status_t status = readInt32(&size); + status_t status = readVectorSizeWithCoarseBoundCheck(&size); val->reset(); if (status != OK || size < 0) { @@ -1742,7 +1767,7 @@ status_t Parcel::readBoolVector(std::unique_ptr<std::vector<bool>>* val) const { status_t Parcel::readBoolVector(std::vector<bool>* val) const { int32_t size; - status_t status = readInt32(&size); + status_t status = readVectorSizeWithCoarseBoundCheck(&size); if (status != OK) { return status; diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h index b49951b448..54c49e4c0c 100644 --- a/libs/binder/include/binder/Parcel.h +++ b/libs/binder/include/binder/Parcel.h @@ -517,6 +517,11 @@ private: void initState(); void scanForFds() const; status_t validateReadData(size_t len) const; + + // Reads an int32 size and does a coarse bounds check against the number + // of available bytes in the Parcel. + status_t readVectorSizeWithCoarseBoundCheck(int32_t *size) const; + void updateWorkSourceRequestHeaderPosition() const; status_t finishFlattenBinder(const sp<IBinder>& binder); @@ -787,6 +792,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; + // used for allocating 'out' vector args, do not use readVectorSizeWithCoarseBoundCheck() here status_t err = readInt32(&size); if (err != NO_ERROR) { return err; @@ -802,6 +808,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; + // used for allocating 'out' vector args, do not use readVectorSizeWithCoarseBoundCheck() here status_t err = readInt32(&size); if (err != NO_ERROR) { return err; @@ -818,6 +825,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; + // used for allocating 'out' vector args, do not use readVectorSizeWithCoarseBoundCheck() here status_t err = readInt32(&size); if (err != NO_ERROR) { return err; @@ -834,7 +842,7 @@ status_t Parcel::resizeOutVector(std::unique_ptr<std::vector<T>>* val) const { template<typename T> status_t Parcel::reserveOutVector(std::vector<T>* val, size_t* size) const { int32_t read_size; - status_t err = readInt32(&read_size); + status_t err = readVectorSizeWithCoarseBoundCheck(&read_size); if (err != NO_ERROR) { return err; } @@ -850,7 +858,7 @@ status_t Parcel::reserveOutVector(std::vector<T>* val, size_t* size) const { template<typename T> status_t Parcel::reserveOutVector(std::optional<std::vector<T>>* val, size_t* size) const { int32_t read_size; - status_t err = readInt32(&read_size); + status_t err = readVectorSizeWithCoarseBoundCheck(&read_size); if (err != NO_ERROR) { return err; } @@ -870,7 +878,7 @@ template<typename T> status_t Parcel::reserveOutVector(std::unique_ptr<std::vector<T>>* val, size_t* size) const { int32_t read_size; - status_t err = readInt32(&read_size); + status_t err = readVectorSizeWithCoarseBoundCheck(&read_size); if (err != NO_ERROR) { return err; } @@ -923,7 +931,7 @@ status_t Parcel::unsafeReadTypedVector( std::vector<T>* val, status_t(Parcel::*read_func)(U*) const) const { int32_t size; - status_t status = this->readInt32(&size); + status_t status = this->readVectorSizeWithCoarseBoundCheck(&size); if (status != OK) { return status; @@ -965,7 +973,7 @@ status_t Parcel::readNullableTypedVector(std::optional<std::vector<T>>* val, status_t(Parcel::*read_func)(T*) const) const { const size_t start = dataPosition(); int32_t size; - status_t status = readInt32(&size); + status_t status = readVectorSizeWithCoarseBoundCheck(&size); val->reset(); if (status != OK || size < 0) { @@ -989,7 +997,7 @@ status_t Parcel::readNullableTypedVector(std::unique_ptr<std::vector<T>>* val, status_t(Parcel::*read_func)(T*) const) const { const size_t start = dataPosition(); int32_t size; - status_t status = readInt32(&size); + status_t status = readVectorSizeWithCoarseBoundCheck(&size); val->reset(); if (status != OK || size < 0) { @@ -1093,7 +1101,7 @@ template<typename T> status_t Parcel::readParcelableVector(std::optional<std::vector<std::optional<T>>>* val) const { const size_t start = dataPosition(); int32_t size; - status_t status = readInt32(&size); + status_t status = readVectorSizeWithCoarseBoundCheck(&size); val->reset(); if (status != OK || size < 0) { @@ -1117,7 +1125,7 @@ template<typename T> status_t Parcel::readParcelableVector(std::unique_ptr<std::vector<std::unique_ptr<T>>>* val) const { const size_t start = dataPosition(); int32_t size; - status_t status = readInt32(&size); + status_t status = readVectorSizeWithCoarseBoundCheck(&size); val->reset(); if (status != OK || size < 0) { |