[OpenJDK 2D-Dev] [11] RFR JDK-8191023: PngReader throws NegativeArraySizeException when keyword length exceeds chunk size

Prahalad Kumar Narayanan prahalad.kumar.narayanan at oracle.com
Tue Jan 23 07:17:41 UTC 2018

Hello Jay

The existing verification of CRC value with already stored value is only to ensure we have processed right amount of data.
This is done at the end and is explained in the comments at Line 853. It does not validate whether a chunk (length/ data) is valid upfront.

Here is the code: 
 728                 try {
 729                     stream.mark();
 730                     stream.seek(stream.getStreamPosition() + chunkLength);
 731                     chunkCRC = stream.readInt();
 732                     stream.reset();
 733                 } catch (IOException e) {
 734                     throw new IIOException("Invalid chunk length " + chunkLength);
 735                 }
 737                 switch (chunkType) {

 853                 // double check whether all chunk data were consumed
 854                 if (chunkCRC != stream.readInt()) {
 855                     throw new IIOException("Failed to read a chunk of type " +
 856                             chunkType);
 857                 }

My suggestion was to -
. 'Generate' CRC from Chunk data and compare it with the retrieved value at Line 731 'before' proceeding to process any of the chunks.
. In mal-formed chunks (corrupted chunk length /or chunk data), the CRC check will fail thus giving an effective way to identify a valid chunk.
. Many of the if (...) conditions that 've been added to parse_<Chunk> methods can be avoided with CRC check done upfront.

Hope this helps.

Thank you
Have a good day

Prahalad N.

-----Original Message-----
From: Jayathirth D V 
Sent: Tuesday, January 23, 2018 12:18 PM
To: Prahalad Kumar Narayanan; 2d-dev
Subject: RE: [OpenJDK 2D-Dev] [11] RFR JDK-8191023: PngReader throws NegativeArraySizeException when keyword length exceeds chunk size

Hi Prahalad,

Thanks for providing your inputs.

Regarding the CRC check, as of now in PNGImageReader.readMetadata() we store CRC value for each chunk based on read chunk length before parsing them and after parsing a given chunk we verify the CRC value at the end of the chunk with already stored value. If they differ we throw IIOException. Please let me know if you are suggesting some other logic related to CRC check.

Also we check negative chunk length value and throw IIOException before we start parsing a chunk.

Main issue in this bug is while we are parsing a chunk, we use the available chunk length to determine the remaining length that should be parsed. So only when we parse these individual chunks we get to know the data present in them like keyword.length(). In our test sample scenario we hit a condition while we are parsing where the present chunk length is less than keyword.length() and when we try to create byte array using this value we hit NegativeArraySizeException. We will not reach this problem scenario until we parse these individual chunks.

Regarding the problem in other PNG chunks, I went through all the chunk parsing functions and wherever I saw that we are using available chunk length and subtracting some value from it and it might cause NegativeArraySizeException I have added additional checks(in sPLT & tRNS).

Please find updated webrev for review :


-----Original Message-----
From: Prahalad Kumar Narayanan 
Sent: Tuesday, January 23, 2018 8:24 AM
To: Jayathirth D V; 2d-dev
Subject: RE: [OpenJDK 2D-Dev] [11] RFR JDK-8191023: PngReader throws NegativeArraySizeException when keyword length exceeds chunk size

Hello Jay

I looked into the bug and the fix.

The root cause of the problem is mal-formed "chunk length" field.
Thus the available chunk data to decode could either be larger (or) lesser than the value of "chunk length".

The bug seems to target one specific case- where available data is larger than value of "Chunk length". Moreover bug targets few chunks alone.

When a "chunk length" is mal-formed, exceptions could be triggered while reading any data (not just the case indicated by the bug).
There are 4 critical chunks and as many as 12 ancillary chunks that may appear in a PNG stream.
Adding checks for every individual case would flood the PNG image reader with if (...) checks.

Can you think of any better solution to detect mal-formed "chunk length" and chunk data ? 

How about using the chunk's CRC field ?
You could generate CRC with data read from the stream and compare it against the CRC stored for the chunk to validate.

Thank you
Have a good day

Prahalad N.

----- Original Message -----
From: Jayathirth D V 
Sent: Monday, January 22, 2018 4:20 PM
To: 2d-dev
Subject: [OpenJDK 2D-Dev] [11] RFR JDK-8191023: PngReader throws NegativeArraySizeException when keyword length exceeds chunk size

Hello All,

Please review the following fix in JDK11 :

Bug : https://bugs.openjdk.java.net/browse/JDK-8191023 
Webrev : http://cr.openjdk.java.net/~jdv/8191023/webrev.00/ 

Note : Submitter has raised 3 bugs JDK-8191023 , JDK-8191076 , JDK-8191109 with similar issue but in 3 different PNG chunks. I have closed two bugs and kept first opened JBS bug for this issue. From the closed bug test samples are picked and merged into one test case.

Issue: When the issue was reported PNGImageReader was throwing NegativeArraySizeException when chunk length is malformed and it exceeds keyword length. After changes present in https://bugs.openjdk.java.net/browse/JDK-8190332 the NegativeArraySizeException is wrapped inside IIOException.

Exception in thread "main" javax.imageio.IIOException: Caught exception during read: 
at java.desktop/com.sun.imageio.plugins.png.PNGImageReader.read(PNGImageReader.java:1707) 
at java.desktop/javax.imageio.ImageIO.read(ImageIO.java:1468) 
at java.desktop/javax.imageio.ImageIO.read(ImageIO.java:1363) 
at PngReaderTextChunkKeywordSizeTest.main(PngReaderTextChunkKeywordSizeTest.java:19) 
Caused by: java.lang.NegativeArraySizeException 
at java.desktop/com.sun.imageio.plugins.png.PNGImageReader.parse_tEXt_chunk(PNGImageReader.java:563) 
at java.desktop/com.sun.imageio.plugins.png.PNGImageReader.readMetadata(PNGImageReader.java:816) 
at java.desktop/com.sun.imageio.plugins.png.PNGImageReader.readImage(PNGImageReader.java:1331) 
at java.desktop/com.sun.imageio.plugins.png.PNGImageReader.read(PNGImageReader.java:1700)

Root cause : Since the chunk length present is lesser than keyword length. When we try to parse individual chunks and create byte Array to store remaining data in the chunk. We calculate the byte array size from chunk length and size of alreadt parsed data like keyword (like chunkLength - keyword.length() - 2). This results in negative value and it causes NegativeArraySizeException when we try to create the byte Array.

Solution: Add check in parse function of all the individual chunks to check for negative value for the size of the remaining data to be stored. We have PNG stream data from 3 bugs with which we can reproduce this issue for zTXt, tEXt and iCCP chunk but we don't have stream data for iTXt chunk but still I have added similar check in parse_iTXt_chunk() function also.


More information about the 2d-dev mailing list