Skip to content

Instantly share code, notes, and snippets.

@jankowskib
Last active August 29, 2015 14:26
Show Gist options
  • Save jankowskib/07906c221d214696e65e to your computer and use it in GitHub Desktop.
Save jankowskib/07906c221d214696e65e to your computer and use it in GitHub Desktop.
Stagefright explioit patch for Mediateks (4.4.2)
From feb0e93c1ec4e980a01293ec418db25a25aded1f Mon Sep 17 00:00:00 2001
From: Bartosz J <thug1337@gmail.com>
Date: Thu, 6 Aug 2015 16:01:57 +0200
Subject: [PATCH] Fix Stagefright exploits
Signed-off-by: Bartosz J <thug1337@gmail.com>
diff --git a/media/libstagefright/ESDS.cpp b/media/libstagefright/ESDS.cpp
index 103105d..b008df1 100644
--- a/media/libstagefright/ESDS.cpp
+++ b/media/libstagefright/ESDS.cpp
@@ -179,6 +179,9 @@ status_t ESDS::parseESDescriptor(size_t offset, size_t size) {
--size;
if (streamDependenceFlag) {
+ if (size < 2)
+ return ERROR_MALFORMED;
+
offset += 2;
size -= 2;
}
@@ -188,11 +191,18 @@ status_t ESDS::parseESDescriptor(size_t offset, size_t size) {
return ERROR_MALFORMED;
}
unsigned URLlength = mData[offset];
+
+ if (URLlength >= size)
+ return ERROR_MALFORMED;
+
offset += URLlength + 1;
size -= URLlength + 1;
}
if (OCRstreamFlag) {
+ if (size < 2)
+ return ERROR_MALFORMED;
+
offset += 2;
size -= 2;
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 88d7705..bd181cb 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -903,6 +903,9 @@ status_t MPEG4Extractor::parseDrmSINFMOOV(off64_t *offset, off64_t data_offset)
uint32_t size = U32_AT(&buf[36]);
uint8_t *data = new uint8_t[size];
+ if (data == NULL) {
+ return ERROR_MALFORMED;
+ }
memset(data, 0, size);
if (mDataSource->readAt(data_offset+40, data, size) != size) {
return ERROR_IO;
@@ -946,6 +949,8 @@ status_t MPEG4Extractor::parseDrmSINFTrack(off64_t *offset, off64_t data_offset)
uint32_t Algor = U32_AT(&buf[20]) >> 8;
uint8_t IV_Size = buf[23];
ALOGI("Algor:%d, IV_Size:%d", Algor, IV_Size);
+ if (!mLastTrack)
+ return ERROR_MALFORMED;
mLastTrack->meta->setInt32(kKeyCryptoDefaultIVSize, IV_Size);
// encode KID for base64
@@ -1336,6 +1341,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
mDataSource = cachedSource;
}
}
+
+ if (!mLastTrack)
+ return ERROR_MALFORMED;
mLastTrack->sampleTable = new SampleTable(mDataSource);
}
@@ -1578,6 +1586,10 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
}
original_fourcc = ntohl(original_fourcc);
ALOGV("read original format: %d", original_fourcc);
+
+ if (!mLastTrack)
+ return ERROR_MALFORMED;
+
mLastTrack->meta->setCString(kKeyMIMEType, FourCC2MIME(original_fourcc));
uint32_t num_channels = 0;
uint32_t sample_rate = 0;
@@ -1631,7 +1643,10 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
if (mDataSource->readAt(data_offset + 8, &defaultKeyId, 16) < 16) {
return ERROR_IO;
}
-
+
+ if (!mLastTrack)
+ return ERROR_MALFORMED;
+
mLastTrack->meta->setInt32(kKeyCryptoMode, defaultAlgorithmId);
mLastTrack->meta->setInt32(kKeyCryptoDefaultIVSize, defaultIVSize);
mLastTrack->meta->setData(kKeyCryptoKey, 'tenc', defaultKeyId, 16);
@@ -1728,6 +1743,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
int64_t duration;
int32_t samplerate;
+ if (!mLastTrack)
+ return ERROR_MALFORMED;
+
if (mLastTrack->meta->findInt64(kKeyDuration, &duration) &&
mLastTrack->meta->findInt32(kKeySampleRate, &samplerate)) {
@@ -1773,6 +1791,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
else if (entry_count == 2)
ALOGW("edit list entry_count=2, Assume the second entry is the duration of the track and normal play");
+ if (!mLastTrack)
+ return ERROR_MALFORMED;
+
mLastTrack->mElstEntryCount = entry_count;
mLastTrack->mElstEntries = new Track::ElstEntry[entry_count];
if (version == 1) {
@@ -1844,6 +1865,8 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
if (mDataSource->readAt(data_offset, buffer, 26) < 26) {
return ERROR_IO;
}
+ if (!mLastTrack)
+ return ERROR_MALFORMED;
const char* mtk_livephoto_tag = "MTK-live-photo:";
if (!memcmp(mtk_livephoto_tag, buffer+6, 16)) {
int32_t mtk_livephoto_mode = U32_AT(&buffer[22]);
@@ -1917,9 +1940,12 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
if (mDataSource->readAt(data_offset, buffer, 16) < 16) {
return ERROR_IO;
}
+ if (!mLastTrack)
+ return ERROR_MALFORMED;
const char* mtk_hevc_tag = "HEVC_MTK";
if (!memcmp(mtk_hevc_tag, buffer+8, 8)) {
ALOGI("hevc_mtk");
+
mLastTrack->meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_HEVC);
}
}
@@ -1958,7 +1984,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
< (ssize_t)sizeof(timescale)) {
return ERROR_IO;
}
-
+ if (!mLastTrack)
+ return ERROR_MALFORMED;
+
mLastTrack->timescale = ntohl(timescale);
int64_t duration = 0;
@@ -2065,6 +2093,10 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
// display the timed text.
// For encrypted files, there may also be more than one entry.
const char *mime;
+
+ if (!mLastTrack)
+ return ERROR_MALFORMED;
+
CHECK(mLastTrack->meta->findCString(kKeyMIMEType, &mime));
#ifdef MTK_SUBTITLE_SUPPORT
if(strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP) && strcasecmp(mime, "application/octet-stream") && strcasecmp(mime, MEDIA_MIMETYPE_TEXT_VOBSUB))
@@ -2114,6 +2146,8 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
#endif
#endif
{
+ if (!mLastTrack)
+ return ERROR_MALFORMED;
#ifndef ANDROID_DEFAULT_CODE//hai.li
mHasAudio = true;
mLastTrack->mIsAudio = true;
@@ -2148,6 +2182,10 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
uint16_t sample_size = U16_AT(&buffer[18]);
uint32_t sample_rate = U32_AT(&buffer[24]) >> 16;
+
+ if (!mLastTrack)
+ return ERROR_MALFORMED;
+
#ifndef ANDROID_DEFAULT_CODE
uint16_t versions = U16_AT(&buffer[8]);
#ifdef MTK_AUDIO_RAW_SUPPORT
@@ -2294,6 +2332,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
// printf("*** coding='%s' width=%d height=%d\n",
// chunk, width, height);
+ if (!mLastTrack)
+ return ERROR_MALFORMED;
+
#ifndef ANDROID_DEFAULT_CODE
#ifdef MTK_VIDEO_HEVC_SUPPORT
const char *mime;
@@ -2343,6 +2384,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
case FOURCC('s', 't', 'c', 'o'):
case FOURCC('c', 'o', '6', '4'):
{
+ if (!mLastTrack || !mLastTrack->sampleTable.get())
+ return ERROR_MALFORMED;
+
status_t err =
mLastTrack->sampleTable->setChunkOffsetParams(
chunk_type, data_offset, chunk_data_size);
@@ -2357,6 +2401,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
case FOURCC('s', 't', 's', 'c'):
{
+ if (!mLastTrack || !mLastTrack->sampleTable.get())
+ return ERROR_MALFORMED;
+
status_t err =
mLastTrack->sampleTable->setSampleToChunkParams(
data_offset, chunk_data_size);
@@ -2372,6 +2419,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
case FOURCC('s', 't', 's', 'z'):
case FOURCC('s', 't', 'z', '2'):
{
+ if (!mLastTrack || !mLastTrack->sampleTable.get())
+ return ERROR_MALFORMED;
+
status_t err =
mLastTrack->sampleTable->setSampleSizeParams(
chunk_type, data_offset, chunk_data_size);
@@ -2488,6 +2538,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
case FOURCC('s', 't', 't', 's'):
{
+ if (!mLastTrack || !mLastTrack->sampleTable.get())
+ return ERROR_MALFORMED;
+
#ifndef ANDROID_DEFAULT_CODE
status_t err =
mLastTrack->sampleTable->setTimeToSampleParams(
@@ -2519,6 +2572,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
case FOURCC('c', 't', 't', 's'):
{
+ if (!mLastTrack || !mLastTrack->sampleTable.get())
+ return ERROR_MALFORMED;
+
#ifndef ANDROID_DEFAULT_CODE
status_t err =
mLastTrack->sampleTable->setCompositionTimeToSampleParams(
@@ -2538,6 +2594,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
case FOURCC('s', 't', 's', 's'):
{
+ if (!mLastTrack || !mLastTrack->sampleTable.get())
+ return ERROR_MALFORMED;
+
#ifndef ANDROID_DEFAULT_CODE // ALPS00779876: Audio track doesn't need 'stss' table, each frame is sync frame
const char *mime;
mLastTrack->meta->findCString(kKeyMIMEType, &mime);
@@ -2604,6 +2663,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
return ERROR_MALFORMED;
}
+ if (!mLastTrack)
+ return ERROR_MALFORMED;
+
uint8_t *buffer = (uint8_t *)malloc(chunk_data_size);
if (buffer == NULL) {
return -ENOMEM;
@@ -2615,6 +2677,8 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
ALOGE("ERROR_IO, LINE=%d", __LINE__);
return ERROR_IO;
}
+
+
mLastTrack->meta->setData(kKeyMPEG4VOS, 0,buffer,chunk_data_size);
*offset += chunk_size;
free(buffer);
@@ -2667,6 +2731,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
return ERROR_MALFORMED;
}
#endif
+ if (!mLastTrack)
+ return ERROR_MALFORMED;
+
mLastTrack->meta->setData(
kKeyESDS, kTypeESDS, &buffer[4], chunk_data_size - 4);
@@ -2767,6 +2834,10 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
data_offset, buffer->data(), chunk_data_size) < chunk_data_size) {
return ERROR_IO;
}
+
+ if (!mLastTrack)
+ return ERROR_MALFORMED;
+
#ifndef ANDROID_DEFAULT_CODE
#ifdef MTK_VIDEO_HEVC_SUPPORT
uint8_t *ptr1 = (uint8_t *)buffer->data();
@@ -2817,7 +2888,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
data_offset, buffer, chunk_data_size) < chunk_data_size) {
return ERROR_IO;
}
-
+ if (!mLastTrack)
+ return ERROR_MALFORMED;
+
mLastTrack->meta->setData(kKeyD263, kTypeD263, buffer, chunk_data_size);
*offset += chunk_size;
@@ -2949,6 +3022,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
return ERROR_IO;
}
+ if (!mLastTrack)
+ return ERROR_MALFORMED;
+
uint32_t type = ntohl(buffer);
// For the 3GPP file format, the handler-type within the 'hdlr' box
// shall be 'text'. We also want to support 'sbtl' handler type
@@ -2975,13 +3051,22 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
uint32_t type;
const void *data;
size_t size = 0;
+ if (!mLastTrack)
+ return ERROR_MALFORMED;
+
if (!mLastTrack->meta->findData(
kKeyTextFormatData, &type, &data, &size)) {
size = 0;
}
- uint8_t *buffer = new uint8_t[size + chunk_size];
-
+ if (SIZE_MAX - chunk_size <= size)
+ return ERROR_MALFORMED;
+
+ uint8_t *buffer = new (std::nothrow) uint8_t[size + chunk_size];
+ if (buffer == NULL) {
+ return ERROR_MALFORMED;
+ }
+
if (size > 0) {
memcpy(buffer, data, size);
}
@@ -3008,12 +3093,17 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
if (mFileMetaData != NULL) {
ALOGV("chunk_data_size = %lld and data_offset = %lld",
chunk_data_size, data_offset);
+
+ if (chunk_data_size >= SIZE_MAX - 1)
+ return ERROR_MALFORMED;
sp<ABuffer> buffer = new ABuffer(chunk_data_size + 1);
if (mDataSource->readAt(
data_offset, buffer->data(), chunk_data_size) != (ssize_t)chunk_data_size) {
return ERROR_IO;
}
const int kSkipBytesOfDataBox = 16;
+ if (chunk_data_size <= kSkipBytesOfDataBox)
+ return ERROR_MALFORMED;
mFileMetaData->setData(
kKeyAlbumArt, MetaData::TYPE_NONE,
buffer->data() + kSkipBytesOfDataBox, chunk_data_size - kSkipBytesOfDataBox);
@@ -3224,6 +3314,8 @@ status_t MPEG4Extractor::parseSegmentIndex(off64_t offset, size_t size) {
if (!mDataSource->getUInt32(offset + 8, &timeScale)) {
return ERROR_MALFORMED;
}
+ if (timeScale < 1)
+ return ERROR_MALFORMED;
ALOGV("sidx refid/timescale: %d/%d", referenceId, timeScale);
uint64_t earliestPresentationTime;
@@ -3305,6 +3397,9 @@ status_t MPEG4Extractor::parseSegmentIndex(off64_t offset, size_t size) {
mSidxEntries.add(se);
}
+ if (!mLastTrack)
+ return ERROR_MALFORMED;
+
mSidxDuration = total_duration * 1000000 / timeScale;
ALOGV("duration: %lld", mSidxDuration);
@@ -3358,6 +3453,9 @@ status_t MPEG4Extractor::parseTrackHeader(
return ERROR_UNSUPPORTED;
}
+ if (!mLastTrack)
+ return ERROR_MALFORMED;
+
mLastTrack->meta->setInt32(kKeyTrackID, id);
size_t matrixOffset = dynSize + 16;
@@ -3412,6 +3510,9 @@ status_t MPEG4Extractor::parseMetaData(off64_t offset, size_t size) {
}
uint8_t *buffer = new uint8_t[size + 1];
+ if (buffer == NULL) {
+ return ERROR_MALFORMED;
+ }
if (mDataSource->readAt(
offset, buffer, size) != (ssize_t)size) {
delete[] buffer;
@@ -3536,6 +3637,9 @@ status_t MPEG4Extractor::parseMetaData(off64_t offset, size_t size) {
int32_t delay, padding;
if (sscanf(mLastCommentData,
" %*x %x %x %*x", &delay, &padding) == 2) {
+ if (!mLastTrack)
+ return ERROR_MALFORMED;
+
mLastTrack->meta->setInt32(kKeyEncoderDelay, delay);
mLastTrack->meta->setInt32(kKeyEncoderPadding, padding);
}
@@ -3692,6 +3796,9 @@ status_t MPEG4Extractor::updateAudioTrackInfoFromESDS_MPEG4Audio(
if (objectTypeIndication == 0xe1) {
// This isn't MPEG4 audio at all, it's QCELP 14k...
+ if (!mLastTrack)
+ return ERROR_MALFORMED;
+
mLastTrack->meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_QCELP);
#ifndef ANDROID_DEFAULT_CODE
mLastTrack->skipTrack = true;
@@ -3701,6 +3808,8 @@ status_t MPEG4Extractor::updateAudioTrackInfoFromESDS_MPEG4Audio(
}
#ifndef ANDROID_DEFAULT_CODE //xingyu.zhou
if (objectTypeIndication == 0x6B || objectTypeIndication == 0x69) {
+ if (!mLastTrack)
+ return ERROR_MALFORMED;
mLastTrack->meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
mLastTrack->meta->setInt32(kKeyCodecInfoIsInFirstFrame, true);
return OK;
@@ -3746,6 +3855,8 @@ status_t MPEG4Extractor::updateAudioTrackInfoFromESDS_MPEG4Audio(
}
#ifndef ANDROID_DEFAULT_CODE
ALOGD("objectType:%d", objectType);
+ if (!mLastTrack)
+ return ERROR_MALFORMED;
mLastTrack->meta->setInt32(kKeyAacObjType, objectType);
#endif
uint32_t freqIndex = br.getBits(4);
@@ -3789,6 +3900,9 @@ status_t MPEG4Extractor::updateAudioTrackInfoFromESDS_MPEG4Audio(
return ERROR_UNSUPPORTED;
}
+ if (!mLastTrack)
+ return ERROR_MALFORMED;
+
int32_t prevSampleRate;
CHECK(mLastTrack->meta->findInt32(kKeySampleRate, &prevSampleRate));
@@ -4244,7 +4358,7 @@ status_t MPEG4Extractor::getFirstNal(Track *track, size_t *nal_offset, size_t *n
ALOGE("incomplete first NAL unit.frame_size=%d, nalLengthSize=%d, nal_size=%d", frame_size, nalLengthSize, *nal_size);
return ERROR_MALFORMED;
}
-/*
+
nal_data = malloc(nal_size);
if (NULL == nal_data) {
@@ -4258,8 +4372,6 @@ status_t MPEG4Extractor::getFirstNal(Track *track, size_t *nal_offset, size_t *n
ALOGE("read first nal fail!!");
return ERROR_IO;
}
-*/
-/*
*nal_offset = frame_offset + nalLengthSize;
ALOGD("First Nal offset=%d, size=%d", *nal_offset, *nal_size);
diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp
index 976ea2a..66335ad 100644
--- a/media/libstagefright/SampleTable.cpp
+++ b/media/libstagefright/SampleTable.cpp
@@ -269,9 +269,15 @@ status_t SampleTable::setSampleToChunkParams(
return ERROR_MALFORMED;
}
+ if (SIZE_MAX / sizeof(SampleToChunkEntry) <= mNumSampleToChunkOffsets)
+ return ERROR_OUT_OF_RANGE;
+
mSampleToChunkEntries =
- new SampleToChunkEntry[mNumSampleToChunkOffsets];
-
+ new (std::nothrow) SampleToChunkEntry[mNumSampleToChunkOffsets];
+
+ if (!mSampleToChunkEntries)
+ return ERROR_OUT_OF_RANGE;
+
for (uint32_t i = 0; i < mNumSampleToChunkOffsets; ++i) {
uint8_t buffer[12];
if (mDataSource->readAt(
@@ -378,8 +384,16 @@ status_t SampleTable::setTimeToSampleParams(
}
mTimeToSampleCount = U32_AT(&header[4]);
- mTimeToSample = new uint32_t[mTimeToSampleCount * 2];
-
+ uint64_t allocSize = mTimeToSampleCount * 2 * (uint64_t)sizeof(uint32_t);
+ if (allocSize > SIZE_MAX) {
+ return ERROR_OUT_OF_RANGE;
+ }
+
+ mTimeToSample = new (std::nothrow) uint32_t[mTimeToSampleCount * 2];
+
+ if (!mTimeToSample)
+ return ERROR_OUT_OF_RANGE;
+
size_t size = sizeof(uint32_t) * mTimeToSampleCount * 2;
if (mDataSource->readAt(
data_offset + 8, mTimeToSample, size) < (ssize_t)size) {
@@ -435,8 +449,16 @@ status_t SampleTable::setCompositionTimeToSampleParams(
#endif
mNumCompositionTimeDeltaEntries = numEntries;
- mCompositionTimeDeltaEntries = new uint32_t[2 * numEntries];
+ uint64_t allocSize = numEntries * 2 * (uint64_t)sizeof(uint32_t);
+ if (allocSize > SIZE_MAX) {
+ return ERROR_OUT_OF_RANGE;
+ }
+
+ mCompositionTimeDeltaEntries = new (std::nothrow) uint32_t[2 * numEntries];
+ if (!mCompositionTimeDeltaEntries)
+ return ERROR_OUT_OF_RANGE;
+
if (mDataSource->readAt(
data_offset + 8, mCompositionTimeDeltaEntries, numEntries * 8)
< (ssize_t)numEntries * 8) {
@@ -528,8 +550,16 @@ status_t SampleTable::setSyncSampleParams(off64_t data_offset, size_t data_size)
if (mNumSyncSamples < 2) {
ALOGV("Table of sync samples is empty or has only a single entry!");
}
-
- mSyncSamples = new uint32_t[mNumSyncSamples];
+
+ uint64_t allocSize = mNumSyncSamples * (uint64_t)sizeof(uint32_t);
+ if (allocSize > SIZE_MAX) {
+ return ERROR_OUT_OF_RANGE;
+ }
+
+ mSyncSamples = new (std::nothrow) uint32_t[mNumSyncSamples];
+ if (!mSyncSamples)
+ return ERROR_OUT_OF_RANGE;
+
size_t size = mNumSyncSamples * sizeof(uint32_t);
if (mDataSource->readAt(mSyncSampleOffset + 8, mSyncSamples, size)
!= (ssize_t)size) {
@@ -597,8 +627,11 @@ void SampleTable::buildSampleEntriesTable() {
return;
}
- mSampleTimeEntries = new SampleTimeEntry[mNumSampleSizes];
+ mSampleTimeEntries = new (std::nothrow) SampleTimeEntry[mNumSampleSizes];
+ if (!mSampleTimeEntries)
+ return;
+
uint32_t sampleIndex = 0;
uint32_t sampleTime = 0;
--
Gitg
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment