From ec35db991ffaff26de8b63ddcd8e85512e13d154 Mon Sep 17 00:00:00 2001 From: Dichen Zhang Date: Fri, 3 Apr 2020 17:39:23 -0700 Subject: [PATCH] add chunk size as restriction for function parseClearEncryptedSizes() Without trunksize as restriction, function parseClearEncryptedSized() can read the rest of file. If the file has a large number of saiz trunk, large number of bytes will be copied, which can lead to high cost of CPU time. Bug: 124777526 Test: please see #3 and #8 in b/124777526: push senc.mp4 to devices's sdcard, play with photo app, manuly print log. Also need to verify if Dexter app (b/152531488) not crash. Change-Id: I87f215cf04c5d002076e145f21c10556773f4bb2 --- media/extractors/mp4/MPEG4Extractor.cpp | 43 +++++++++++++++++++------ 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp index aea28c0386..54f1fa2296 100755 --- a/media/extractors/mp4/MPEG4Extractor.cpp +++ b/media/extractors/mp4/MPEG4Extractor.cpp @@ -113,6 +113,7 @@ private: const Trex *mTrex; off64_t mFirstMoofOffset; off64_t mCurrentMoofOffset; + off64_t mCurrentMoofSize; off64_t mNextMoofOffset; uint32_t mCurrentTime; // in media timescale ticks int32_t mLastParsedTrackId; @@ -165,8 +166,9 @@ private: status_t parseTrackFragmentRun(off64_t offset, off64_t size); status_t parseSampleAuxiliaryInformationSizes(off64_t offset, off64_t size); status_t parseSampleAuxiliaryInformationOffsets(off64_t offset, off64_t size); - status_t parseClearEncryptedSizes(off64_t offset, bool isSubsampleEncryption, uint32_t flags); - status_t parseSampleEncryption(off64_t offset); + status_t parseClearEncryptedSizes(off64_t offset, bool isSampleEncryption, + uint32_t flags, off64_t size); + status_t parseSampleEncryption(off64_t offset, off64_t size); // returns -1 for invalid layer ID int32_t parseHEVCLayerId(const uint8_t *data, size_t size); @@ -4859,6 +4861,7 @@ MPEG4Source::MPEG4Source( mTrex(trex), mFirstMoofOffset(firstMoofOffset), mCurrentMoofOffset(firstMoofOffset), + mCurrentMoofSize(0), mNextMoofOffset(-1), mCurrentTime(0), mDefaultEncryptedByteBlock(0), @@ -5109,6 +5112,9 @@ status_t MPEG4Source::parseChunk(off64_t *offset) { case FOURCC("moof"): { off64_t stop_offset = *offset + chunk_size; *offset = data_offset; + if (chunk_type == FOURCC("moof")) { + mCurrentMoofSize = chunk_data_size; + } while (*offset < stop_offset) { status_t err = parseChunk(offset); if (err != OK) { @@ -5197,7 +5203,7 @@ status_t MPEG4Source::parseChunk(off64_t *offset) { case FOURCC("senc"): { status_t err; - if ((err = parseSampleEncryption(data_offset)) != OK) { + if ((err = parseSampleEncryption(data_offset, chunk_data_size)) != OK) { return err; } *offset += chunk_size; @@ -5390,11 +5396,11 @@ status_t MPEG4Source::parseSampleAuxiliaryInformationOffsets( drmoffset += mCurrentMoofOffset; - return parseClearEncryptedSizes(drmoffset, false, 0); + return parseClearEncryptedSizes(drmoffset, false, 0, mCurrentMoofSize); } status_t MPEG4Source::parseClearEncryptedSizes( - off64_t offset, bool isSubsampleEncryption, uint32_t flags) { + off64_t offset, bool isSampleEncryption, uint32_t flags, off64_t size) { int32_t ivlength; if (!AMediaFormat_getInt32(mFormat, AMEDIAFORMAT_KEY_CRYPTO_DEFAULT_IV_SIZE, &ivlength)) { @@ -5408,11 +5414,15 @@ status_t MPEG4Source::parseClearEncryptedSizes( } uint32_t sampleCount = mCurrentSampleInfoCount; - if (isSubsampleEncryption) { + if (isSampleEncryption) { + if (size < 4) { + return ERROR_MALFORMED; + } if (!mDataSource->getUInt32(offset, &sampleCount)) { return ERROR_IO; } offset += 4; + size -= 4; } // read CencSampleAuxiliaryDataFormats @@ -5427,14 +5437,18 @@ status_t MPEG4Source::parseClearEncryptedSizes( } memset(smpl->iv, 0, 16); + if (size < ivlength) { + return ERROR_MALFORMED; + } if (mDataSource->readAt(offset, smpl->iv, ivlength) != ivlength) { return ERROR_IO; } offset += ivlength; + size -= ivlength; bool readSubsamples; - if (isSubsampleEncryption) { + if (isSampleEncryption) { readSubsamples = flags & 2; } else { int32_t smplinfosize = mCurrentDefaultSampleInfoSize; @@ -5446,13 +5460,20 @@ status_t MPEG4Source::parseClearEncryptedSizes( if (readSubsamples) { uint16_t numsubsamples; + if (size < 2) { + return ERROR_MALFORMED; + } if (!mDataSource->getUInt16(offset, &numsubsamples)) { return ERROR_IO; } offset += 2; + size -= 2; for (size_t j = 0; j < numsubsamples; j++) { uint16_t numclear; uint32_t numencrypted; + if (size < 6) { + return ERROR_MALFORMED; + } if (!mDataSource->getUInt16(offset, &numclear)) { return ERROR_IO; } @@ -5461,6 +5482,7 @@ status_t MPEG4Source::parseClearEncryptedSizes( return ERROR_IO; } offset += 4; + size -= 6; smpl->clearsizes.add(numclear); smpl->encryptedsizes.add(numencrypted); } @@ -5473,12 +5495,15 @@ status_t MPEG4Source::parseClearEncryptedSizes( return OK; } -status_t MPEG4Source::parseSampleEncryption(off64_t offset) { +status_t MPEG4Source::parseSampleEncryption(off64_t offset, off64_t chunk_data_size) { uint32_t flags; + if (chunk_data_size < 4) { + return ERROR_MALFORMED; + } if (!mDataSource->getUInt32(offset, &flags)) { // actually version + flags return ERROR_MALFORMED; } - return parseClearEncryptedSizes(offset + 4, true, flags); + return parseClearEncryptedSizes(offset + 4, true, flags, chunk_data_size - 4); } status_t MPEG4Source::parseTrackFragmentHeader(off64_t offset, off64_t size) {