diff --git a/image/Decoder.cpp b/image/Decoder.cpp index 1194e218b673..13b0f0a5c313 100644 --- a/image/Decoder.cpp +++ b/image/Decoder.cpp @@ -405,6 +405,14 @@ Decoder::PostSize(int32_t aWidth, // Set our intrinsic size. mImageMetadata.SetSize(aWidth, aHeight, aOrientation); + // Verify it is the expected size, if given. Note that this is only used by + // the ICO decoder for embedded image types, so only its subdecoders are + // required to handle failures in PostSize. + if (!IsExpectedSize()) { + PostError(); + return; + } + // Set our output size if it's not already set. if (!mOutputSize) { mOutputSize = Some(IntSize(aWidth, aHeight)); diff --git a/image/Decoder.h b/image/Decoder.h index 3d8af3e89bfd..dce42476405f 100644 --- a/image/Decoder.h +++ b/image/Decoder.h @@ -215,6 +215,23 @@ public: */ Maybe ExplicitOutputSize() const; + /** + * Sets the expected image size of this decoder. Decoding will fail if this + * does not match. + */ + void SetExpectedSize(const gfx::IntSize& aSize) + { + mExpectedSize.emplace(aSize); + } + + /** + * Is the image size what was expected, if specified? + */ + bool IsExpectedSize() const + { + return mExpectedSize.isNothing() || *mExpectedSize == Size(); + } + /** * Set an iterator to the SourceBuffer which will feed data to this decoder. * This must always be called before calling Init(). (And only before Init().) @@ -527,6 +544,7 @@ private: ImageMetadata mImageMetadata; gfx::IntRect mInvalidRect; // Tracks an invalidation region in the current frame. Maybe mOutputSize; // The size of our output surface. + Maybe mExpectedSize; // The expected size of the image. Progress mProgress; uint32_t mFrameCount; // Number of frames, including anything in-progress diff --git a/image/DecoderFactory.cpp b/image/DecoderFactory.cpp index 2b5dd5f28f85..bafbc929ae63 100644 --- a/image/DecoderFactory.cpp +++ b/image/DecoderFactory.cpp @@ -236,6 +236,7 @@ DecoderFactory::CreateMetadataDecoder(DecoderType aType, DecoderFactory::CreateDecoderForICOResource(DecoderType aType, NotNull aSourceBuffer, NotNull aICODecoder, + const Maybe& aExpectedSize, const Maybe& aDataOffset /* = Nothing() */) { @@ -264,6 +265,9 @@ DecoderFactory::CreateDecoderForICOResource(DecoderType aType, decoder->SetMetadataDecode(aICODecoder->IsMetadataDecode()); decoder->SetIterator(aSourceBuffer->Iterator()); decoder->SetOutputSize(aICODecoder->OutputSize()); + if (aExpectedSize) { + decoder->SetExpectedSize(*aExpectedSize); + } decoder->SetDecoderFlags(aICODecoder->GetDecoderFlags()); decoder->SetSurfaceFlags(aICODecoder->GetSurfaceFlags()); decoder->SetFinalizeFrames(false); diff --git a/image/DecoderFactory.h b/image/DecoderFactory.h index fd2a4f04c24d..97780efbfbe7 100644 --- a/image/DecoderFactory.h +++ b/image/DecoderFactory.h @@ -126,6 +126,7 @@ public: * resource decoder, so the two decoders will have the * same decoder flags, surface flags, target size, and * other parameters. + * @param aExpectedSize The expected size of the resource from the ICO header. * @param aDataOffset If @aType is BMP, specifies the offset at which data * begins in the BMP resource. Must be Some() if and only * if @aType is BMP. @@ -134,6 +135,7 @@ public: CreateDecoderForICOResource(DecoderType aType, NotNull aSourceBuffer, NotNull aICODecoder, + const Maybe& aExpectedSize, const Maybe& aDataOffset = Nothing()); /** diff --git a/image/decoders/nsBMPDecoder.cpp b/image/decoders/nsBMPDecoder.cpp index 1f0449e4e672..83078219a8e5 100644 --- a/image/decoders/nsBMPDecoder.cpp +++ b/image/decoders/nsBMPDecoder.cpp @@ -650,6 +650,9 @@ nsBMPDecoder::ReadBitfields(const char* aData, size_t aLength) // Post our size to the superclass. PostSize(mH.mWidth, AbsoluteHeight()); + if (HasError()) { + return Transition::TerminateFailure(); + } // We've now read all the headers. If we're doing a metadata decode, we're // done. diff --git a/image/decoders/nsICODecoder.cpp b/image/decoders/nsICODecoder.cpp index d8171431ea83..0a86ff18239c 100644 --- a/image/decoders/nsICODecoder.cpp +++ b/image/decoders/nsICODecoder.cpp @@ -281,6 +281,10 @@ nsICODecoder::ReadDirEntry(const char* aData) // is necessary for downscale-during-decode to work since we won't even // attempt to *upscale* while decoding. PostSize(mBiggestResourceSize.width, mBiggestResourceSize.height); + if (HasError()) { + return Transition::TerminateFailure(); + } + if (IsMetadataDecode()) { return Transition::TerminateSuccess(); } @@ -316,7 +320,8 @@ nsICODecoder::SniffResource(const char* aData) mContainedDecoder = DecoderFactory::CreateDecoderForICOResource(DecoderType::PNG, WrapNotNull(mContainedSourceBuffer), - WrapNotNull(this)); + WrapNotNull(this), + Some(GetRealSize())); if (!WriteToContainedDecoder(aData, PNGSIGNATURESIZE)) { return Transition::TerminateFailure(); @@ -395,6 +400,7 @@ nsICODecoder::ReadBIH(const char* aData) DecoderFactory::CreateDecoderForICOResource(DecoderType::BMP, WrapNotNull(mContainedSourceBuffer), WrapNotNull(this), + Some(GetRealSize()), Some(dataOffset)); RefPtr bmpDecoder = static_cast(mContainedDecoder.get());