From 2bef075f91e203e96130c88320b7d13eddc17d89 Mon Sep 17 00:00:00 2001 From: Pawin Vongmasa Date: Tue, 21 Jun 2016 19:10:21 -0700 Subject: Impose a size bound for dynamically allocated tables in stbl. Impose a restriction of 200MiB for tables in stsc, stts, ctts and stss boxes. Also change mTimeToSample from Vector to array. Bug: 29367429 Change-Id: I953bea9fe0590268cf27376740f582dc88563d42 Merge conflict resolution of ag/1170200 to mnc-mr2-release --- media/libstagefright/SampleTable.cpp | 150 ++++++++++++++++++++++++----- media/libstagefright/include/SampleTable.h | 9 +- 2 files changed, 133 insertions(+), 26 deletions(-) (limited to 'media/libstagefright') diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp index 8df9cb8..bc01a2d 100644 --- a/media/libstagefright/SampleTable.cpp +++ b/media/libstagefright/SampleTable.cpp @@ -123,7 +123,7 @@ SampleTable::SampleTable(const sp &source) mNumSampleSizes(0), mHasTimeToSample(false), mTimeToSampleCount(0), - mTimeToSample(), + mTimeToSample(NULL), mSampleTimeEntries(NULL), mCompositionTimeDeltaEntries(NULL), mNumCompositionTimeDeltaEntries(0), @@ -132,7 +132,8 @@ SampleTable::SampleTable(const sp &source) mNumSyncSamples(0), mSyncSamples(NULL), mLastSyncSampleIndex(0), - mSampleToChunkEntries(NULL) { + mSampleToChunkEntries(NULL), + mTotalSize(0) { mSampleIterator = new SampleIterator(this); } @@ -143,6 +144,9 @@ SampleTable::~SampleTable() { delete[] mSyncSamples; mSyncSamples = NULL; + delete[] mTimeToSample; + mTimeToSample = NULL; + delete mCompositionDeltaLookup; mCompositionDeltaLookup = NULL; @@ -233,13 +237,43 @@ status_t SampleTable::setSampleToChunkParams( return ERROR_MALFORMED; } - if (SIZE_MAX / sizeof(SampleToChunkEntry) <= (size_t)mNumSampleToChunkOffsets) + if ((uint64_t)SIZE_MAX / sizeof(SampleToChunkEntry) <= + (uint64_t)mNumSampleToChunkOffsets) { + ALOGE("Sample-to-chunk table size too large."); return ERROR_OUT_OF_RANGE; + } + + mTotalSize += (uint64_t)mNumSampleToChunkOffsets * + sizeof(SampleToChunkEntry); + if (mTotalSize > kMaxTotalSize) { + ALOGE("Sample-to-chunk table size would make sample table too large.\n" + " Requested sample-to-chunk table size = %llu\n" + " Eventual sample table size >= %llu\n" + " Allowed sample table size = %llu\n", + (unsigned long long)mNumSampleToChunkOffsets * + sizeof(SampleToChunkEntry), + (unsigned long long)mTotalSize, + (unsigned long long)kMaxTotalSize); + return ERROR_OUT_OF_RANGE; + } mSampleToChunkEntries = new (std::nothrow) SampleToChunkEntry[mNumSampleToChunkOffsets]; - if (!mSampleToChunkEntries) + if (!mSampleToChunkEntries) { + ALOGE("Cannot allocate sample-to-chunk table with %llu entries.", + (unsigned long long)mNumSampleToChunkOffsets); return ERROR_OUT_OF_RANGE; + } + + if (mNumSampleToChunkOffsets == 0) { + return OK; + } + + if ((off64_t)(SIZE_MAX - 8 - + ((mNumSampleToChunkOffsets - 1) * sizeof(SampleToChunkEntry))) + < mSampleToChunkOffset) { + return ERROR_MALFORMED; + } for (uint32_t i = 0; i < mNumSampleToChunkOffsets; ++i) { uint8_t buffer[12]; @@ -248,8 +282,11 @@ status_t SampleTable::setSampleToChunkParams( != (ssize_t)sizeof(buffer)) { return ERROR_IO; } - - CHECK(U32_AT(buffer) >= 1); // chunk index is 1 based in the spec. + // chunk index is 1 based in the spec. + if (U32_AT(buffer) < 1) { + ALOGE("b/23534160"); + return ERROR_OUT_OF_RANGE; + } // We want the chunk index to be 0-based. mSampleToChunkEntries[i].startChunk = U32_AT(buffer) - 1; @@ -349,21 +386,41 @@ status_t SampleTable::setTimeToSampleParams( // 2) mTimeToSampleCount is the number of entries of the time-to-sample // table. // 3) We hope that the table size does not exceed UINT32_MAX. - ALOGE(" Error: Time-to-sample table size too large."); - + ALOGE("Time-to-sample table size too large."); return ERROR_OUT_OF_RANGE; } // Note: At this point, we know that mTimeToSampleCount * 2 will not // overflow because of the above condition. - if (!mDataSource->getVector(data_offset + 8, &mTimeToSample, - mTimeToSampleCount * 2)) { - ALOGE(" Error: Incomplete data read for time-to-sample table."); + + uint64_t allocSize = (uint64_t)mTimeToSampleCount * 2 * sizeof(uint32_t); + mTotalSize += allocSize; + if (mTotalSize > kMaxTotalSize) { + ALOGE("Time-to-sample table size would make sample table too large.\n" + " Requested time-to-sample table size = %llu\n" + " Eventual sample table size >= %llu\n" + " Allowed sample table size = %llu\n", + (unsigned long long)allocSize, + (unsigned long long)mTotalSize, + (unsigned long long)kMaxTotalSize); + return ERROR_OUT_OF_RANGE; + } + + mTimeToSample = new (std::nothrow) uint32_t[mTimeToSampleCount * 2]; + if (!mTimeToSample) { + ALOGE("Cannot allocate time-to-sample table with %llu entries.", + (unsigned long long)mTimeToSampleCount); + return ERROR_OUT_OF_RANGE; + } + + if (mDataSource->readAt(data_offset + 8, mTimeToSample, + (size_t)allocSize) < (ssize_t)allocSize) { + ALOGE("Incomplete data read for time-to-sample table."); return ERROR_IO; } - for (size_t i = 0; i < mTimeToSample.size(); ++i) { - mTimeToSample.editItemAt(i) = ntohl(mTimeToSample[i]); + for (size_t i = 0; i < mTimeToSampleCount * 2; ++i) { + mTimeToSample[i] = ntohl(mTimeToSample[i]); } mHasTimeToSample = true; @@ -398,17 +455,32 @@ status_t SampleTable::setCompositionTimeToSampleParams( mNumCompositionTimeDeltaEntries = numEntries; uint64_t allocSize = (uint64_t)numEntries * 2 * sizeof(uint32_t); - if (allocSize > UINT32_MAX) { + if (allocSize > SIZE_MAX) { + ALOGE("Composition-time-to-sample table size too large."); + return ERROR_OUT_OF_RANGE; + } + + mTotalSize += allocSize; + if (mTotalSize > kMaxTotalSize) { + ALOGE("Composition-time-to-sample table would make sample table too large.\n" + " Requested composition-time-to-sample table size = %llu\n" + " Eventual sample table size >= %llu\n" + " Allowed sample table size = %llu\n", + (unsigned long long)allocSize, + (unsigned long long)mTotalSize, + (unsigned long long)kMaxTotalSize); return ERROR_OUT_OF_RANGE; } mCompositionTimeDeltaEntries = new (std::nothrow) uint32_t[2 * numEntries]; - if (!mCompositionTimeDeltaEntries) + if (!mCompositionTimeDeltaEntries) { + ALOGE("Cannot allocate composition-time-to-sample table with %llu " + "entries.", (unsigned long long)numEntries); return ERROR_OUT_OF_RANGE; + } - if (mDataSource->readAt( - data_offset + 8, mCompositionTimeDeltaEntries, numEntries * 8) - < (ssize_t)numEntries * 8) { + if (mDataSource->readAt(data_offset + 8, mCompositionTimeDeltaEntries, + (size_t)allocSize) < (ssize_t)allocSize) { delete[] mCompositionTimeDeltaEntries; mCompositionTimeDeltaEntries = NULL; @@ -449,18 +521,33 @@ status_t SampleTable::setSyncSampleParams(off64_t data_offset, size_t data_size) ALOGV("Table of sync samples is empty or has only a single entry!"); } - uint64_t allocSize = mNumSyncSamples * (uint64_t)sizeof(uint32_t); + uint64_t allocSize = (uint64_t)mNumSyncSamples * sizeof(uint32_t); if (allocSize > SIZE_MAX) { + ALOGE("Sync sample table size too large."); + return ERROR_OUT_OF_RANGE; + } + + mTotalSize += allocSize; + if (mTotalSize > kMaxTotalSize) { + ALOGE("Sync sample table size would make sample table too large.\n" + " Requested sync sample table size = %llu\n" + " Eventual sample table size >= %llu\n" + " Allowed sample table size = %llu\n", + (unsigned long long)allocSize, + (unsigned long long)mTotalSize, + (unsigned long long)kMaxTotalSize); return ERROR_OUT_OF_RANGE; } mSyncSamples = new (std::nothrow) uint32_t[mNumSyncSamples]; - if (!mSyncSamples) + if (!mSyncSamples) { + ALOGE("Cannot allocate sync sample table with %llu entries.", + (unsigned long long)mNumSyncSamples); return ERROR_OUT_OF_RANGE; + } - size_t size = mNumSyncSamples * sizeof(uint32_t); - if (mDataSource->readAt(mSyncSampleOffset + 8, mSyncSamples, size) - != (ssize_t)size) { + if (mDataSource->readAt(mSyncSampleOffset + 8, mSyncSamples, + (size_t)allocSize) != (ssize_t)allocSize) { return ERROR_IO; } @@ -525,9 +612,24 @@ void SampleTable::buildSampleEntriesTable() { return; } + mTotalSize += (uint64_t)mNumSampleSizes * sizeof(SampleTimeEntry); + if (mTotalSize > kMaxTotalSize) { + ALOGE("Sample entry table size would make sample table too large.\n" + " Requested sample entry table size = %llu\n" + " Eventual sample table size >= %llu\n" + " Allowed sample table size = %llu\n", + (unsigned long long)mNumSampleSizes * sizeof(SampleTimeEntry), + (unsigned long long)mTotalSize, + (unsigned long long)kMaxTotalSize); + return; + } + mSampleTimeEntries = new (std::nothrow) SampleTimeEntry[mNumSampleSizes]; - if (!mSampleTimeEntries) + if (!mSampleTimeEntries) { + ALOGE("Cannot allocate sample entry table with %llu entries.", + (unsigned long long)mNumSampleSizes); return; + } uint32_t sampleIndex = 0; uint32_t sampleTime = 0; diff --git a/media/libstagefright/include/SampleTable.h b/media/libstagefright/include/SampleTable.h index 465f37c..552eef7 100644 --- a/media/libstagefright/include/SampleTable.h +++ b/media/libstagefright/include/SampleTable.h @@ -24,7 +24,6 @@ #include #include #include -#include namespace android { @@ -96,6 +95,9 @@ private: static const uint32_t kSampleSizeType32; static const uint32_t kSampleSizeTypeCompact; + // Limit the total size of all internal tables to 200MiB. + static const size_t kMaxTotalSize = 200 * (1 << 20); + sp mDataSource; Mutex mLock; @@ -113,7 +115,7 @@ private: bool mHasTimeToSample; uint32_t mTimeToSampleCount; - Vector mTimeToSample; + uint32_t* mTimeToSample; struct SampleTimeEntry { uint32_t mSampleIndex; @@ -139,6 +141,9 @@ private: }; SampleToChunkEntry *mSampleToChunkEntries; + // Approximate size of all tables combined. + uint64_t mTotalSize; + friend struct SampleIterator; // normally we don't round -- cgit v1.1