From 42b62872275ff757b999cf189fe48693c576a282 Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Tue, 14 Feb 2017 17:07:24 -0800 Subject: MPEG4Extractor: ensure returned status is checked. Also fix handling of zero atom size in MPEG4Source::parseChunk. IDataSource: ensure readAt returns correct status. Test: manually test with mediaplayer. Bug: 34718515 Change-Id: I1219ec579aa0876dc1230e36af46b158b84c6d77 (cherry picked from commit ff1fb4d5cdd3b2b28c69edd8cd3021e335ca381a) (cherry picked from commit 371561214467f848496928914f771703d6c331e6) Change-Id: I51546975ac0992cff7cf890a71a177e1058ed613 CVE-2017-0774 --- media/libmedia/IDataSource.cpp | 12 +++++- media/libstagefright/MPEG4Extractor.cpp | 67 +++++++++++++++++++++++++++++---- 2 files changed, 69 insertions(+), 10 deletions(-) diff --git a/media/libmedia/IDataSource.cpp b/media/libmedia/IDataSource.cpp index 76d1d68ef8..a969c7db6e 100644 --- a/media/libmedia/IDataSource.cpp +++ b/media/libmedia/IDataSource.cpp @@ -50,8 +50,16 @@ struct BpDataSource : public BpInterface { data.writeInterfaceToken(IDataSource::getInterfaceDescriptor()); data.writeInt64(offset); data.writeInt64(size); - remote()->transact(READ_AT, data, &reply); - return reply.readInt64(); + status_t err = remote()->transact(READ_AT, data, &reply); + if (err != OK) { + return err; + } + int64_t value = 0; + err = reply.readInt64(&value); + if (err != OK) { + return err; + } + return (ssize_t)value; } virtual status_t getSize(off64_t* size) { diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp index 5d97181034..8c66c29d91 100755 --- a/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/MPEG4Extractor.cpp @@ -67,6 +67,7 @@ public: Vector &sidx, const Trex *trex, off64_t firstMoofOffset); + virtual status_t init(); virtual status_t start(MetaData *params = NULL); virtual status_t stop(); @@ -2046,7 +2047,10 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { *offset += chunk_size; if (underQTMetaPath(mPath, 3)) { - parseQTMetaKey(data_offset, chunk_data_size); + status_t err = parseQTMetaKey(data_offset, chunk_data_size); + if (err != OK) { + return err; + } } break; } @@ -2190,7 +2194,10 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { case FOURCC('s', 'i', 'd', 'x'): { - parseSegmentIndex(data_offset, chunk_data_size); + status_t err = parseSegmentIndex(data_offset, chunk_data_size); + if (err != OK) { + return err; + } *offset += chunk_size; return UNKNOWN_ERROR; // stop parsing after sidx } @@ -2200,7 +2207,10 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { // check if we're parsing 'ilst' for meta keys // if so, treat type as a number (key-id). if (underQTMetaPath(mPath, 3)) { - parseQTMetaVal(chunk_type, data_offset, chunk_data_size); + status_t err = parseQTMetaVal(chunk_type, data_offset, chunk_data_size); + if (err != OK) { + return err; + } } *offset += chunk_size; @@ -2940,9 +2950,13 @@ sp MPEG4Extractor::getTrack(size_t index) { ALOGV("getTrack called, pssh: %zu", mPssh.size()); - return new MPEG4Source(this, + sp source = new MPEG4Source(this, track->meta, mDataSource, track->timescale, track->sampleTable, mSidxEntries, trex, mMoofOffset); + if (source->init() != OK) { + return NULL; + } + return source; } // static @@ -3339,6 +3353,7 @@ MPEG4Source::MPEG4Source( mTrex(trex), mFirstMoofOffset(firstMoofOffset), mCurrentMoofOffset(firstMoofOffset), + mNextMoofOffset(-1), mCurrentTime(0), mCurrentSampleInfoAllocSize(0), mCurrentSampleInfoSizes(NULL), @@ -3405,10 +3420,14 @@ MPEG4Source::MPEG4Source( CHECK(format->findInt32(kKeyTrackID, &mTrackId)); +} + +status_t MPEG4Source::init() { if (mFirstMoofOffset != 0) { off64_t offset = mFirstMoofOffset; - parseChunk(&offset); + return parseChunk(&offset); } + return OK; } MPEG4Source::~MPEG4Source() { @@ -3532,9 +3551,30 @@ status_t MPEG4Source::parseChunk(off64_t *offset) { } chunk_size = ntohl(hdr[0]); chunk_type = ntohl(hdr[1]); + if (chunk_size == 1) { + // ISO/IEC 14496-12:2012, 8.8.4 Movie Fragment Box, moof is a Box + // which is defined in 4.2 Object Structure. + // When chunk_size==1, 8 bytes follows as "largesize". + if (mDataSource->readAt(*offset + 8, &chunk_size, 8) < 8) { + return ERROR_IO; + } + chunk_size = ntoh64(chunk_size); + if (chunk_size < 16) { + // The smallest valid chunk is 16 bytes long in this case. + return ERROR_MALFORMED; + } + } else if (chunk_size == 0) { + // next box extends to end of file. + } else if (chunk_size < 8) { + // The smallest valid chunk is 8 bytes long in this case. + return ERROR_MALFORMED; + } + if (chunk_type == FOURCC('m', 'o', 'o', 'f')) { mNextMoofOffset = *offset; break; + } else if (chunk_size == 0) { + break; } *offset += chunk_size; } @@ -4399,17 +4439,25 @@ status_t MPEG4Source::fragmentedRead( totalOffset += se->mSize; } mCurrentMoofOffset = totalOffset; + mNextMoofOffset = -1; mCurrentSamples.clear(); mCurrentSampleIndex = 0; - parseChunk(&totalOffset); + status_t err = parseChunk(&totalOffset); + if (err != OK) { + return err; + } mCurrentTime = totalTime * mTimescale / 1000000ll; } else { // without sidx boxes, we can only seek to 0 mCurrentMoofOffset = mFirstMoofOffset; + mNextMoofOffset = -1; mCurrentSamples.clear(); mCurrentSampleIndex = 0; off64_t tmp = mCurrentMoofOffset; - parseChunk(&tmp); + status_t err = parseChunk(&tmp); + if (err != OK) { + return err; + } mCurrentTime = 0; } @@ -4438,7 +4486,10 @@ status_t MPEG4Source::fragmentedRead( mCurrentMoofOffset = nextMoof; mCurrentSamples.clear(); mCurrentSampleIndex = 0; - parseChunk(&nextMoof); + status_t err = parseChunk(&nextMoof); + if (err != OK) { + return err; + } if (mCurrentSampleIndex >= mCurrentSamples.size()) { return ERROR_END_OF_STREAM; } -- cgit v1.2.3