Commit message: None
CVE: CVE-2017-0820
Vulnerability description: A vulnerability in the Android media framework (n/a). Product: Android. Versions: 7.0, 7.1.1, 7.1.2, 8.0. Android ID: A-62187433.

Project: Android

MPEG4Source::MPEG4Source(
 const sp<MPEG4Extractor> &owner,
 const sp<MetaData> &format,
 const sp<DataSource> &dataSource,
 int32_t timeScale,
 const sp<SampleTable> &sampleTable,
 Vector<SidxEntry> &sidx,
 const Trex *trex,
 off64_t firstMoofOffset)
 : mOwner(owner),
      mFormat(format),
      mDataSource(dataSource),
      mTimescale(timeScale),
      mSampleTable(sampleTable),
      mCurrentSampleIndex(0),
      mCurrentFragmentIndex(0),
      mSegments(sidx),
      mTrex(trex),
      mFirstMoofOffset(firstMoofOffset),
      mCurrentMoofOffset(firstMoofOffset),
      mNextMoofOffset(-1),
      mCurrentTime(0),
      mCurrentSampleInfoAllocSize(0),
      mCurrentSampleInfoSizes(NULL),
      mCurrentSampleInfoOffsetsAllocSize(0),
      mCurrentSampleInfoOffsets(NULL),
      mIsAVC(false),
      mIsHEVC(false),
      mNALLengthSize(0),
      mStarted(false),
      mGroup(NULL),
      mBuffer(NULL),
      mWantsNALFragments(false),
      mSrcBuffer(NULL) {

    memset(&mTrackFragmentHeaderInfo, 0, sizeof(mTrackFragmentHeaderInfo));

    mFormat->findInt32(kKeyCryptoMode, &mCryptoMode);
    mDefaultIVSize = 0;
    mFormat->findInt32(kKeyCryptoDefaultIVSize, &mDefaultIVSize);
 uint32_t keytype;
 const void *key;
 size_t keysize;
 if (mFormat->findData(kKeyCryptoKey, &keytype, &key, &keysize)) {
        CHECK(keysize <= 16);
        memset(mCryptoKey, 0, 16);
        memcpy(mCryptoKey, key, keysize);
 }

 const char *mime;
 bool success = mFormat->findCString(kKeyMIMEType, &mime);
    CHECK(success);

    mIsAVC = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
    mIsHEVC = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC);

 if (mIsAVC) {
 uint32_t type;
 const void *data;
 size_t size;
        CHECK(format->findData(kKeyAVCC, &type, &data, &size));

 const uint8_t *ptr = (const uint8_t *)data;

        CHECK(size >= 7);
        CHECK_EQ((unsigned)ptr[0], 1u); // configurationVersion == 1

        mNALLengthSize = 1 + (ptr[4] & 3);
 } else if (mIsHEVC) {
 uint32_t type;
 const void *data;
 size_t size;
        CHECK(format->findData(kKeyHVCC, &type, &data, &size));

 const uint8_t *ptr = (const uint8_t *)data;

        CHECK(size >= 22);
        CHECK_EQ((unsigned)ptr[0], 1u); // configurationVersion == 1

        mNALLengthSize = 1 + (ptr[14 + 7] & 3);
 }

    CHECK(format->findInt32(kKeyTrackID, &mTrackId));

}

Project: Android

status_t MPEG4Source::parseSampleAuxiliaryInformationOffsets(
 off64_t offset, off64_t /* size */) {
    ALOGV("parseSampleAuxiliaryInformationOffsets");
 uint8_t version;
 if (mDataSource->readAt(offset, &version, sizeof(version)) != 1) {
 return ERROR_IO;
 }
    offset++;

 uint32_t flags;
 if (!mDataSource->getUInt24(offset, &flags)) {
 return ERROR_IO;
 }
    offset += 3;

 uint32_t entrycount;
 if (!mDataSource->getUInt32(offset, &entrycount)) {
 return ERROR_IO;
 }
    offset += 4;
 if (entrycount == 0) {
 return OK;
 }
 if (entrycount > UINT32_MAX / 8) {
 return ERROR_MALFORMED;
 }

 if (entrycount > mCurrentSampleInfoOffsetsAllocSize) {
 uint64_t *newPtr = (uint64_t *)realloc(mCurrentSampleInfoOffsets, entrycount * 8);
 if (newPtr == NULL) {
            ALOGE("failed to realloc %u -> %u", mCurrentSampleInfoOffsetsAllocSize, entrycount * 8);
 return NO_MEMORY;
 }
        mCurrentSampleInfoOffsets = newPtr;
        mCurrentSampleInfoOffsetsAllocSize = entrycount;
 }
    mCurrentSampleInfoOffsetCount = entrycount;

 if (mCurrentSampleInfoOffsets == NULL) {
 return OK;
 }

 for (size_t i = 0; i < entrycount; i++) {
 if (version == 0) {
 uint32_t tmp;
 if (!mDataSource->getUInt32(offset, &tmp)) {
 return ERROR_IO;
 }
            mCurrentSampleInfoOffsets[i] = tmp;
            offset += 4;
 } else {
 uint64_t tmp;
 if (!mDataSource->getUInt64(offset, &tmp)) {
 return ERROR_IO;
 }
            mCurrentSampleInfoOffsets[i] = tmp;
            offset += 8;
 }
 }


 off64_t drmoffset = mCurrentSampleInfoOffsets[0]; // from moof

    drmoffset += mCurrentMoofOffset;
 int ivlength;
    CHECK(mFormat->findInt32(kKeyCryptoDefaultIVSize, &ivlength));

 if (ivlength != 0 && ivlength != 8 && ivlength != 16) {
        ALOGW("unsupported IV length: %d", ivlength);
 return ERROR_MALFORMED;
 }
 for (size_t i = 0; i < mCurrentSampleInfoCount; i++) {
 if (i >= mCurrentSamples.size()) {
            ALOGW("too few samples");
 break;
 }
 Sample *smpl = &mCurrentSamples.editItemAt(i);

        memset(smpl->iv, 0, 16);
 if (mDataSource->readAt(drmoffset, smpl->iv, ivlength) != ivlength) {
 return ERROR_IO;
 }

        drmoffset += ivlength;

 int32_t smplinfosize = mCurrentDefaultSampleInfoSize;
 if (smplinfosize == 0) {
            smplinfosize = mCurrentSampleInfoSizes[i];
 }
 if (smplinfosize > ivlength) {
 uint16_t numsubsamples;
 if (!mDataSource->getUInt16(drmoffset, &numsubsamples)) {
 return ERROR_IO;
 }
            drmoffset += 2;
 for (size_t j = 0; j < numsubsamples; j++) {
 uint16_t numclear;
 uint32_t numencrypted;
 if (!mDataSource->getUInt16(drmoffset, &numclear)) {
 return ERROR_IO;
 }
                drmoffset += 2;
 if (!mDataSource->getUInt32(drmoffset, &numencrypted)) {
 return ERROR_IO;
 }
                drmoffset += 4;
                smpl->clearsizes.add(numclear);
                smpl->encryptedsizes.add(numencrypted);
 }
 } else {
            smpl->clearsizes.add(0);
            smpl->encryptedsizes.add(smpl->size);
 }
 }


 return OK;
}