diff options
| author | 2018-04-10 11:01:42 -0700 | |
|---|---|---|
| committer | 2018-04-10 11:01:42 -0700 | |
| commit | c720d6e2bfa35e35b4114f9018359f9976a78def (patch) | |
| tree | 560b9ce0fe67c5ddb80d4d1526f48bddb99f5d2a /libs/binder/Parcel.cpp | |
| parent | c278874239d664985617361483e3a8ec63c508b7 (diff) | |
| parent | e69532fd03e5c83e637b65aba23d8c23ca438a63 (diff) | |
Disallow reading object data from Parcels with non-object reads am: c517681c66
am: e69532fd03
Change-Id: If46b533d0d34ef21f979c50049f3dd8a4339fd67
Diffstat (limited to 'libs/binder/Parcel.cpp')
| -rw-r--r-- | libs/binder/Parcel.cpp | 73 | 
1 files changed, 73 insertions, 0 deletions
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index e22179b15d..44357c3653 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -433,6 +433,7 @@ void Parcel::setDataPosition(size_t pos) const      mDataPos = pos;      mNextObjectHint = 0; +    mObjectsSorted = false;  }  status_t Parcel::setDataCapacity(size_t size) @@ -1469,6 +1470,59 @@ void Parcel::remove(size_t /*start*/, size_t /*amt*/)      LOG_ALWAYS_FATAL("Parcel::remove() not yet implemented!");  } +status_t Parcel::validateReadData(size_t upperBound) const +{ +    // Don't allow non-object reads on object data +    if (mObjectsSorted || mObjectsSize <= 1) { +data_sorted: +        // Expect to check only against the next object +        if (mNextObjectHint < mObjectsSize && upperBound > mObjects[mNextObjectHint]) { +            // For some reason the current read position is greater than the next object +            // hint. Iterate until we find the right object +            size_t nextObject = mNextObjectHint; +            do { +                if (mDataPos < mObjects[nextObject] + sizeof(flat_binder_object)) { +                    // Requested info overlaps with an object +                    ALOGE("Attempt to read from protected data in Parcel %p", this); +                    return PERMISSION_DENIED; +                } +                nextObject++; +            } while (nextObject < mObjectsSize && upperBound > mObjects[nextObject]); +            mNextObjectHint = nextObject; +        } +        return NO_ERROR; +    } +    // Quickly determine if mObjects is sorted. +    binder_size_t* currObj = mObjects + mObjectsSize - 1; +    binder_size_t* prevObj = currObj; +    while (currObj > mObjects) { +        prevObj--; +        if(*prevObj > *currObj) { +            goto data_unsorted; +        } +        currObj--; +    } +    mObjectsSorted = true; +    goto data_sorted; + +data_unsorted: +    // Insertion Sort mObjects +    // Great for mostly sorted lists. If randomly sorted or reverse ordered mObjects become common, +    // switch to std::sort(mObjects, mObjects + mObjectsSize); +    for (binder_size_t* iter0 = mObjects + 1; iter0 < mObjects + mObjectsSize; iter0++) { +        binder_size_t temp = *iter0; +        binder_size_t* iter1 = iter0 - 1; +        while (iter1 >= mObjects && *iter1 > temp) { +            *(iter1 + 1) = *iter1; +            iter1--; +        } +        *(iter1 + 1) = temp; +    } +    mNextObjectHint = 0; +    mObjectsSorted = true; +    goto data_sorted; +} +  status_t Parcel::read(void* outData, size_t len) const  {      if (len > INT32_MAX) { @@ -1479,6 +1533,10 @@ status_t Parcel::read(void* outData, size_t len) const      if ((mDataPos+pad_size(len)) >= mDataPos && (mDataPos+pad_size(len)) <= mDataSize              && len <= pad_size(len)) { +        if (mObjectsSize > 0) { +            status_t err = validateReadData(mDataPos + pad_size(len)); +            if(err != NO_ERROR) return err; +        }          memcpy(outData, mData+mDataPos, len);          mDataPos += pad_size(len);          ALOGV("read Setting data pos of %p to %zu", this, mDataPos); @@ -1497,6 +1555,11 @@ const void* Parcel::readInplace(size_t len) const      if ((mDataPos+pad_size(len)) >= mDataPos && (mDataPos+pad_size(len)) <= mDataSize              && len <= pad_size(len)) { +        if (mObjectsSize > 0) { +            status_t err = validateReadData(mDataPos + pad_size(len)); +            if(err != NO_ERROR) return NULL; +        } +          const void* data = mData+mDataPos;          mDataPos += pad_size(len);          ALOGV("readInplace Setting data pos of %p to %zu", this, mDataPos); @@ -1510,6 +1573,11 @@ status_t Parcel::readAligned(T *pArg) const {      COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T));      if ((mDataPos+sizeof(T)) <= mDataSize) { +        if (mObjectsSize > 0) { +            status_t err = validateReadData(mDataPos + sizeof(T)); +            if(err != NO_ERROR) return err; +        } +          const void* data = mData+mDataPos;          mDataPos += sizeof(T);          *pArg =  *reinterpret_cast<const T*>(data); @@ -2366,6 +2434,7 @@ void Parcel::ipcSetDataReference(const uint8_t* data, size_t dataSize,      mObjects = const_cast<binder_size_t*>(objects);      mObjectsSize = mObjectsCapacity = objectsCount;      mNextObjectHint = 0; +    mObjectsSorted = false;      mOwner = relFunc;      mOwnerCookie = relCookie;      for (size_t i = 0; i < mObjectsSize; i++) { @@ -2524,6 +2593,7 @@ status_t Parcel::restartWrite(size_t desired)      mObjects = NULL;      mObjectsSize = mObjectsCapacity = 0;      mNextObjectHint = 0; +    mObjectsSorted = false;      mHasFds = false;      mFdsKnown = true;      mAllowFds = true; @@ -2610,6 +2680,7 @@ status_t Parcel::continueWrite(size_t desired)          mDataCapacity = desired;          mObjectsSize = mObjectsCapacity = objectsSize;          mNextObjectHint = 0; +        mObjectsSorted = false;      } else if (mData) {          if (objectsSize < mObjectsSize) { @@ -2631,6 +2702,7 @@ status_t Parcel::continueWrite(size_t desired)              }              mObjectsSize = objectsSize;              mNextObjectHint = 0; +            mObjectsSorted = false;          }          // We own the data, so we can just do a realloc(). @@ -2703,6 +2775,7 @@ void Parcel::initState()      mObjectsSize = 0;      mObjectsCapacity = 0;      mNextObjectHint = 0; +    mObjectsSorted = false;      mHasFds = false;      mFdsKnown = true;      mAllowFds = true;  |