Skip to content

Commit

Permalink
Impose a size bound for dynamically allocated tables in stbl.
Browse files Browse the repository at this point in the history
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
(cherry picked from commit 583a012)
  • Loading branch information
Pawin Vongmasa authored and andi34 committed Oct 22, 2016
1 parent 013273d commit 276e314
Show file tree
Hide file tree
Showing 2 changed files with 141 additions and 24 deletions.
156 changes: 134 additions & 22 deletions media/libstagefright/SampleTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ SampleTable::SampleTable(const sp<DataSource> &source)
mNumSampleSizes(0),
mHasTimeToSample(false),
mTimeToSampleCount(0),
mTimeToSample(),
mTimeToSample(NULL),
mSampleTimeEntries(NULL),
mCompositionTimeDeltaEntries(NULL),
mNumCompositionTimeDeltaEntries(0),
Expand All @@ -132,7 +132,8 @@ SampleTable::SampleTable(const sp<DataSource> &source)
mNumSyncSamples(0),
mSyncSamples(NULL),
mLastSyncSampleIndex(0),
mSampleToChunkEntries(NULL) {
mSampleToChunkEntries(NULL),
mTotalSize(0) {
mSampleIterator = new SampleIterator(this);
}

Expand All @@ -143,6 +144,9 @@ SampleTable::~SampleTable() {
delete[] mSyncSamples;
mSyncSamples = NULL;

delete[] mTimeToSample;
mTimeToSample = NULL;

delete mCompositionDeltaLookup;
mCompositionDeltaLookup = NULL;

Expand Down Expand Up @@ -233,11 +237,43 @@ status_t SampleTable::setSampleToChunkParams(
return ERROR_MALFORMED;
}

if (SIZE_MAX / sizeof(SampleToChunkEntry) <= 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 SampleToChunkEntry[mNumSampleToChunkOffsets];
new (std::nothrow) SampleToChunkEntry[mNumSampleToChunkOffsets];
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];
Expand All @@ -246,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;
Expand Down Expand Up @@ -347,20 +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;
Expand Down Expand Up @@ -396,14 +456,31 @@ status_t SampleTable::setCompositionTimeToSampleParams(
mNumCompositionTimeDeltaEntries = numEntries;
uint64_t allocSize = (uint64_t)numEntries * 2 * sizeof(uint32_t);
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 uint32_t[2 * numEntries];
mCompositionTimeDeltaEntries = new (std::nothrow) uint32_t[2 * numEntries];
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;

Expand Down Expand Up @@ -444,15 +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) {
ALOGE("Cannot allocate sync sample table with %llu entries.",
(unsigned long long)mNumSyncSamples);
return ERROR_OUT_OF_RANGE;
}

mSyncSamples = new uint32_t[mNumSyncSamples];
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;
}

Expand Down Expand Up @@ -517,7 +612,24 @@ void SampleTable::buildSampleEntriesTable() {
return;
}

mSampleTimeEntries = new SampleTimeEntry[mNumSampleSizes];
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) {
ALOGE("Cannot allocate sample entry table with %llu entries.",
(unsigned long long)mNumSampleSizes);
return;
}

uint32_t sampleIndex = 0;
uint32_t sampleTime = 0;
Expand Down
9 changes: 7 additions & 2 deletions media/libstagefright/include/SampleTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
#include <media/stagefright/MediaErrors.h>
#include <utils/RefBase.h>
#include <utils/threads.h>
#include <utils/Vector.h>

namespace android {

Expand Down Expand Up @@ -94,6 +93,9 @@ class SampleTable : public RefBase {
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<DataSource> mDataSource;
Mutex mLock;

Expand All @@ -111,7 +113,7 @@ class SampleTable : public RefBase {

bool mHasTimeToSample;
uint32_t mTimeToSampleCount;
Vector<uint32_t> mTimeToSample;
uint32_t* mTimeToSample;

struct SampleTimeEntry {
uint32_t mSampleIndex;
Expand All @@ -137,6 +139,9 @@ class SampleTable : public RefBase {
};
SampleToChunkEntry *mSampleToChunkEntries;

// Approximate size of all tables combined.
uint64_t mTotalSize;

friend struct SampleIterator;

status_t getSampleSize_l(uint32_t sample_index, size_t *sample_size);
Expand Down

0 comments on commit 276e314

Please sign in to comment.