Bug 1315554 - Part 1. Enforce the parent decoder size (ICO) for child decoders (BMP, PNG). r=tnikkel

This commit is contained in:
Andrew Osmond 2017-07-22 07:50:31 -04:00
parent 6319821925
commit ac14e4f8f5
6 changed files with 42 additions and 1 deletions

View File

@ -405,6 +405,14 @@ Decoder::PostSize(int32_t aWidth,
// Set our intrinsic size. // Set our intrinsic size.
mImageMetadata.SetSize(aWidth, aHeight, aOrientation); 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. // Set our output size if it's not already set.
if (!mOutputSize) { if (!mOutputSize) {
mOutputSize = Some(IntSize(aWidth, aHeight)); mOutputSize = Some(IntSize(aWidth, aHeight));

View File

@ -215,6 +215,23 @@ public:
*/ */
Maybe<gfx::IntSize> ExplicitOutputSize() const; Maybe<gfx::IntSize> 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. * 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().) * This must always be called before calling Init(). (And only before Init().)
@ -527,6 +544,7 @@ private:
ImageMetadata mImageMetadata; ImageMetadata mImageMetadata;
gfx::IntRect mInvalidRect; // Tracks an invalidation region in the current frame. gfx::IntRect mInvalidRect; // Tracks an invalidation region in the current frame.
Maybe<gfx::IntSize> mOutputSize; // The size of our output surface. Maybe<gfx::IntSize> mOutputSize; // The size of our output surface.
Maybe<gfx::IntSize> mExpectedSize; // The expected size of the image.
Progress mProgress; Progress mProgress;
uint32_t mFrameCount; // Number of frames, including anything in-progress uint32_t mFrameCount; // Number of frames, including anything in-progress

View File

@ -236,6 +236,7 @@ DecoderFactory::CreateMetadataDecoder(DecoderType aType,
DecoderFactory::CreateDecoderForICOResource(DecoderType aType, DecoderFactory::CreateDecoderForICOResource(DecoderType aType,
NotNull<SourceBuffer*> aSourceBuffer, NotNull<SourceBuffer*> aSourceBuffer,
NotNull<nsICODecoder*> aICODecoder, NotNull<nsICODecoder*> aICODecoder,
const Maybe<IntSize>& aExpectedSize,
const Maybe<uint32_t>& aDataOffset const Maybe<uint32_t>& aDataOffset
/* = Nothing() */) /* = Nothing() */)
{ {
@ -264,6 +265,9 @@ DecoderFactory::CreateDecoderForICOResource(DecoderType aType,
decoder->SetMetadataDecode(aICODecoder->IsMetadataDecode()); decoder->SetMetadataDecode(aICODecoder->IsMetadataDecode());
decoder->SetIterator(aSourceBuffer->Iterator()); decoder->SetIterator(aSourceBuffer->Iterator());
decoder->SetOutputSize(aICODecoder->OutputSize()); decoder->SetOutputSize(aICODecoder->OutputSize());
if (aExpectedSize) {
decoder->SetExpectedSize(*aExpectedSize);
}
decoder->SetDecoderFlags(aICODecoder->GetDecoderFlags()); decoder->SetDecoderFlags(aICODecoder->GetDecoderFlags());
decoder->SetSurfaceFlags(aICODecoder->GetSurfaceFlags()); decoder->SetSurfaceFlags(aICODecoder->GetSurfaceFlags());
decoder->SetFinalizeFrames(false); decoder->SetFinalizeFrames(false);

View File

@ -126,6 +126,7 @@ public:
* resource decoder, so the two decoders will have the * resource decoder, so the two decoders will have the
* same decoder flags, surface flags, target size, and * same decoder flags, surface flags, target size, and
* other parameters. * 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 * @param aDataOffset If @aType is BMP, specifies the offset at which data
* begins in the BMP resource. Must be Some() if and only * begins in the BMP resource. Must be Some() if and only
* if @aType is BMP. * if @aType is BMP.
@ -134,6 +135,7 @@ public:
CreateDecoderForICOResource(DecoderType aType, CreateDecoderForICOResource(DecoderType aType,
NotNull<SourceBuffer*> aSourceBuffer, NotNull<SourceBuffer*> aSourceBuffer,
NotNull<nsICODecoder*> aICODecoder, NotNull<nsICODecoder*> aICODecoder,
const Maybe<gfx::IntSize>& aExpectedSize,
const Maybe<uint32_t>& aDataOffset = Nothing()); const Maybe<uint32_t>& aDataOffset = Nothing());
/** /**

View File

@ -650,6 +650,9 @@ nsBMPDecoder::ReadBitfields(const char* aData, size_t aLength)
// Post our size to the superclass. // Post our size to the superclass.
PostSize(mH.mWidth, AbsoluteHeight()); 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 // We've now read all the headers. If we're doing a metadata decode, we're
// done. // done.

View File

@ -281,6 +281,10 @@ nsICODecoder::ReadDirEntry(const char* aData)
// is necessary for downscale-during-decode to work since we won't even // is necessary for downscale-during-decode to work since we won't even
// attempt to *upscale* while decoding. // attempt to *upscale* while decoding.
PostSize(mBiggestResourceSize.width, mBiggestResourceSize.height); PostSize(mBiggestResourceSize.width, mBiggestResourceSize.height);
if (HasError()) {
return Transition::TerminateFailure();
}
if (IsMetadataDecode()) { if (IsMetadataDecode()) {
return Transition::TerminateSuccess(); return Transition::TerminateSuccess();
} }
@ -316,7 +320,8 @@ nsICODecoder::SniffResource(const char* aData)
mContainedDecoder = mContainedDecoder =
DecoderFactory::CreateDecoderForICOResource(DecoderType::PNG, DecoderFactory::CreateDecoderForICOResource(DecoderType::PNG,
WrapNotNull(mContainedSourceBuffer), WrapNotNull(mContainedSourceBuffer),
WrapNotNull(this)); WrapNotNull(this),
Some(GetRealSize()));
if (!WriteToContainedDecoder(aData, PNGSIGNATURESIZE)) { if (!WriteToContainedDecoder(aData, PNGSIGNATURESIZE)) {
return Transition::TerminateFailure(); return Transition::TerminateFailure();
@ -395,6 +400,7 @@ nsICODecoder::ReadBIH(const char* aData)
DecoderFactory::CreateDecoderForICOResource(DecoderType::BMP, DecoderFactory::CreateDecoderForICOResource(DecoderType::BMP,
WrapNotNull(mContainedSourceBuffer), WrapNotNull(mContainedSourceBuffer),
WrapNotNull(this), WrapNotNull(this),
Some(GetRealSize()),
Some(dataOffset)); Some(dataOffset));
RefPtr<nsBMPDecoder> bmpDecoder = RefPtr<nsBMPDecoder> bmpDecoder =
static_cast<nsBMPDecoder*>(mContainedDecoder.get()); static_cast<nsBMPDecoder*>(mContainedDecoder.get());