From a84cc1c060fd3c112cd99bfca42a9671962cb37a Mon Sep 17 00:00:00 2001 From: Harald Kuhr Date: Tue, 17 Nov 2020 22:33:50 +0100 Subject: [PATCH] #330 Now guards against buffer overruns in RLE decoder. --- .../imageio/plugins/bmp/BMPImageReader.java | 79 ++++++++++--------- .../imageio/plugins/bmp/RLE4Decoder.java | 8 +- .../imageio/plugins/bmp/RLE8Decoder.java | 4 +- 3 files changed, 48 insertions(+), 43 deletions(-) diff --git a/imageio/imageio-bmp/src/main/java/com/twelvemonkeys/imageio/plugins/bmp/BMPImageReader.java b/imageio/imageio-bmp/src/main/java/com/twelvemonkeys/imageio/plugins/bmp/BMPImageReader.java index d78e5d9e..7d769d89 100755 --- a/imageio/imageio-bmp/src/main/java/com/twelvemonkeys/imageio/plugins/bmp/BMPImageReader.java +++ b/imageio/imageio-bmp/src/main/java/com/twelvemonkeys/imageio/plugins/bmp/BMPImageReader.java @@ -216,50 +216,55 @@ public final class BMPImageReader extends ImageReaderBase { throw new IIOException("Multiple planes not supported"); } - switch (header.getBitCount()) { - case 1: - case 2: - case 4: - case 8: - return ImageTypeSpecifiers.createFromIndexColorModel(readColorMap()); + try { + switch (header.getBitCount()) { + case 1: + case 2: + case 4: + case 8: + return ImageTypeSpecifiers.createFromIndexColorModel(readColorMap()); - case 16: - if (header.hasMasks()) { - return ImageTypeSpecifiers.createPacked( - ColorSpace.getInstance(ColorSpace.CS_sRGB), - header.masks[0], header.masks[1], header.masks[2], header.masks[3], - DataBuffer.TYPE_USHORT, false - ); - } + case 16: + if (header.hasMasks()) { + return ImageTypeSpecifiers.createPacked( + ColorSpace.getInstance(ColorSpace.CS_sRGB), + header.masks[0], header.masks[1], header.masks[2], header.masks[3], + DataBuffer.TYPE_USHORT, false + ); + } - // Default if no mask is 555 - return ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_USHORT_555_RGB); + // Default if no mask is 555 + return ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_USHORT_555_RGB); - case 24: - if (header.getCompression() != DIB.COMPRESSION_RGB) { - throw new IIOException("Unsupported compression for RGB: " + header.getCompression()); - } + case 24: + if (header.getCompression() != DIB.COMPRESSION_RGB) { + throw new IIOException("Unsupported compression for RGB: " + header.getCompression()); + } - return ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_3BYTE_BGR); + return ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_3BYTE_BGR); - case 32: - if (header.hasMasks()) { - return ImageTypeSpecifiers.createPacked( - ColorSpace.getInstance(ColorSpace.CS_sRGB), - header.masks[0], header.masks[1], header.masks[2], header.masks[3], - DataBuffer.TYPE_INT, false - ); - } + case 32: + if (header.hasMasks()) { + return ImageTypeSpecifiers.createPacked( + ColorSpace.getInstance(ColorSpace.CS_sRGB), + header.masks[0], header.masks[1], header.masks[2], header.masks[3], + DataBuffer.TYPE_INT, false + ); + } - // Default if no mask - return ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_INT_RGB); + // Default if no mask + return ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_INT_RGB); - case 0: - if (header.getCompression() == DIB.COMPRESSION_JPEG || header.getCompression() == DIB.COMPRESSION_PNG) { - return initReaderDelegate(header.getCompression()).getRawImageType(0); - } - default: - throw new IIOException("Unsupported bit count: " + header.getBitCount()); + case 0: + if (header.getCompression() == DIB.COMPRESSION_JPEG || header.getCompression() == DIB.COMPRESSION_PNG) { + return initReaderDelegate(header.getCompression()).getRawImageType(0); + } + default: + throw new IIOException("Unsupported bit count: " + header.getBitCount()); + } + } + catch (IllegalArgumentException e) { + throw new IIOException(e.getMessage(), e); } } diff --git a/imageio/imageio-bmp/src/main/java/com/twelvemonkeys/imageio/plugins/bmp/RLE4Decoder.java b/imageio/imageio-bmp/src/main/java/com/twelvemonkeys/imageio/plugins/bmp/RLE4Decoder.java index 60e08842..999b449d 100644 --- a/imageio/imageio-bmp/src/main/java/com/twelvemonkeys/imageio/plugins/bmp/RLE4Decoder.java +++ b/imageio/imageio-bmp/src/main/java/com/twelvemonkeys/imageio/plugins/bmp/RLE4Decoder.java @@ -41,8 +41,8 @@ import java.util.Arrays; * @version $Id: RLE4Decoder.java#1 $ */ final class RLE4Decoder extends AbstractRLEDecoder { - final static int BIT_MASKS[] = {0xf0, 0x0f}; - final static int BIT_SHIFTS[] = {4, 0}; + final static int[] BIT_MASKS = {0xf0, 0x0f}; + final static int[] BIT_SHIFTS = {4, 0}; public RLE4Decoder(final int width) { super(width, 4); @@ -94,7 +94,7 @@ final class RLE4Decoder extends AbstractRLEDecoder { boolean paddingByte = (((byte2 + 1) / 2) % 2) != 0; int packed = 0; - for (int i = 0; i < byte2; i++) { + for (int i = 0; i < byte2 && srcX / 2 < row.length; i++) { if (i % 2 == 0) { packed = checkEOF(stream.read()); } @@ -111,7 +111,7 @@ final class RLE4Decoder extends AbstractRLEDecoder { else { // Encoded mode // Replicate the two samples in byte2 as many times as byte1 says - for (int i = 0; i < byte1; i++) { + for (int i = 0; i < byte1 && srcX / 2 < row.length; i++) { row[srcX / 2] |= (byte) (((byte2 & BIT_MASKS[i % 2]) >> BIT_SHIFTS[i % 2]) << BIT_SHIFTS[srcX % 2]); srcX++; } diff --git a/imageio/imageio-bmp/src/main/java/com/twelvemonkeys/imageio/plugins/bmp/RLE8Decoder.java b/imageio/imageio-bmp/src/main/java/com/twelvemonkeys/imageio/plugins/bmp/RLE8Decoder.java index fee3de1e..bbe0a728 100644 --- a/imageio/imageio-bmp/src/main/java/com/twelvemonkeys/imageio/plugins/bmp/RLE8Decoder.java +++ b/imageio/imageio-bmp/src/main/java/com/twelvemonkeys/imageio/plugins/bmp/RLE8Decoder.java @@ -94,7 +94,7 @@ final class RLE8Decoder extends AbstractRLEDecoder { // an additional padding byte is in the stream and must be skipped boolean paddingByte = (byte2 % 2) != 0; - while (byte2-- > 0) { + while (byte2-- > 0 && srcX < row.length) { row[srcX++] = (byte) checkEOF(stream.read()); } @@ -107,7 +107,7 @@ final class RLE8Decoder extends AbstractRLEDecoder { // Encoded mode // Replicate byte2 as many times as byte1 says byte value = (byte) byte2; - while (byte1-- > 0) { + while (byte1-- > 0 && srcX < row.length) { row[srcX++] = value; } }