diff --git a/imageio/imageio-core/src/main/java/com/twelvemonkeys/imageio/color/KCMSSanitizerStrategy.java b/imageio/imageio-core/src/main/java/com/twelvemonkeys/imageio/color/KCMSSanitizerStrategy.java index 0daefb3c..44d80987 100644 --- a/imageio/imageio-core/src/main/java/com/twelvemonkeys/imageio/color/KCMSSanitizerStrategy.java +++ b/imageio/imageio-core/src/main/java/com/twelvemonkeys/imageio/color/KCMSSanitizerStrategy.java @@ -65,7 +65,6 @@ final class KCMSSanitizerStrategy implements ICCProfileSanitizer { ((array[index + 3] & 0xff) ); } - // TODO: Move to some common util static void intToBigEndian(final int value, final byte[] array, final int index) { array[index ] = (byte) (value >> 24); diff --git a/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/JPEGImageReader.java b/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/JPEGImageReader.java index 47b5584f..671c8342 100644 --- a/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/JPEGImageReader.java +++ b/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/JPEGImageReader.java @@ -689,11 +689,20 @@ public final class JPEGImageReader extends ImageReaderBase { return profile; } - static void intToBigEndian(int value, byte[] array, int index) { - array[index] = (byte) (value >> 24); - array[index+1] = (byte) (value >> 16); - array[index+2] = (byte) (value >> 8); - array[index+3] = (byte) (value); + // TODO: Move to some common util + static int intFromBigEndian(final byte[] array, final int index) { + return ((array[index ] & 0xff) << 24) | + ((array[index + 1] & 0xff) << 16) | + ((array[index + 2] & 0xff) << 8) | + ((array[index + 3] & 0xff) ); + } + + // TODO: Move to some common util + static void intToBigEndian(final int value, final byte[] array, final int index) { + array[index ] = (byte) (value >> 24); + array[index + 1] = (byte) (value >> 16); + array[index + 2] = (byte) (value >> 8); + array[index + 3] = (byte) (value ); } private void initHeader() throws IOException { @@ -853,7 +862,10 @@ public final class JPEGImageReader extends ImageReaderBase { return null; } - return readICCProfileSafe(stream, allowBadIndexes); + int iccChunkDataSize = segment.data.length - segment.identifier.length() - 3; // ICC_PROFILE + null + chunk number + count + int iccSize = intFromBigEndian(segment.data, segment.identifier.length() + 3); + + return readICCProfileSafe(stream, allowBadIndexes, iccSize, iccChunkDataSize); } else if (!segments.isEmpty()) { // NOTE: This is probably over-complicated, as I've never encountered ICC_PROFILE chunks out of order... @@ -888,25 +900,40 @@ public final class JPEGImageReader extends ImageReaderBase { InputStream[] streams = new InputStream[count]; streams[badICC ? 0 : chunkNumber - 1] = stream; + int iccChunkDataSize = 0; + int iccSize = 0; + for (int i = 1; i < count; i++) { - stream = new DataInputStream(segments.get(i).data()); + Application segment = segments.get(i); + stream = new DataInputStream(segment.data()); chunkNumber = stream.readUnsignedByte(); - if (!badICC && stream.readUnsignedByte() != chunkCount) { + if (stream.readUnsignedByte() != chunkCount && !badICC) { throw new IIOException(String.format("Bad number of 'ICC_PROFILE' chunks: %d of %d.", chunkNumber, chunkCount)); } - streams[badICC ? i : chunkNumber - 1] = stream; + int index = badICC ? i : chunkNumber - 1; + streams[index] = stream; + + iccChunkDataSize += segment.data.length - segment.identifier.length() - 3; + if (index == 0) { + iccSize = intFromBigEndian(segment.data, segment.identifier.length() + 3); + } } - return readICCProfileSafe(new SequenceInputStream(Collections.enumeration(Arrays.asList(streams))), allowBadIndexes); + return readICCProfileSafe(new SequenceInputStream(Collections.enumeration(Arrays.asList(streams))), allowBadIndexes, iccSize, iccChunkDataSize); } return null; } - private ICC_Profile readICCProfileSafe(final InputStream stream, final boolean allowBadProfile) throws IOException { + private ICC_Profile readICCProfileSafe(final InputStream stream, final boolean allowBadProfile, final int iccSize, final int iccChunkDataSize) throws IOException { + if (iccSize < 0 || iccSize > iccChunkDataSize) { + processWarningOccurred(String.format("Truncated 'ICC_PROFILE' chunk(s), size: %d. Ignoring ICC profile.", iccSize)); + return null; + } + try { ICC_Profile profile = ICC_Profile.getInstance(stream); diff --git a/imageio/imageio-tiff/src/main/java/com/twelvemonkeys/imageio/plugins/tiff/TIFFImageReader.java b/imageio/imageio-tiff/src/main/java/com/twelvemonkeys/imageio/plugins/tiff/TIFFImageReader.java index f06b847f..acfc2f4e 100755 --- a/imageio/imageio-tiff/src/main/java/com/twelvemonkeys/imageio/plugins/tiff/TIFFImageReader.java +++ b/imageio/imageio-tiff/src/main/java/com/twelvemonkeys/imageio/plugins/tiff/TIFFImageReader.java @@ -2205,6 +2205,13 @@ public final class TIFFImageReader extends ImageReaderBase { if (entry != null) { byte[] value = (byte[]) entry.getValue(); + // Validate ICC profile size vs actual value size + int size = (value[0] & 0xff) << 24 | (value[1] & 0xff) << 16 | (value[2] & 0xff) << 8 | (value[3] & 0xff); + if (size < 0 || size > value.length) { + processWarningOccurred("Ignoring truncated ICC profile: Bad ICC profile size (" + size + ")"); + return null; + } + try { // WEIRDNESS: Reading profile from InputStream is somehow more compatible // than reading from byte array (chops off extra bytes + validates profile). @@ -2218,7 +2225,6 @@ public final class TIFFImageReader extends ImageReaderBase { return null; } - @Override public boolean canReadRaster() { return true;