Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8191023

PngReader throws NegativeArraySizeException when keyword length exceeds chunk size

    Details

    • Subcomponent:
    • Resolved In Build:
      b01
    • CPU:
      x86_64
    • OS:
      generic

      Description

      FULL PRODUCT VERSION :
      openjdk version "9.0.1"
      OpenJDK Runtime Environment (build 9.0.1+11)
      OpenJDK 64-Bit Server VM (build 9.0.1+11, mixed mode)

      ADDITIONAL OS VERSION INFORMATION :
      Ubuntu Linux 64-bit

      A DESCRIPTION OF THE PROBLEM :
      The ImageReader com.sun.imageio.plugins.png.PNGImageReader throws a NegativeArraySizeException when attempting to read malformed PNG image files that contain tEXt sections containing keywords that are larger than the length of the tEXt chunk.

      The PNG specification defines a tEXt chunk as follows: Upto 80 bytes of a null-terminated "keyword" followed by a textual section of length N: the total length of the chunk, say chunkLength, should be N + keyword.length() + 1. Therefore, the textual section contains N = chunkLength - keyword.length() - 1 bytes, and N must be greater or equal to zero.

      However, when keyword.length() >= chunkLength, the PngImageReader calculates N to be a negative value and attempts to allocate a negative-sized array for the textual section, resulting in a NegativeArraySizeException to be thrown in parse_tEXt_chunk(). Instead, an IOException should be thrown as the PNG input is malformed if a null byte is not found within tEXt chunk length.


      A suggested fix is to replace this line in PngImageReader#parse_tEXt_chunk():
        byte[] b = new byte[chunkLength - keyword.length() - 1];

      with:
        int n = chunkLength - keyword.length() - 1;
        if (n < 0 || keyword.length() == 80) {
           throw new IIOException("tEXt chunk length is smaller than keyword size");
        }
        byte[] b = new byte[n];

      The second condition is required because reading in the keyword with `readNullTerminatedString("ISO-8859-1", 80)` does not guarantee that a null byte has been read; the chunk is still malformed if 80 non-null bytes are read in the beginning of the chunk.

      This bug was found using AFL.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Compile and run the test program attached below.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      An IOException should be thrown (e.g. javax.imagio.IIOException).
      ACTUAL -
      A java.lang.NegativeArraySizeException is thrown.

      ERROR MESSAGES/STACK TRACES THAT OCCUR :
      Exception in thread "main" java.lang.NegativeArraySizeException
      at java.desktop/com.sun.imageio.plugins.png.PNGImageReader.parse_tEXt_chunk(PNGImageReader.java:555)
      at java.desktop/com.sun.imageio.plugins.png.PNGImageReader.readMetadata(PNGImageReader.java:757)
      at java.desktop/com.sun.imageio.plugins.png.PNGImageReader.readImage(PNGImageReader.java:1263)
      at java.desktop/com.sun.imageio.plugins.png.PNGImageReader.read(PNGImageReader.java:1627)
      at java.desktop/javax.imageio.ImageIO.read(ImageIO.java:1468)
      at java.desktop/javax.imageio.ImageIO.read(ImageIO.java:1363)
      at PngReaderTextChunkSizeIssue.main(PngReaderTextChunkSizeIssue.java:21)


      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      import java.io.ByteArrayInputStream;
      import java.io.InputStream;
      import java.util.Base64;
      import javax.imageio.ImageIO;

      public class PngReaderTextChunkSizeIssue {

      // PNG image test case (encoded as base64)
      private static String inputImageBase64 = "iVBORw0KGgoAAAANSUhEUgAAACA" +
      "AAAAgCAMAAABEpIrGAAAAGXRFWHRTb2Z0d2FyZWVBZG9iZSBJbWFnZVJlYWR59oLevgA" +
      "AAA9QTFRFZszM////AAAAM5lmmf/MPkyvFQAAAGFJREFUeNrckzEOwCAMA5OY/7+5NBQ" +
      "J1DphYaA3sPgkCwtEE0TVAm7BCkfMBaHgp4JvFwjPulSoITAabwHwk1a0PBB6TSBM+bc" +
      "w5ERIlkQiTEPuqTj2ydWbUWzl8yZcAgwA0mYDNbDXy5oAAAAASUVORK5CYII=";

      public static void main(String[] args) throws java.io.IOException {
      // Convert test case into input stream
      byte[] inputBytes = Base64.getDecoder().decode(inputImageBase64);
      InputStream in = new ByteArrayInputStream(inputBytes);

      // Attempt to read PNG
      ImageIO.read(in); // Throws java.lang.NegativeArraySizeException!
      }
      }
      ---------- END SOURCE ----------

        Attachments

          Issue Links

            Activity

              People

              • Assignee:
                jdv Jayathirth D V
                Reporter:
                webbuggrp Webbug Group
              • Votes:
                0 Vote for this issue
                Watchers:
                4 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved: