From dcd8fcb072c3a47c991d05f58a691371688a960d Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Tue, 20 Jan 2015 13:42:27 +1100 Subject: [PATCH] Bug 1116056: Ensure all atoms read are valid. r=mattwoodrow --HG-- extra : rebase_source : 6d5575bd0886b70dec23e1bccb638b1591eef5e9 --- media/libstagefright/binding/Box.cpp | 2 +- media/libstagefright/binding/MoofParser.cpp | 108 +++++++++++++++++- .../binding/include/mp4_demuxer/ByteReader.h | 4 +- .../binding/include/mp4_demuxer/MoofParser.h | 54 +++++++-- 4 files changed, 148 insertions(+), 20 deletions(-) diff --git a/media/libstagefright/binding/Box.cpp b/media/libstagefright/binding/Box.cpp index 886345036d26..5f442338341c 100644 --- a/media/libstagefright/binding/Box.cpp +++ b/media/libstagefright/binding/Box.cpp @@ -94,7 +94,7 @@ Box::Read(nsTArray* aDest) { aDest->SetLength(mRange.mEnd - mChildOffset); size_t bytes; - if (!mContext->mSource->CachedReadAt(mChildOffset, &(*aDest)[0], + if (!mContext->mSource->CachedReadAt(mChildOffset, aDest->Elements(), aDest->Length(), &bytes) || bytes != aDest->Length()) { // Byte ranges are being reported incorrectly diff --git a/media/libstagefright/binding/MoofParser.cpp b/media/libstagefright/binding/MoofParser.cpp index 39876e9529a3..e73f7bc1a8d3 100644 --- a/media/libstagefright/binding/MoofParser.cpp +++ b/media/libstagefright/binding/MoofParser.cpp @@ -286,21 +286,43 @@ public: void Moof::ParseTrun(Box& aBox, Tfhd& aTfhd, Tfdt& aTfdt, Mdhd& aMdhd, Edts& aEdts) { - if (!aMdhd.mTimescale) { + if (!aTfhd.IsValid() || !aTfdt.IsValid() || + !aMdhd.IsValid() || !aEdts.IsValid()) { return; } BoxReader reader(aBox); + if (!reader->CanReadType()) { + return; + } uint32_t flags = reader->ReadU32(); if ((flags & 0x404) == 0x404) { // Can't use these flags together reader->DiscardRemaining(); + mValid = true; return; } uint8_t version = flags >> 24; + if (!reader->CanReadType()) { + return; + } uint32_t sampleCount = reader->ReadU32(); if (sampleCount == 0) { + mValid = true; + return; + } + + size_t need = + ((flags & 1) ? sizeof(uint32_t) : 0) + + ((flags & 4) ? sizeof(uint32_t) : 0); + uint16_t flag[] = { 0x100, 0x200, 0x400, 0x800, 0 }; + for (size_t i = 0; flag[i]; i++) { + if (flags & flag[i]) { + need += sizeof(uint32_t) * sampleCount; + } + } + if (reader->Remaining() < need) { return; } @@ -354,13 +376,22 @@ Moof::ParseTrun(Box& aBox, Tfhd& aTfhd, Tfdt& aTfdt, Mdhd& aMdhd, Edts& aEdts) } mTimeRange = Interval(ctsOrder[0]->mCompositionRange.start, ctsOrder.LastElement()->mCompositionRange.end); + mValid = true; } Tkhd::Tkhd(Box& aBox) { BoxReader reader(aBox); + if (!reader->CanReadType()) { + return; + } uint32_t flags = reader->ReadU32(); uint8_t version = flags >> 24; + size_t need = + 3*(version ? sizeof(int64_t) : sizeof(int32_t)) + 2*sizeof(int32_t); + if (reader->Remaining() < need) { + return; + } if (version == 0) { mCreationTime = reader->ReadU32(); mModificationTime = reader->ReadU32(); @@ -378,13 +409,23 @@ Tkhd::Tkhd(Box& aBox) } // More stuff that we don't care about reader->DiscardRemaining(); + mValid = true; } Mdhd::Mdhd(Box& aBox) { BoxReader reader(aBox); + if (!reader->CanReadType()) { + return; + } uint32_t flags = reader->ReadU32(); uint8_t version = flags >> 24; + size_t need = + 3*(version ? sizeof(int64_t) : sizeof(int32_t)) + 2*sizeof(uint32_t); + if (reader->Remaining() < need) { + return; + } + if (version == 0) { mCreationTime = reader->ReadU32(); mModificationTime = reader->ReadU32(); @@ -398,17 +439,24 @@ Mdhd::Mdhd(Box& aBox) } // language and pre_defined=0 reader->ReadU32(); + if (mTimescale) { + mValid = true; + } } Trex::Trex(Box& aBox) { BoxReader reader(aBox); + if (reader->Remaining() < 6*sizeof(uint32_t)) { + return; + } mFlags = reader->ReadU32(); mTrackId = reader->ReadU32(); mDefaultSampleDescriptionIndex = reader->ReadU32(); mDefaultSampleDuration = reader->ReadU32(); mDefaultSampleSize = reader->ReadU32(); mDefaultSampleFlags = reader->ReadU32(); + mValid = true; } Tfhd::Tfhd(Box& aBox, Trex& aTrex) : Trex(aTrex) @@ -418,7 +466,20 @@ Tfhd::Tfhd(Box& aBox, Trex& aTrex) : Trex(aTrex) MOZ_ASSERT(aBox.Parent()->Parent()->IsType("moof")); BoxReader reader(aBox); + if (!reader->CanReadType()) { + return; + } mFlags = reader->ReadU32(); + size_t need = sizeof(uint32_t) /* trackid */; + uint8_t flag[] = { 1, 2, 8, 0x10, 0x20, 0 }; + for (size_t i = 0; flag[i]; i++) { + if (mFlags & flag[i]) { + need += sizeof(uint32_t); + } + } + if (reader->Remaining() < need) { + return; + } mBaseDataOffset = mFlags & 1 ? reader->ReadU32() : aBox.Parent()->Parent()->Offset(); mTrackId = reader->ReadU32(); @@ -434,19 +495,28 @@ Tfhd::Tfhd(Box& aBox, Trex& aTrex) : Trex(aTrex) if (mFlags & 0x20) { mDefaultSampleFlags = reader->ReadU32(); } + mValid = true; } Tfdt::Tfdt(Box& aBox) { BoxReader reader(aBox); + if (!reader->CanReadType()) { + return; + } uint32_t flags = reader->ReadU32(); uint8_t version = flags >> 24; + size_t need = version ? sizeof(uint64_t) : sizeof(uint32_t) ; + if (reader->Remaining() < need) { + return; + } if (version == 0) { mBaseMediaDecodeTime = reader->ReadU32(); } else if (version == 1) { mBaseMediaDecodeTime = reader->ReadU64(); } reader->DiscardRemaining(); + mValid = true; } Edts::Edts(Box& aBox) @@ -458,9 +528,16 @@ Edts::Edts(Box& aBox) } BoxReader reader(child); + if (!reader->CanReadType()) { + return; + } uint32_t flags = reader->ReadU32(); uint8_t version = flags >> 24; - + size_t need = + sizeof(uint32_t) + 2*(version ? sizeof(int64_t) : sizeof(uint32_t)); + if (reader->Remaining() < need) { + return; + } uint32_t entryCount = reader->ReadU32(); NS_ASSERTION(entryCount == 1, "Can't handle videos with multiple edits"); if (entryCount != 1) { @@ -483,9 +560,16 @@ Edts::Edts(Box& aBox) Saiz::Saiz(Box& aBox) : mAuxInfoType("sinf"), mAuxInfoTypeParameter(0) { BoxReader reader(aBox); + if (!reader->CanReadType()) { + return; + } uint32_t flags = reader->ReadU32(); uint8_t version = flags >> 24; - + size_t need = + ((flags & 1) ? 2*sizeof(uint32_t) : 0) + sizeof(uint8_t) + sizeof(uint32_t); + if (reader->Remaining() < need) { + return; + } if (flags & 1) { mAuxInfoType = reader->ReadU32(); mAuxInfoTypeParameter = reader->ReadU32(); @@ -497,21 +581,34 @@ Saiz::Saiz(Box& aBox) : mAuxInfoType("sinf"), mAuxInfoTypeParameter(0) mSampleInfoSize.AppendElement(defaultSampleInfoSize); } } else { - reader->ReadArray(mSampleInfoSize, count); + if (!reader->ReadArray(mSampleInfoSize, count)) { + return; + } } + mValid = true; } Saio::Saio(Box& aBox) : mAuxInfoType("sinf"), mAuxInfoTypeParameter(0) { BoxReader reader(aBox); + if (!reader->CanReadType()) { + return; + } uint32_t flags = reader->ReadU32(); uint8_t version = flags >> 24; - + size_t need = ((flags & 1) ? (2*sizeof(uint32_t)) : 0) + sizeof(uint32_t); + if (reader->Remaining() < need) { + return; + } if (flags & 1) { mAuxInfoType = reader->ReadU32(); mAuxInfoTypeParameter = reader->ReadU32(); } size_t count = reader->ReadU32(); + need = (version ? sizeof(uint64_t) : sizeof(uint32_t)) * count; + if (reader->Remaining() < count) { + return; + } mOffsets.SetCapacity(count); if (version == 0) { for (size_t i = 0; i < count; i++) { @@ -522,5 +619,6 @@ Saio::Saio(Box& aBox) : mAuxInfoType("sinf"), mAuxInfoTypeParameter(0) mOffsets.AppendElement(reader->ReadU64()); } } + mValid = true; } } diff --git a/media/libstagefright/binding/include/mp4_demuxer/ByteReader.h b/media/libstagefright/binding/include/mp4_demuxer/ByteReader.h index 8f7e08c84fcc..35d5e1aa4546 100644 --- a/media/libstagefright/binding/include/mp4_demuxer/ByteReader.h +++ b/media/libstagefright/binding/include/mp4_demuxer/ByteReader.h @@ -36,14 +36,14 @@ public: void SetData(const nsTArray& aData) { MOZ_ASSERT(!mPtr && !mRemaining); - mPtr = &aData[0]; + mPtr = aData.Elements(); mRemaining = aData.Length(); mLength = mRemaining; } ~ByteReader() { - MOZ_ASSERT(!mRemaining); + NS_ASSERTION(!mRemaining, "Not all bytes have been processed"); } size_t Offset() diff --git a/media/libstagefright/binding/include/mp4_demuxer/MoofParser.h b/media/libstagefright/binding/include/mp4_demuxer/MoofParser.h index e76e22297c34..94bfd2d5ea2f 100644 --- a/media/libstagefright/binding/include/mp4_demuxer/MoofParser.h +++ b/media/libstagefright/binding/include/mp4_demuxer/MoofParser.h @@ -16,7 +16,22 @@ class Box; class BoxContext; class Moof; -class Tkhd +class Atom +{ +public: + Atom() + : mValid(false) + { + } + virtual bool IsValid() + { + return mValid; + } +protected: + bool mValid; +}; + +class Tkhd : public Atom { public: Tkhd() @@ -34,7 +49,7 @@ public: uint64_t mDuration; }; -class Mdhd +class Mdhd : public Atom { public: Mdhd() @@ -57,7 +72,7 @@ public: uint64_t mDuration; }; -class Trex +class Trex : public Atom { public: explicit Trex(uint32_t aTrackId) @@ -83,26 +98,42 @@ public: class Tfhd : public Trex { public: - explicit Tfhd(Trex& aTrex) : Trex(aTrex), mBaseDataOffset(0) {} + explicit Tfhd(Trex& aTrex) + : Trex(aTrex) + , mBaseDataOffset(0) + { + mValid = aTrex.IsValid(); + } Tfhd(Box& aBox, Trex& aTrex); uint64_t mBaseDataOffset; }; -class Tfdt +class Tfdt : public Atom { public: - Tfdt() : mBaseMediaDecodeTime(0) {} + Tfdt() + : mBaseMediaDecodeTime(0) + { + } explicit Tfdt(Box& aBox); uint64_t mBaseMediaDecodeTime; }; -class Edts +class Edts : public Atom { public: - Edts() : mMediaStart(0) {} + Edts() + : mMediaStart(0) + { + } explicit Edts(Box& aBox); + virtual bool IsValid() + { + // edts is optional + return true; + } int64_t mMediaStart; }; @@ -116,7 +147,7 @@ struct Sample bool mSync; }; -class Saiz +class Saiz : public Atom { public: explicit Saiz(Box& aBox); @@ -126,7 +157,7 @@ public: nsTArray mSampleInfoSize; }; -class Saio +class Saio : public Atom { public: explicit Saio(Box& aBox); @@ -142,13 +173,12 @@ public: bool GetByteRanges(nsTArray* aByteRanges); private: - int64_t mMoofOffset; Saiz& mSaiz; Saio& mSaio; }; -class Moof +class Moof : public Atom { public: Moof(Box& aBox, Trex& aTrex, Mdhd& aMdhd, Edts& aEdts, Microseconds aTimestampOffset);