#330 Now guards against buffer overruns in RLE decoder.

This commit is contained in:
Harald Kuhr 2020-11-17 22:33:50 +01:00
parent 31cb79d2b9
commit a84cc1c060
3 changed files with 48 additions and 43 deletions

View File

@ -216,50 +216,55 @@ public final class BMPImageReader extends ImageReaderBase {
throw new IIOException("Multiple planes not supported"); throw new IIOException("Multiple planes not supported");
} }
switch (header.getBitCount()) { try {
case 1: switch (header.getBitCount()) {
case 2: case 1:
case 4: case 2:
case 8: case 4:
return ImageTypeSpecifiers.createFromIndexColorModel(readColorMap()); case 8:
return ImageTypeSpecifiers.createFromIndexColorModel(readColorMap());
case 16: case 16:
if (header.hasMasks()) { if (header.hasMasks()) {
return ImageTypeSpecifiers.createPacked( return ImageTypeSpecifiers.createPacked(
ColorSpace.getInstance(ColorSpace.CS_sRGB), ColorSpace.getInstance(ColorSpace.CS_sRGB),
header.masks[0], header.masks[1], header.masks[2], header.masks[3], header.masks[0], header.masks[1], header.masks[2], header.masks[3],
DataBuffer.TYPE_USHORT, false DataBuffer.TYPE_USHORT, false
); );
} }
// Default if no mask is 555 // Default if no mask is 555
return ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_USHORT_555_RGB); return ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_USHORT_555_RGB);
case 24: case 24:
if (header.getCompression() != DIB.COMPRESSION_RGB) { if (header.getCompression() != DIB.COMPRESSION_RGB) {
throw new IIOException("Unsupported compression for RGB: " + header.getCompression()); 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: case 32:
if (header.hasMasks()) { if (header.hasMasks()) {
return ImageTypeSpecifiers.createPacked( return ImageTypeSpecifiers.createPacked(
ColorSpace.getInstance(ColorSpace.CS_sRGB), ColorSpace.getInstance(ColorSpace.CS_sRGB),
header.masks[0], header.masks[1], header.masks[2], header.masks[3], header.masks[0], header.masks[1], header.masks[2], header.masks[3],
DataBuffer.TYPE_INT, false DataBuffer.TYPE_INT, false
); );
} }
// Default if no mask // Default if no mask
return ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_INT_RGB); return ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_INT_RGB);
case 0: case 0:
if (header.getCompression() == DIB.COMPRESSION_JPEG || header.getCompression() == DIB.COMPRESSION_PNG) { if (header.getCompression() == DIB.COMPRESSION_JPEG || header.getCompression() == DIB.COMPRESSION_PNG) {
return initReaderDelegate(header.getCompression()).getRawImageType(0); return initReaderDelegate(header.getCompression()).getRawImageType(0);
} }
default: default:
throw new IIOException("Unsupported bit count: " + header.getBitCount()); throw new IIOException("Unsupported bit count: " + header.getBitCount());
}
}
catch (IllegalArgumentException e) {
throw new IIOException(e.getMessage(), e);
} }
} }

View File

@ -41,8 +41,8 @@ import java.util.Arrays;
* @version $Id: RLE4Decoder.java#1 $ * @version $Id: RLE4Decoder.java#1 $
*/ */
final class RLE4Decoder extends AbstractRLEDecoder { final class RLE4Decoder extends AbstractRLEDecoder {
final static int BIT_MASKS[] = {0xf0, 0x0f}; final static int[] BIT_MASKS = {0xf0, 0x0f};
final static int BIT_SHIFTS[] = {4, 0}; final static int[] BIT_SHIFTS = {4, 0};
public RLE4Decoder(final int width) { public RLE4Decoder(final int width) {
super(width, 4); super(width, 4);
@ -94,7 +94,7 @@ final class RLE4Decoder extends AbstractRLEDecoder {
boolean paddingByte = (((byte2 + 1) / 2) % 2) != 0; boolean paddingByte = (((byte2 + 1) / 2) % 2) != 0;
int packed = 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) { if (i % 2 == 0) {
packed = checkEOF(stream.read()); packed = checkEOF(stream.read());
} }
@ -111,7 +111,7 @@ final class RLE4Decoder extends AbstractRLEDecoder {
else { else {
// Encoded mode // Encoded mode
// Replicate the two samples in byte2 as many times as byte1 says // 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]); row[srcX / 2] |= (byte) (((byte2 & BIT_MASKS[i % 2]) >> BIT_SHIFTS[i % 2]) << BIT_SHIFTS[srcX % 2]);
srcX++; srcX++;
} }

View File

@ -94,7 +94,7 @@ final class RLE8Decoder extends AbstractRLEDecoder {
// an additional padding byte is in the stream and must be skipped // an additional padding byte is in the stream and must be skipped
boolean paddingByte = (byte2 % 2) != 0; boolean paddingByte = (byte2 % 2) != 0;
while (byte2-- > 0) { while (byte2-- > 0 && srcX < row.length) {
row[srcX++] = (byte) checkEOF(stream.read()); row[srcX++] = (byte) checkEOF(stream.read());
} }
@ -107,7 +107,7 @@ final class RLE8Decoder extends AbstractRLEDecoder {
// Encoded mode // Encoded mode
// Replicate byte2 as many times as byte1 says // Replicate byte2 as many times as byte1 says
byte value = (byte) byte2; byte value = (byte) byte2;
while (byte1-- > 0) { while (byte1-- > 0 && srcX < row.length) {
row[srcX++] = value; row[srcX++] = value;
} }
} }