Uploaded image for project: 'XMLGraphicsCommons'
  1. XMLGraphicsCommons
  2. XGC-136

2.8 Out of memory on certain malformed PNGs

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Open
    • Minor
    • Resolution: Unresolved
    • None
    • None
    • None
    • None

    Description

      Our team has a test PNG that we use in test cases that would fail fast in xmlgraphics-commons 2.7: https://gist.github.com/NicholasMoser/ba8cef937cc3c0328ec89883f5c7879e

      After upgrading to 2.8, we noticed that it would fail with OOM: https://gist.github.com/NicholasMoser/324ee1b814a6785a465fca2ee8e73c9c

      Apparently it no longer fails when parsing the header and now instead tries to allocate massive invalid chunks (0x2FC57D50 bytes). As far as I'm aware, this chunk size is valid per the PNG spec (0 - 2,147,483,647 bytes). The only caveat here is that the full image size is 0x50 bytes. Hypothetically this could be used as a denial of service vector that is small but becomes large in memory, kind of like a zip bomb.

      The only reasonable fix I could see here would be to validate that chunk size is less than the total file size, as I cannot imagine a scenario where that would be valid. With that being said, I'm sure there are a lot of different ways to craft images that error in similar ways, so I'm not sure this is worth fixing.

      Just curious to hear what contributors think.

      import java.io.InputStream;
      import java.nio.file.Files;
      import java.nio.file.Paths;
      import javax.imageio.ImageIO;
      import javax.imageio.stream.ImageInputStream;
      import org.apache.xmlgraphics.image.loader.ImageContext;
      import org.apache.xmlgraphics.image.loader.ImageInfo;
      import org.apache.xmlgraphics.image.loader.ImageSource;
      import org.apache.xmlgraphics.image.loader.impl.PreloaderRawPNG;
      import org.junit.jupiter.api.Test;
      
      @Test
      public void testBrokenPNG() throws Exception {
        try (InputStream is = Files.newInputStream(Paths.get("broken.png"))) {
          ImageInputStream iis = ImageIO.createImageInputStream(is);
          ImageSource imageSource = new ImageSource(iis, "", false);
          PreloaderRawPNG preloader = new PreloaderRawPNG();
          ImageContext imageContext = () -> 72.0f;
          // Fails with OOM
          ImageInfo imageInfo = preloader.preloadImage("", imageSource, imageContext);
        }
      } 

      Attachments

        1. broken.png
          0.1 kB
          Nicholas Moser
        2. image-2023-05-10-10-28-02-928.png
          93 kB
          Nicholas Moser

        Activity

          People

            Unassigned Unassigned
            NicholasMoser Nicholas Moser
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

              Created:
              Updated: