diff options
Diffstat (limited to 'media/libstagefright/SampleTable.cpp')
-rw-r--r-- | media/libstagefright/SampleTable.cpp | 187 |
1 files changed, 150 insertions, 37 deletions
diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp index ee5def5..8a38c24 100644 --- a/media/libstagefright/SampleTable.cpp +++ b/media/libstagefright/SampleTable.cpp @@ -18,6 +18,8 @@ //#define LOG_NDEBUG 0 #include <utils/Log.h> +#include <limits> + #include "include/SampleTable.h" #include "include/SampleIterator.h" @@ -27,11 +29,6 @@ #include <media/stagefright/DataSource.h> #include <media/stagefright/Utils.h> -/* TODO: remove after being merged into other branches */ -#ifndef UINT32_MAX -#define UINT32_MAX (4294967295U) -#endif - namespace android { // static @@ -45,6 +42,8 @@ const uint32_t SampleTable::kSampleSizeTypeCompact = FOURCC('s', 't', 'z', '2'); //////////////////////////////////////////////////////////////////////////////// +const off64_t kMaxOffset = std::numeric_limits<off64_t>::max(); + struct SampleTable::CompositionDeltaLookup { CompositionDeltaLookup(); @@ -121,6 +120,7 @@ SampleTable::SampleTable(const sp<DataSource> &source) mSampleSizeFieldSize(0), mDefaultSampleSize(0), mNumSampleSizes(0), + mHasTimeToSample(false), mTimeToSampleCount(0), mTimeToSample(NULL), mSampleTimeEntries(NULL), @@ -131,7 +131,8 @@ SampleTable::SampleTable(const sp<DataSource> &source) mNumSyncSamples(0), mSyncSamples(NULL), mLastSyncSampleIndex(0), - mSampleToChunkEntries(NULL) { + mSampleToChunkEntries(NULL), + mTotalSize(0) { mSampleIterator = new SampleIterator(this); } @@ -142,6 +143,9 @@ SampleTable::~SampleTable() { delete[] mSyncSamples; mSyncSamples = NULL; + delete[] mTimeToSample; + mTimeToSample = NULL; + delete mCompositionDeltaLookup; mCompositionDeltaLookup = NULL; @@ -151,9 +155,6 @@ SampleTable::~SampleTable() { delete[] mSampleTimeEntries; mSampleTimeEntries = NULL; - delete[] mTimeToSample; - mTimeToSample = NULL; - delete mSampleIterator; mSampleIterator = NULL; } @@ -162,7 +163,7 @@ bool SampleTable::isValid() const { return mChunkOffsetOffset >= 0 && mSampleToChunkOffset >= 0 && mSampleSizeOffset >= 0 - && mTimeToSample != NULL; + && mHasTimeToSample; } status_t SampleTable::setChunkOffsetParams( @@ -209,6 +210,11 @@ status_t SampleTable::setChunkOffsetParams( status_t SampleTable::setSampleToChunkParams( off64_t data_offset, size_t data_size) { if (mSampleToChunkOffset >= 0) { + // already set + return ERROR_MALFORMED; + } + + if (data_offset < 0) { return ERROR_MALFORMED; } @@ -231,32 +237,67 @@ status_t SampleTable::setSampleToChunkParams( mNumSampleToChunkOffsets = U32_AT(&header[4]); - if ((data_size - 8) / 12 < mNumSampleToChunkOffsets) { + if ((data_size - 8) / sizeof(SampleToChunkEntry) < mNumSampleToChunkOffsets) { return ERROR_MALFORMED; } - if (SIZE_MAX / sizeof(SampleToChunkEntry) <= (size_t)mNumSampleToChunkOffsets) + if ((uint64_t)kMaxTotalSize / 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)(kMaxOffset - 8 - + ((mNumSampleToChunkOffsets - 1) * sizeof(SampleToChunkEntry))) + < mSampleToChunkOffset) { + return ERROR_MALFORMED; + } for (uint32_t i = 0; i < mNumSampleToChunkOffsets; ++i) { - uint8_t buffer[12]; + uint8_t buffer[sizeof(SampleToChunkEntry)]; - if ((off64_t)(INT64_MAX - 8 - (i * 12)) < mSampleToChunkOffset) { + if ((SIZE_MAX - 8 - (i * 12)) < (size_t)mSampleToChunkOffset) { return ERROR_MALFORMED; } if (mDataSource->readAt( - mSampleToChunkOffset + 8 + i * 12, buffer, sizeof(buffer)) + mSampleToChunkOffset + 8 + i * sizeof(SampleToChunkEntry), + buffer, + sizeof(buffer)) != (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; @@ -332,7 +373,7 @@ status_t SampleTable::setSampleSizeParams( status_t SampleTable::setTimeToSampleParams( off64_t data_offset, size_t data_size) { - if (mTimeToSample != NULL || data_size < 8) { + if (mHasTimeToSample || data_size < 8) { return ERROR_MALFORMED; } @@ -348,24 +389,51 @@ status_t SampleTable::setTimeToSampleParams( } mTimeToSampleCount = U32_AT(&header[4]); + if (mTimeToSampleCount > UINT32_MAX / (2 * sizeof(uint32_t))) { + // Choose this bound because + // 1) 2 * sizeof(uint32_t) is the amount of memory needed for one + // time-to-sample entry in the time-to-sample table. + // 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("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. + uint64_t allocSize = (uint64_t)mTimeToSampleCount * 2 * sizeof(uint32_t); - if (allocSize > UINT32_MAX) { + 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) + if (!mTimeToSample) { + ALOGE("Cannot allocate time-to-sample table with %llu entries.", + (unsigned long long)mTimeToSampleCount); return ERROR_OUT_OF_RANGE; + } - size_t size = sizeof(uint32_t) * mTimeToSampleCount * 2; - if (mDataSource->readAt( - data_offset + 8, mTimeToSample, size) < (ssize_t)size) { + 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 (uint32_t i = 0; i < mTimeToSampleCount * 2; ++i) { + for (size_t i = 0; i < mTimeToSampleCount * 2; ++i) { mTimeToSample[i] = ntohl(mTimeToSample[i]); } + mHasTimeToSample = true; return OK; } @@ -397,17 +465,32 @@ status_t SampleTable::setCompositionTimeToSampleParams( mNumCompositionTimeDeltaEntries = numEntries; uint64_t allocSize = (uint64_t)numEntries * 2 * sizeof(uint32_t); - if (allocSize > UINT32_MAX) { + if (allocSize > kMaxTotalSize) { + 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; @@ -448,18 +531,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); - if (allocSize > SIZE_MAX) { + uint64_t allocSize = (uint64_t)mNumSyncSamples * sizeof(uint32_t); + if (allocSize > kMaxTotalSize) { + 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; } @@ -524,9 +622,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; |