Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Png- Do not attempt to read data for chunks of length 0. #2561

Merged
merged 4 commits into from
Nov 29, 2023

Conversation

JimBobSquarePants
Copy link
Member

Prerequisites

  • I have written a descriptive pull-request title
  • I have verified that there are no overlapping pull-requests open
  • I have verified that I am following the existing coding patterns and practice as demonstrated in the repository. These follow strict Stylecop rules 👮.
  • I have provided test coverage for my change (where applicable)

Description

Png was attempting to read chunk data for chunks of length 0, for example EOF. This lead, to multiple attempts to read past the end of a stream.

@@ -1569,6 +1570,11 @@ private void SkipChunkDataAndCrc(in PngChunk chunk)
[MethodImpl(InliningOptions.ShortMethod)]
private IMemoryOwner<byte> ReadChunkData(int length)
{
if (length == 0)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We avoid the read here because Png still has to do a CRC check which if does not occur leads to failure during reading of chained Png images within a single stream.

Copy link
Member

@antonfirsov antonfirsov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The behavior with these changes is still odd: we run through the stream with ~500 attempts to read a 0-byte chunk. It doesn't look like the correct/optimal thing to do for such an input.

This code doesn't look correct to me:

while (length < 0 || length > (this.currentStream.Length - this.currentStream.Position))
{
// Not a valid chunk so try again until we reach a known chunk.
if (!this.TryReadChunkLength(buffer, out length))
{
chunk = default;
return false;
}
}

If length > (this.currentStream.Length - this.currentStream.Position) because the file is truncated, we just start interpreting the following (type/data) bytes as length until length becomes 0. If we really don't want to throw/abort here, why not to process the chunk in the truncated form instead?

Edit: I guess there was some corrupt input this was logic was introduced for but is this really the best we can do?

@JimBobSquarePants
Copy link
Member Author

The behavior with these changes is still odd: we run through the stream with ~500 attempts to read a 0-byte chunk. It doesn't look like the correct/optimal thing to do for such an input.

This code doesn't look correct to me:

while (length < 0 || length > (this.currentStream.Length - this.currentStream.Position))
{
// Not a valid chunk so try again until we reach a known chunk.
if (!this.TryReadChunkLength(buffer, out length))
{
chunk = default;
return false;
}
}

If length > (this.currentStream.Length - this.currentStream.Position) because the file is truncated, we just start interpreting the following (type/data) bytes as length until length becomes 0. If we really don't want to throw/abort here, why not to process the chunk in the truncated form instead?

Edit: I guess there was some corrupt input this was logic was introduced for but is this really the best we can do?

Is it the best we can do?

We differ from libpng here. We continue reading after parsing a length greater than 2147483647 while libpng will throw.

https://github.com/glennrp/libpng/blob/f2294569cfe43f87c9f72d35545e8de1126eb4b9/pngrutil.c#L22-L30

libpng doesn't seem to do the inner check.
https://github.com/glennrp/libpng/blob/libpng16/pngrutil.c#L156-L192

However, it seems to freely loop like we do. I'm not sure there's a better way to detect chunks while skipping corrupted sections.
https://github.com/glennrp/libpng/blob/f2294569cfe43f87c9f72d35545e8de1126eb4b9/pngread.c#L106-L262

@JimBobSquarePants JimBobSquarePants added this to the v3.1.0 milestone Oct 23, 2023
@JimBobSquarePants
Copy link
Member Author

JimBobSquarePants commented Nov 29, 2023

I recked our suite of tests while disabling that section and we only had the one failing image. I don't think we'll hit that path often at all and it's the only way I think that we can be skip bad sections.

@JimBobSquarePants JimBobSquarePants merged commit 6cf09dc into main Nov 29, 2023
8 checks passed
@JimBobSquarePants JimBobSquarePants deleted the js/faster-png-eof-handling branch November 29, 2023 08:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants