PS4 Jailbreaking       Thread starter Insityyy       1860       4

Insityyy

Developer
Member
Contributor
Keep in mind i didnt find this myself, it was listed in an exploit database that i cant remember the name of.
this is something i found a while ago, it is a webkit exploit that depends on a bug inside of the mp4 playback, the mp4 file is available here https://www.dropbox.com/s/aer8bmojvfu5ar1/crash.mp4?dl=0

EDIT: the code in case anyone is wondering is javascript.
EDIT 2: I remember when I found the code, the version of webkit it applies to is the same as the webkit version inside of 4.01
Code:
     };
     Vector<AuxRange> mDeferredSaiz;
     Vector<AuxRange> mDeferredSaio;
 
     MPEG4Source(const MPEG4Source &);
     MPEG4Source &operator=(const MPEG4Source &);
 
     bool ensureSrcBufferAllocated(int32_t size);
+    // Ensure that we have enough data in mMediaBuffer to copy our data.
+    // Returns false if not and clear mMediaBuffer.
+    bool ensureMediaBufferAllocated(int32_t size);
 };
 
 // This custom data source wraps an existing one and satisfies requests
 // falling entirely within a cached range from the cache while forwarding
 // all remaining requests to the wrapped datasource.
 // This is used to cache the full sampletable metadata for a single track,
 // possibly wrapping multiple times to cover all tracks, i.e.
 // Each MPEG4DataSource caches the sampletable metadata for a single track.
@@ -3265,22 +3268,35 @@ status_t MPEG4Source::lookForMoof() {
     }
 }
 
 bool MPEG4Source::ensureSrcBufferAllocated(int32_t aSize) {
     if (mSrcBackend.Length() >= aSize) {
         return true;
     }
     if (!mSrcBackend.SetLength(aSize)) {
+        ALOGE("Error insufficient memory, requested %u bytes (had:%u)",
+              aSize, mSrcBackend.Length());
         return false;
     }
     mSrcBuffer = mSrcBackend.Elements();
     return true;
 }
 
+bool MPEG4Source::ensureMediaBufferAllocated(int32_t aSize) {
+  if (mBuffer->size() < aSize) {
+      ALOGE("Error insufficient memory, requested %u bytes (had:%u)",
+            aSize, mBuffer->size());
+      mBuffer->release();
+      mBuffer = NULL;
+      return false;
+  }
+  return true;
+}
+
 status_t MPEG4Source::read(
         MediaBuffer **out, const ReadOptions *options) {
     Mutex::Autolock autoLock(mLock);
 
     CHECK(mStarted);
 
     if (!mLookedForMoof) {
         mLookedForMoof = lookForMoof() == OK;
@@ -3405,16 +3421,19 @@ status_t MPEG4Source::read(
           return ERROR_MALFORMED;
         }
         mBuffer = new MediaBuffer(max_size);
         assert(mBuffer);
     }
 
     if (!mIsAVC || mWantsNALFragments) {
         if (newBuffer) {
+            if (!ensureMediaBufferAllocated(size)) {
+                return ERROR_MALFORMED;
+            }
             ssize_t num_bytes_read =
                 mDataSource->readAt(offset, (uint8_t *)mBuffer->data(), size);
 
             if (num_bytes_read < (ssize_t)size) {
                 mBuffer->release();
                 mBuffer = NULL;
 
                 return ERROR_IO;
@@ -3512,22 +3531,23 @@ status_t MPEG4Source::read(
         return OK;
     } else {
         // Whole NAL units are returned but each fragment is prefixed by
         // the NAL length, stored in four bytes.
         ssize_t num_bytes_read = 0;
         int32_t drm = 0;
         bool usesDRM = (mFormat->findInt32(kKeyIsDRM, &drm) && drm != 0);
         if (usesDRM) {
+            if (!ensureMediaBufferAllocated(size)) {
+                return ERROR_MALFORMED;
+            }
             num_bytes_read =
                 mDataSource->readAt(offset, (uint8_t*)mBuffer->data(), size);
         } else {
             if (!ensureSrcBufferAllocated(size)) {
-                ALOGE("Error insufficient memory, requested %u bytes (had:%u)",
-                      size, mSrcBackend.Length());
                 return ERROR_MALFORMED;
             }
             num_bytes_read = mDataSource->readAt(offset, mSrcBuffer, size);
         }
 
         if (num_bytes_read < (ssize_t)size) {
             mBuffer->release();
             mBuffer = NULL;
@@ -3559,17 +3579,19 @@ status_t MPEG4Source::read(
                     mBuffer = NULL;
                     return ERROR_MALFORMED;
                 }
 
                 if (nalLength == 0) {
                     continue;
                 }
 
-                CHECK(dstOffset + 4 <= mBuffer->size());
+                if (!ensureMediaBufferAllocated(dstOffset + 4 + nalLength)) {
+                    return ERROR_MALFORMED;
+                }
                 dstData[dstOffset++] = (uint8_t) (nalLength >> 24);
                 dstData[dstOffset++] = (uint8_t) (nalLength >> 16);
                 dstData[dstOffset++] = (uint8_t) (nalLength >> 8);
                 dstData[dstOffset++] = (uint8_t) nalLength;
                 memcpy(&dstData[dstOffset], &mSrcBuffer[srcOffset], nalLength);
                 srcOffset += nalLength;
                 dstOffset += nalLength;
             }
@@ -3784,16 +3806,19 @@ status_t MPEG4Source::fragmentedRead(
         bufmeta->setData(kKeyCryptoIV, 0, smpl->iv, 16); // use 16 or the actual size?
         bufmeta->setInt32(kKeyCryptoDefaultIVSize, mDefaultIVSize);
         bufmeta->setInt32(kKeyCryptoMode, mCryptoMode);
         bufmeta->setData(kKeyCryptoKey, 0, mCryptoKey, 16);
     }
 
     if (!mIsAVC || mWantsNALFragments) {
         if (newBuffer) {
+            if (!ensureMediaBufferAllocated(size)) {
+                return ERROR_MALFORMED;
+            }
             ssize_t num_bytes_read =
                 mDataSource->readAt(offset, (uint8_t *)mBuffer->data(), size);
 
             if (num_bytes_read < (ssize_t)size) {
                 mBuffer->release();
                 mBuffer = NULL;
 
                 ALOGV("i/o error");
@@ -3869,22 +3894,23 @@ status_t MPEG4Source::fragmentedRead(
     } else {
         ALOGV("whole NAL");
         // Whole NAL units are returned but each fragment is prefixed by
         // the NAL unit's length, stored in four bytes.
         ssize_t num_bytes_read = 0;
         int32_t drm = 0;
         bool usesDRM = (mFormat->findInt32(kKeyIsDRM, &drm) && drm != 0);
         if (usesDRM) {
+            if (!ensureMediaBufferAllocated(size)) {
+                return ERROR_MALFORMED;
+            }
             num_bytes_read =
                 mDataSource->readAt(offset, (uint8_t*)mBuffer->data(), size);
         } else {
             if (!ensureSrcBufferAllocated(size)) {
-                ALOGE("Error insufficient memory, requested %u bytes (had:%u)",
-                      size, mSrcBackend.Length());
                 return ERROR_MALFORMED;
             }
             num_bytes_read = mDataSource->readAt(offset, mSrcBuffer, size);
         }
 
         if (num_bytes_read < (ssize_t)size) {
             mBuffer->release();
             mBuffer = NULL;
@@ -3917,17 +3943,19 @@ status_t MPEG4Source::fragmentedRead(
                     mBuffer = NULL;
                     return ERROR_MALFORMED;
                 }
 
                 if (nalLength == 0) {
                     continue;
                 }
 
-                CHECK(dstOffset + 4 <= mBuffer->size());
+                if (!ensureMediaBufferAllocated(dstOffset + 4 + nalLength)) {
+                    return ERROR_MALFORMED;
+                }
                 dstData[dstOffset++] = (uint8_t) (nalLength >> 24);
                 dstData[dstOffset++] = (uint8_t) (nalLength >> 16);
                 dstData[dstOffset++] = (uint8_t) (nalLength >> 8);
                 dstData[dstOffset++] = (uint8_t) nalLength;
                 memcpy(&dstData[dstOffset], &mSrcBuffer[srcOffset], nalLength);
                 srcOffset += nalLength;
                 dstOffset += nalLength;
                          mBuffer = NULL;
 
             return OK;
         }
 
         // Each NAL unit is split up into its constituent fragments and
         // each one of them returned in its own buffer.
 
-        CHECK(mBuffer->range_length() >= mNALLengthSize);
+        if (mBuffer->range_length() < mNALLengthSize) {
+            ALOGE("incomplete NAL unit.");
+
+            mBuffer->release();
+            mBuffer = NULL;
+
+            return ERROR_MALFORMED;
+        }
 
         const uint8_t *src =
             (const uint8_t *)mBuffer->data() + mBuffer->range_offset();
 
         size_t nal_size = parseNALSize(src);
         if (mBuffer->range_length() < mNALLengthSize + nal_size) {
             ALOGE("incomplete NAL unit.");
 
@@ -3854,17 +3861,24 @@ status_t MPEG4Source::fragmentedRead(
             mBuffer = NULL;
 
             return OK;
         }
 
         // Each NAL unit is split up into its constituent fragments and
         // each one of them returned in its own buffer.
 
-        CHECK(mBuffer->range_length() >= mNALLengthSize);
+        if (mBuffer->range_length() < mNALLengthSize) {
+            ALOGE("incomplete NAL unit.");
+
+            mBuffer->release();
+            mBuffer = NULL;
+
+            return ERROR_MALFORMED;
+        }
 
         const uint8_t *src =
             (const uint8_t *)mBuffer->data() + mBuffer->range_offset();
 
         size_t nal_size = parseNALSize(src);
         if (mBuffer->range_length() < mNALLengthSize + nal_size) {
             ALOGE("incomplete NAL unit.");
 diff --git a/media/libstagefright/frameworks/av/include/media/stagefright/MediaBuffer.h b/media/libstagefright/frameworks/av/include/media/stagefright/MediaBuffer.h
--- a/media/libstagefright/frameworks/av/include/media/stagefright/MediaBuffer.h
+++ b/media/libstagefright/frameworks/av/include/media/stagefright/MediaBuffer.h
@@ -17,16 +17,17 @@
 #ifndef MEDIA_BUFFER_H_
 
 #define MEDIA_BUFFER_H_
 
 #include <pthread.h>
 
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
+#include "nsTArray.h"
 
 namespace stagefright {
 
 struct ABuffer;
 class GraphicBuffer;
 class MediaBuffer;
 class MediaBufferObserver;
 class MetaData;
@@ -80,16 +81,18 @@ public:
 
     // Returns a clone of this MediaBuffer increasing its reference count.
     // The clone references the same data but has its own range and
     // MetaData.
     MediaBuffer *clone();
 
     int refcount() const;
 
+    bool ensuresize(size_t length);
+
 protected:
     virtual ~MediaBuffer();
 
 private:
     friend class MediaBufferGroup;
     friend class OMXDecoder;
 
     // For use by OMXDecoder, reference count must be 1, drop reference
@@ -111,13 +114,15 @@ private:
 
     MediaBuffer *mOriginal;
 
     void setNextBuffer(MediaBuffer *buffer);
     MediaBuffer *nextBuffer();
 
     MediaBuffer(const MediaBuffer &);
     MediaBuffer &operator=(const MediaBuffer &);
+
+    FallibleTArray<uint8_t> mBufferBackend;
 };
 
 }  // namespace stagefright
 
 #endif  // MEDIA_BUFFER_H_
diff --git a/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp
--- a/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp
@@ -3277,24 +3277,24 @@ bool MPEG4Source::ensureSrcBufferAllocat
               aSize, mSrcBackend.Length());
         return false;
     }
     mSrcBuffer = mSrcBackend.Elements();
     return true;
 }
 
 bool MPEG4Source::ensureMediaBufferAllocated(int32_t aSize) {
-  if (mBuffer->size() < aSize) {
-      ALOGE("Error insufficient memory, requested %u bytes (had:%u)",
-            aSize, mBuffer->size());
-      mBuffer->release();
-      mBuffer = NULL;
-      return false;
+  if (mBuffer->ensuresize(aSize)) {
+      return true;
   }
-  return true;
+  ALOGE("Error insufficient memory, requested %u bytes (had:%u)",
+        aSize, mBuffer->size());
+  mBuffer->release();
+  mBuffer = NULL;
+  return false;
 }
 
 status_t MPEG4Source::read(
         MediaBuffer **out, const ReadOptions *options) {
     Mutex::Autolock autoLock(mLock);
 
     CHECK(mStarted);
 
@@ -3411,22 +3411,17 @@ status_t MPEG4Source::read(
                     &isSyncSample, &dts);
 
         if (err != OK) {
             return err;
         }
 
         int32_t max_size;
         CHECK(mFormat->findInt32(kKeyMaxInputSize, &max_size));
-        if (!ValidInputSize(max_size)) {
-          ALOGE("Invalid max input size %d", max_size);
-          return ERROR_MALFORMED;
-        }
-        mBuffer = new MediaBuffer(max_size);
-        assert(mBuffer);
+        mBuffer = new MediaBuffer(max_size > 1024*1024 ? 1024*1024 : max_size);
     }
 
     if (!mIsAVC || mWantsNALFragments) {
         if (newBuffer) {
             if (!ensureMediaBufferAllocated(size)) {
                 return ERROR_MALFORMED;
             }
             ssize_t num_bytes_read =
@@ -3562,17 +3557,16 @@ status_t MPEG4Source::read(
             return ERROR_IO;
         }
 
         if (usesDRM) {
             CHECK(mBuffer != NULL);
             mBuffer->set_range(0, size);
 
         } else {
-            uint8_t *dstData = (uint8_t *)mBuffer->data();
             size_t srcOffset = 0;
             size_t dstOffset = 0;
 
             while (srcOffset < size) {
                 bool isMalFormed = (srcOffset + mNALLengthSize > size);
                 size_t nalLength = 0;
                 if (!isMalFormed) {
                     nalLength = parseNALSize(&mSrcBuffer[srcOffset]);
@@ -3589,16 +3583,17 @@ status_t MPEG4Source::read(
 
                 if (nalLength == 0) {
                     continue;
                 }
 
                 if (!ensureMediaBufferAllocated(dstOffset + 4 + nalLength)) {
                     return ERROR_MALFORMED;
                 }
+                uint8_t *dstData = (uint8_t *)mBuffer->data();
                 dstData[dstOffset++] = (uint8_t) (nalLength >> 24);
                 dstData[dstOffset++] = (uint8_t) (nalLength >> 16);
                 dstData[dstOffset++] = (uint8_t) (nalLength >> 8);
                 dstData[dstOffset++] = (uint8_t) nalLength;
                 memcpy(&dstData[dstOffset], &mSrcBuffer[srcOffset], nalLength);
                 srcOffset += nalLength;
                 dstOffset += nalLength;
             }
@@ -3788,22 +3783,17 @@ status_t MPEG4Source::fragmentedRead(
         dts = mCurrentTime;
         cts = mCurrentTime + smpl->ctsOffset;
         duration = smpl->duration;
         mCurrentTime += smpl->duration;
         isSyncSample = smpl->isSync();
 
         int32_t max_size;
         CHECK(mFormat->findInt32(kKeyMaxInputSize, &max_size));
-        if (!ValidInputSize(max_size)) {
-          ALOGE("Invalid max input size %d", max_size);
-          return ERROR_MALFORMED;
-        }
-        mBuffer = new MediaBuffer(max_size);
-        assert(mBuffer);
+        mBuffer = new MediaBuffer(max_size > 1024*1024 ? 1024*1024 : max_size);
     }
 
     const Sample *smpl = &mCurrentSamples[mCurrentSampleIndex];
     const sp<MetaData> bufmeta = mBuffer->meta_data();
     bufmeta->clear();
     if (smpl->encryptedsizes.size()) {
         // store clear/encrypted lengths in metadata
         bufmeta->setData(kKeyPlainSizes, 0,
@@ -3933,17 +3923,16 @@ status_t MPEG4Source::fragmentedRead(
             return ERROR_IO;
         }
 
         if (usesDRM) {
             CHECK(mBuffer != NULL);
             mBuffer->set_range(0, size);
 
         } else {
-            uint8_t *dstData = (uint8_t *)mBuffer->data();
             size_t srcOffset = 0;
             size_t dstOffset = 0;
 
             while (srcOffset < size) {
                 bool isMalFormed = (srcOffset + mNALLengthSize > size);
                 size_t nalLength = 0;
                 if (!isMalFormed) {
                     nalLength = parseNALSize(&mSrcBuffer[srcOffset]);
@@ -3960,16 +3949,17 @@ status_t MPEG4Source::fragmentedRead(
 
                 if (nalLength == 0) {
                     continue;
                 }
 
                 if (!ensureMediaBufferAllocated(dstOffset + 4 + nalLength)) {
                     return ERROR_MALFORMED;
                 }
+                uint8_t *dstData = (uint8_t *)mBuffer->data();
                 dstData[dstOffset++] = (uint8_t) (nalLength >> 24);
                 dstData[dstOffset++] = (uint8_t) (nalLength >> 16);
                 dstData[dstOffset++] = (uint8_t) (nalLength >> 8);
                 dstData[dstOffset++] = (uint8_t) nalLength;
                 memcpy(&dstData[dstOffset], &mSrcBuffer[srcOffset], nalLength);
                 srcOffset += nalLength;
                 dstOffset += nalLength;
             }
diff --git a/media/libstagefright/frameworks/av/media/libstagefright/MediaBuffer.cpp b/media/libstagefright/frameworks/av/media/libstagefright/MediaBuffer.cpp
--- a/media/libstagefright/frameworks/av/media/libstagefright/MediaBuffer.cpp
+++ b/media/libstagefright/frameworks/av/media/libstagefright/MediaBuffer.cpp
@@ -43,23 +43,24 @@ MediaBuffer::MediaBuffer(void *data, siz
       mMetaData(new MetaData),
       mOriginal(NULL) {
 }
 
 MediaBuffer::MediaBuffer(size_t size)
     : mObserver(NULL),
       mNextBuffer(NULL),
       mRefCount(0),
-      mData(malloc(size)),
+      mData(NULL),
       mSize(size),
       mRangeOffset(0),
       mRangeLength(size),
       mOwnsData(true),
       mMetaData(new MetaData),
       mOriginal(NULL) {
+    ensuresize(size);
 }
 
 MediaBuffer::MediaBuffer(const sp<GraphicBuffer>& graphicBuffer)
     : mObserver(NULL),
       mNextBuffer(NULL),
       mRefCount(0),
       mData(NULL),
       mSize(1),
@@ -154,21 +155,16 @@ sp<MetaData> MediaBuffer::meta_data() {
 void MediaBuffer::reset() {
     mMetaData->clear();
     set_range(0, mSize);
 }
 
 MediaBuffer::~MediaBuffer() {
     CHECK(mObserver == NULL);
 
-    if (mOwnsData && mData != NULL) {
-        free(mData);
-        mData = NULL;
-    }
-
     if (mOriginal != NULL) {
         mOriginal->release();
         mOriginal = NULL;
     }
 }
 
 void MediaBuffer::setObserver(MediaBufferObserver *observer) {
     CHECK(observer == NULL || mObserver == NULL);
@@ -195,9 +191,25 @@ MediaBuffer *MediaBuffer::clone() {
     buffer->mMetaData = new MetaData(*mMetaData.get());
 
     add_ref();
     buffer->mOriginal = this;
 
     return buffer;
 }
 
+bool MediaBuffer::ensuresize(size_t length) {
+    if (mBufferBackend.Length() >= length) {
+        return true;
+    }
+    // Can't reallocate data we don't owned or shared with another.
+    if (!mOwnsData || refcount()) {
+        return false;
+    }
+    if (!mBufferBackend.SetLength(length)) {
+        return false;
+    }
+    mData = mBufferBackend.Elements();
+    mSize = length;
+    return true;
+}
+
 }  diff --git a/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp
--- a/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp
@@ -32,16 +32,17 @@
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
 #include <utils/String8.h>
+#include "nsTArray.h"
 
 namespace stagefright {
 
 class MPEG4Source : public MediaSource {
 public:
     // Caller retains ownership of both "dataSource" and "sampleTable".
     MPEG4Source(const sp<MetaData> &format,
                 const sp<DataSource> &dataSource,
@@ -98,16 +99,17 @@ private:
 
     bool mStarted;
 
     MediaBuffer *mBuffer;
 
     bool mWantsNALFragments;
 
     uint8_t *mSrcBuffer;
+    FallibleTArray<uint8_t> mSrcBackend;
 
     size_t parseNALSize(const uint8_t *data) const;
     status_t parseChunk(off64_t *offset);
     status_t parseTrackFragmentData(off64_t offset, off64_t size);
     status_t parseTrackFragmentHeader(off64_t offset, off64_t size);
     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);
@@ -151,16 +153,21 @@ private:
         Vector<uint16_t> clearsizes;
         Vector<uint32_t> encryptedsizes;
     };
     Vector<Sample> mCurrentSamples;
     MPEG4Extractor::TrackExtends mTrackExtends;
 
     MPEG4Source(const MPEG4Source &);
     MPEG4Source &operator=(const MPEG4Source &);
+
+    bool ensureSrcBufferAllocated(int32_t size);
+    // Ensure that we have enough data in mMediaBuffer to copy our data.
+    // Returns false if not and clear mMediaBuffer.
+    bool ensureMediaBufferAllocated(int32_t size);
 };
 
 // This custom data source wraps an existing one and satisfies requests
 // falling entirely within a cached range from the cache while forwarding
 // all remaining requests to the wrapped datasource.
 // This is used to cache the full sampletable metadata for a single track,
 // possibly wrapping multiple times to cover all tracks, i.e.
 // Each MPEG4DataSource caches the sampletable metadata for a single track.
@@ -748,16 +755,23 @@ static void convertTimeToDate(int64_t ti
     }
 
     char tmp[32];
     strftime(tmp, sizeof(tmp), "%Y%m%dT%H%M%S.000Z", gmtime(&time_1970));
 
     s->setTo(tmp);
 }
 
+static bool ValidInputSize(int32_t size) {
+  // Reject compressed samples larger than an uncompressed UHD
+  // frame. This is a reasonable cut-off for a lossy codec,
+  // combined with the current Firefox limit to 5k video.
+  return (size > 0 && size <= 4 * (1920 * 1080) * 3 / 2);
+}
+
 status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
     ALOGV("entering parseChunk %lld/%d", *offset, depth);
     uint32_t hdr[2];
     if (mDataSource->readAt(*offset, hdr, 8) < 8) {
         return ERROR_IO;
     }
     uint64_t chunk_size = ntohl(hdr[0]);
     uint32_t chunk_type = ntohl(hdr[1]);
@@ -2480,62 +2494,47 @@ MPEG4Source::MPEG4Source(
 MPEG4Source::~MPEG4Source() {
     if (mStarted) {
         stop();
     }
     free(mCurrentSampleInfoSizes);
     free(mCurrentSampleInfoOffsets);
 }
 
-static bool ValidInputSize(int32_t size) {
-  // Reject compressed samples larger than an uncompressed UHD
-  // frame. This is a reasonable cut-off for a lossy codec,
-  // combined with the current Firefox limit to 5k video.
-  return (size > 0 && size < 4 * (1920 * 1080) * 3 / 2);
-}
-
 status_t MPEG4Source::start(MetaData *params) {
     Mutex::Autolock autoLock(mLock);
 
     CHECK(!mStarted);
 
     int32_t val;
     if (params && params->findInt32(kKeyWantsNALFragments, &val)
         && val != 0) {
         mWantsNALFragments = true;
     } else {
         mWantsNALFragments = false;
     }
 
-    int32_t max_size;
-    CHECK(mFormat->findInt32(kKeyMaxInputSize, &max_size));
-    if (!ValidInputSize(max_size)) {
-      ALOGE("Invalid max input size %d", max_size);
-      return ERROR_MALFORMED;
-    }
-
-    mSrcBuffer = new uint8_t[max_size];
+    mSrcBuffer = mSrcBackend.Elements();
 
     mStarted = true;
 
     return OK;
 }
 
 status_t MPEG4Source::stop() {
     Mutex::Autolock autoLock(mLock);
 
     CHECK(mStarted);
 
     if (mBuffer != NULL) {
         mBuffer->release();
         mBuffer = NULL;
     }
 
-    delete[] mSrcBuffer;
-    mSrcBuffer = NULL;
+    mSrcBackend.Clear();
 
     mStarted = false;
     mCurrentSampleIndex = 0;
 
     return OK;
 }
 
 status_t MPEG4Source::parseChunk(off64_t *offset) {
@@ -3137,16 +3136,40 @@ size_t MPEG4Source::parseNALSize(const u
 
     // This cannot happen, mNALLengthSize springs to life by adding 1 to
     // a 2-bit integer.
     CHECK(!"Should not be here.");
 
     return 0;
 }
 
+bool MPEG4Source::ensureSrcBufferAllocated(int32_t aSize) {
+    if (mSrcBackend.Length() >= aSize) {
+        return true;
+    }
+    if (!mSrcBackend.SetLength(aSize)) {
+        ALOGE("Error insufficient memory, requested %u bytes (had:%u)",
+              aSize, mSrcBackend.Length());
+        return false;
+    }
+    mSrcBuffer = mSrcBackend.Elements();
+    return true;
+}
+
+bool MPEG4Source::ensureMediaBufferAllocated(int32_t aSize) {
+  if (mBuffer->size() < aSize) {
+      ALOGE("Error insufficient memory, requested %u bytes (had:%u)",
+            aSize, mBuffer->size());
+      mBuffer->release();
+      mBuffer = NULL;
+      return false;
+  }
+  return true;
+}
+
 status_t MPEG4Source::read(
         MediaBuffer **out, const ReadOptions *options) {
     Mutex::Autolock autoLock(mLock);
 
     CHECK(mStarted);
 
     if (mFirstMoofOffset > 0) {
         return fragmentedRead(out, options);
@@ -3267,16 +3290,19 @@ status_t MPEG4Source::read(
           return ERROR_MALFORMED;
         }
         mBuffer = new MediaBuffer(max_size);
         assert(mBuffer);
     }
 
     if (!mIsAVC || mWantsNALFragments) {
         if (newBuffer) {
+            if (!ensureMediaBufferAllocated(size)) {
+                return ERROR_MALFORMED;
+            }
             ssize_t num_bytes_read =
                 mDataSource->readAt(offset, (uint8_t *)mBuffer->data(), size);
 
             if (num_bytes_read < (ssize_t)size) {
                 mBuffer->release();
                 mBuffer = NULL;
 
                 return ERROR_IO;
@@ -3352,19 +3378,25 @@ status_t MPEG4Source::read(
         return OK;
     } else {
         // Whole NAL units are returned but each fragment is prefixed by
         // the NAL length, stored in four bytes.
         ssize_t num_bytes_read = 0;
         int32_t drm = 0;
         bool usesDRM = (mFormat->findInt32(kKeyIsDRM, &drm) && drm != 0);
         if (usesDRM) {
+            if (!ensureMediaBufferAllocated(size)) {
+                return ERROR_MALFORMED;
+            }
             num_bytes_read =
                 mDataSource->readAt(offset, (uint8_t*)mBuffer->data(), size);
         } else {
+            if (!ensureSrcBufferAllocated(size)) {
+                return ERROR_MALFORMED;
+            }
             num_bytes_read = mDataSource->readAt(offset, mSrcBuffer, size);
         }
 
         if (num_bytes_read < (ssize_t)size) {
             mBuffer->release();
             mBuffer = NULL;
 
             return ERROR_IO;
@@ -3394,17 +3426,19 @@ status_t MPEG4Source::read(
                     mBuffer = NULL;
                     return ERROR_MALFORMED;
                 }
 
                 if (nalLength == 0) {
                     continue;
                 }
 
-                CHECK(dstOffset + 4 <= mBuffer->size());
+                if (!ensureMediaBufferAllocated(dstOffset + 4 + nalLength)) {
+                    return ERROR_MALFORMED;
+                }
                 dstData[dstOffset++] = (uint8_t) (nalLength >> 24);
                 dstData[dstOffset++] = (uint8_t) (nalLength >> 16);
                 dstData[dstOffset++] = (uint8_t) (nalLength >> 8);
                 dstData[dstOffset++] = (uint8_t) nalLength;
                 memcpy(&dstData[dstOffset], &mSrcBuffer[srcOffset], nalLength);
                 srcOffset += nalLength;
                 dstOffset += nalLength;
             }
@@ -3568,16 +3602,19 @@ status_t MPEG4Source::fragmentedRead(
         bufmeta->setData(kKeyCryptoIV, 0, smpl->iv, 16); // use 16 or the actual size?
         bufmeta->setInt32(kKeyCryptoDefaultIVSize, mDefaultIVSize);
         bufmeta->setInt32(kKeyCryptoMode, mCryptoMode);
         bufmeta->setData(kKeyCryptoKey, 0, mCryptoKey, 16);
     }
 
     if (!mIsAVC || mWantsNALFragments) {
         if (newBuffer) {
+            if (!ensureMediaBufferAllocated(size)) {
+                return ERROR_MALFORMED;
+            }
             ssize_t num_bytes_read =
                 mDataSource->readAt(offset, (uint8_t *)mBuffer->data(), size);
 
             if (num_bytes_read < (ssize_t)size) {
                 mBuffer->release();
                 mBuffer = NULL;
 
                 ALOGV("i/o error");
@@ -3653,19 +3690,25 @@ status_t MPEG4Source::fragmentedRead(
     } else {
         ALOGV("whole NAL");
         // Whole NAL units are returned but each fragment is prefixed by
         // the NAL unit's length, stored in four bytes.
         ssize_t num_bytes_read = 0;
         int32_t drm = 0;
         bool usesDRM = (mFormat->findInt32(kKeyIsDRM, &drm) && drm != 0);
         if (usesDRM) {
+            if (!ensureMediaBufferAllocated(size)) {
+                return ERROR_MALFORMED;
+            }
             num_bytes_read =
                 mDataSource->readAt(offset, (uint8_t*)mBuffer->data(), size);
         } else {
+            if (!ensureSrcBufferAllocated(size)) {
+                return ERROR_MALFORMED;
+            }
             num_bytes_read = mDataSource->readAt(offset, mSrcBuffer, size);
         }
 
         if (num_bytes_read < (ssize_t)size) {
             mBuffer->release();
             mBuffer = NULL;
 
             ALOGV("i/o error");
@@ -3696,17 +3739,19 @@ status_t MPEG4Source::fragmentedRead(
                     mBuffer = NULL;
                     return ERROR_MALFORMED;
                 }
 
                 if (nalLength == 0) {
                     continue;
                 }
 
-                CHECK(dstOffset + 4 <= mBuffer->size());
+                if (!ensureMediaBufferAllocated(dstOffset + 4 + nalLength)) {
+                    return ERROR_MALFORMED;
+                }
                 dstData[dstOffset++] = (uint8_t) (nalLength >> 24);
                 dstData[dstOffset++] = (uint8_t) (nalLength >> 16);
                 dstData[dstOffset++] = (uint8_t) (nalLength >> 8);
                 dstData[dstOffset++] = (uint8_t) nalLength;
                 memcpy(&dstData[dstOffset], &mSrcBuffer[srcOffset], nalLength);
                 srcOffset += nalLength;
                 dstOffset += nalLength;
             diff --git a/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp
--- a/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp
@@ -33,16 +33,17 @@
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
 #include <utils/String8.h>
+#include "nsTArray.h"
 
 namespace stagefright {
 
 class MPEG4Source : public MediaSource {
 public:
     // Caller retains ownership of both "dataSource" and "sampleTable".
     MPEG4Source(const sp<MetaData> &format,
                 const sp<DataSource> &dataSource,
@@ -99,16 +100,17 @@ private:
 
     MediaBufferGroup *mGroup;
 
     MediaBuffer *mBuffer;
 
     bool mWantsNALFragments;
 
     uint8_t *mSrcBuffer;
+    FallibleTArray<uint8_t> mSrcBackend;
 
     size_t parseNALSize(const uint8_t *data) const;
     status_t parseChunk(off64_t *offset);
     status_t parseTrackFragmentHeader(off64_t offset, off64_t size);
     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);
 
@@ -141,16 +143,21 @@ private:
         uint8_t iv[16];
         Vector<size_t> clearsizes;
         Vector<size_t> encryptedsizes;
     };
     Vector<Sample> mCurrentSamples;
 
     MPEG4Source(const MPEG4Source &);
     MPEG4Source &operator=(const MPEG4Source &);
+
+    bool ensureSrcBufferAllocated(int32_t size);
+    // Ensure that we have enough data in mMediaBuffer to copy our data.
+    // Returns false if not and clear mMediaBuffer.
+    bool ensureMediaBufferAllocated(int32_t size);
 };
 
 // This custom data source wraps an existing one and satisfies requests
 // falling entirely within a cached range from the cache while forwarding
 // all remaining requests to the wrapped datasource.
 // This is used to cache the full sampletable metadata for a single track,
 // possibly wrapping multiple times to cover all tracks, i.e.
 // Each MPEG4DataSource caches the sampletable metadata for a single track.
@@ -2449,35 +2456,34 @@ status_t MPEG4Source::start(MetaData *pa
 
     mGroup = new MediaBufferGroup;
 
     int32_t max_size;
     CHECK(mFormat->findInt32(kKeyMaxInputSize, &max_size));
 
     mGroup->add_buffer(new MediaBuffer(max_size));
 
-    mSrcBuffer = new uint8_t[max_size];
+    mSrcBuffer = mSrcBackend.Elements();
 
     mStarted = true;
 
     return OK;
 }
 
 status_t MPEG4Source::stop() {
     Mutex::Autolock autoLock(mLock);
 
     CHECK(mStarted);
 
     if (mBuffer != NULL) {
         mBuffer->release();
         mBuffer = NULL;
     }
 
-    delete[] mSrcBuffer;
-    mSrcBuffer = NULL;
+    mSrcBackend.Clear();
 
     delete mGroup;
     mGroup = NULL;
 
     mStarted = false;
     mCurrentSampleIndex = 0;
 
     return OK;
@@ -3026,16 +3032,40 @@ size_t MPEG4Source::parseNALSize(const u
 
     // This cannot happen, mNALLengthSize springs to life by adding 1 to
     // a 2-bit integer.
     CHECK(!"Should not be here.");
 
     return 0;
 }
 
+bool MPEG4Source::ensureSrcBufferAllocated(int32_t aSize) {
+    if (mSrcBackend.Length() >= aSize) {
+        return true;
+    }
+    if (!mSrcBackend.SetLength(aSize)) {
+        ALOGE("Error insufficient memory, requested %u bytes (had:%u)",
+              aSize, mSrcBackend.Length());
+        return false;
+    }
+    mSrcBuffer = mSrcBackend.Elements();
+    return true;
+}
+
+bool MPEG4Source::ensureMediaBufferAllocated(int32_t aSize) {
+  if (mBuffer->size() < aSize) {
+      ALOGE("Error insufficient memory, requested %u bytes (had:%u)",
+            aSize, mBuffer->size());
+      mBuffer->release();
+      mBuffer = NULL;
+      return false;
+  }
+  return true;
+}
+
 status_t MPEG4Source::read(
         MediaBuffer **out, const ReadOptions *options) {
     Mutex::Autolock autoLock(mLock);
 
     CHECK(mStarted);
 
     if (mFirstMoofOffset > 0) {
         return fragmentedRead(out, options);
@@ -3148,16 +3178,19 @@ status_t MPEG4Source::read(
         if (err != OK) {
             CHECK(mBuffer == NULL);
             return err;
         }
     }
 
     if (!mIsAVC || mWantsNALFragments) {
         if (newBuffer) {
+            if (!ensureMediaBufferAllocated(size)) {
+                return ERROR_MALFORMED;
+            }
             ssize_t num_bytes_read =
                 mDataSource->readAt(offset, (uint8_t *)mBuffer->data(), size);
 
             if (num_bytes_read < (ssize_t)size) {
                 mBuffer->release();
                 mBuffer = NULL;
 
                 return ERROR_IO;
@@ -3226,19 +3259,25 @@ status_t MPEG4Source::read(
         return OK;
     } else {
         // Whole NAL units are returned but each fragment is prefixed by
         // the start code (0x00 00 00 01).
         ssize_t num_bytes_read = 0;
         int32_t drm = 0;
         bool usesDRM = (mFormat->findInt32(kKeyIsDRM, &drm) && drm != 0);
         if (usesDRM) {
+            if (!ensureMediaBufferAllocated(size)) {
+                return ERROR_MALFORMED;
+            }
             num_bytes_read =
                 mDataSource->readAt(offset, (uint8_t*)mBuffer->data(), size);
         } else {
+            if (!ensureSrcBufferAllocated(size)) {
+                return ERROR_MALFORMED;
+            }
             num_bytes_read = mDataSource->readAt(offset, mSrcBuffer, size);
         }
 
         if (num_bytes_read < (ssize_t)size) {
             mBuffer->release();
             mBuffer = NULL;
 
             return ERROR_IO;
@@ -3268,17 +3307,19 @@ status_t MPEG4Source::read(
                     mBuffer = NULL;
                     return ERROR_MALFORMED;
                 }
 
                 if (nalLength == 0) {
                     continue;
                 }
 
-                CHECK(dstOffset + 4 <= mBuffer->size());
+                if (!ensureMediaBufferAllocated(dstOffset + 4 + nalLength)) {
+                    return ERROR_MALFORMED;
+                }
 
                 dstData[dstOffset++] = 0;
                 dstData[dstOffset++] = 0;
                 dstData[dstOffset++] = 0;
                 dstData[dstOffset++] = 1;
                 memcpy(&dstData[dstOffset], &mSrcBuffer[srcOffset], nalLength);
                 srcOffset += nalLength;
                 dstOffset += nalLength;
@@ -3423,16 +3464,19 @@ status_t MPEG4Source::fragmentedRead(
         bufmeta->setData(kKeyCryptoIV, 0, smpl->iv, 16); // use 16 or the actual size?
         bufmeta->setInt32(kKeyCryptoDefaultIVSize, mDefaultIVSize);
         bufmeta->setInt32(kKeyCryptoMode, mCryptoMode);
         bufmeta->setData(kKeyCryptoKey, 0, mCryptoKey, 16);
     }
 
     if (!mIsAVC || mWantsNALFragments) {
         if (newBuffer) {
+            if (!ensureMediaBufferAllocated(size)) {
+                return ERROR_MALFORMED;
+            }
             ssize_t num_bytes_read =
                 mDataSource->readAt(offset, (uint8_t *)mBuffer->data(), size);
 
             if (num_bytes_read < (ssize_t)size) {
                 mBuffer->release();
                 mBuffer = NULL;
 
                 ALOGV("i/o error");
@@ -3501,19 +3545,25 @@ status_t MPEG4Source::fragmentedRead(
     } else {
         ALOGV("whole NAL");
         // Whole NAL units are returned but each fragment is prefixed by
         // the start code (0x00 00 00 01).
         ssize_t num_bytes_read = 0;
         int32_t drm = 0;
         bool usesDRM = (mFormat->findInt32(kKeyIsDRM, &drm) && drm != 0);
         if (usesDRM) {
+            if (!ensureMediaBufferAllocated(size)) {
+                return ERROR_MALFORMED;
+            }
             num_bytes_read =
                 mDataSource->readAt(offset, (uint8_t*)mBuffer->data(), size);
         } else {
+            if (!ensureSrcBufferAllocated(size)) {
+                return ERROR_MALFORMED;
+            }
             num_bytes_read = mDataSource->readAt(offset, mSrcBuffer, size);
         }
 
         if (num_bytes_read < (ssize_t)size) {
             mBuffer->release();
             mBuffer = NULL;
 
             ALOGV("i/o error");
@@ -3544,17 +3594,19 @@ status_t MPEG4Source::fragmentedRead(
                     mBuffer = NULL;
                     return ERROR_MALFORMED;
                 }
 
                 if (nalLength == 0) {
                     continue;
                 }
 
-                CHECK(dstOffset + 4 <= mBuffer->size());
+                if (!ensureMediaBufferAllocated(dstOffset + 4 + nalLength)) {
+                    return ERROR_MALFORMED;
+                }
 
                 dstData[dstOffset++] = 0;
                 dstData[dstOffset++] = 0;
                 dstData[dstOffset++] = 0;
                 dstData[dstOffset++] = 1;
                 memcpy(&dstData[dstOffset], &mSrcBuffer[srcOffset], nalLength);
                 srcOffset += nalLength;
                 dstOffset += nalLength;
}
 

PSXHAX

Staff Member
Moderator
Contributor
Verified
Recent Articles
Sony Introduces New Summer Additions to PlayStation Hits Lineup
Since their update last fall, today Sony announced the new summer 2019 additions to their PlayStation Hits videogame lineup. 🎇🧨🎆 Featured titles include Horizon Zero Dawn: Complete Edition, God...
Luna, Mars Alive and Scraper: First Strike Join PlayStation VR Games
Following the PlayStation VR release of Vacation Simulator, Sony unveiled three new PS VR titles with launch trailer videos for Luna from Funomena now on PS Store, Mars Alive from Future Tech...
Metal Gear Solid HD Remake in Dreams on PS4 by Bearly Regal
Similar to what's been done with LittleBigPlanet customizing and recreations, recently Bearly Regal on Twitter shared a Metal Gear Solid HD Remake now playable in Dreams by Media Molecule on PS4...
Vacation Simulator Floats on PSVR Tomorrow, Launch Trailer Video
Those who'd love to take a vacation if they could only get away from work may want to check out Vacation Simulator releasing tomorrow for PS VR on PlayStation 4. ☀ ⛱ 🥥🌴🌊 Owlchemy Labs Tech...
Top