#329 JPEGImageReader endless loop fix

This commit is contained in:
Harald Kuhr
2018-05-22 21:10:57 +02:00
parent b32a38bf02
commit 7ab72f0161
14 changed files with 251 additions and 30 deletions
@@ -90,7 +90,7 @@ class Application extends Segment {
default:
// Generic APPn segment
byte[] bytes = new byte[length - 2];
byte[] bytes = new byte[Math.max(0, length - 2)];
data.readFully(bytes);
return new Application(marker, identifier, bytes);
}
@@ -233,7 +233,14 @@ public final class JPEGImageReader extends ImageReaderBase {
@Override
public Iterator<ImageTypeSpecifier> getImageTypes(int imageIndex) throws IOException {
Iterator<ImageTypeSpecifier> types = delegate.getImageTypes(imageIndex);
Iterator<ImageTypeSpecifier> types;
try {
types = delegate.getImageTypes(imageIndex);
}
catch (IndexOutOfBoundsException | NegativeArraySizeException ignore) {
types = null;
}
JPEGColorSpace csType = getSourceCSType(getJFIF(), getAdobeDCT(), getSOF());
if (types == null || !types.hasNext() || csType == JPEGColorSpace.CMYK || csType == JPEGColorSpace.YCCK) {
@@ -302,7 +309,7 @@ public final class JPEGImageReader extends ImageReaderBase {
return rawType;
}
}
catch (IIOException | NullPointerException ignore) {
catch (IIOException | NullPointerException | ArrayIndexOutOfBoundsException | NegativeArraySizeException ignore) {
// Fall through
}
@@ -933,7 +940,13 @@ public final class JPEGImageReader extends ImageReaderBase {
return new JPEGLosslessDecoderWrapper(this).readRaster(segments, imageInput);
}
return delegate.readRaster(imageIndex, param);
try {
return delegate.readRaster(imageIndex, param);
}
catch (IndexOutOfBoundsException knownIssue) {
// com.sun.imageio.plugins.jpeg.JPEGBuffer doesn't do proper sanity check of input data.
throw new IIOException("Corrupt JPEG data: Bad segment length", knownIssue);
}
}
@Override
@@ -40,6 +40,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static com.twelvemonkeys.imageio.metadata.jpeg.JPEGSegmentUtil.isKnownJPEGMarker;
import static com.twelvemonkeys.lang.Validate.notNull;
import static java.util.Arrays.copyOf;
@@ -105,24 +106,25 @@ final class JPEGSegmentImageInputStream extends ImageInputStreamImpl {
// Scan forward
while (true) {
long realPosition = stream.getStreamPosition();
int trash = 0;
int marker = stream.readUnsignedByte();
// Skip bad padding before the marker
while (marker != 0xff) {
marker = stream.readUnsignedByte();
trash++;
realPosition++;
}
while (!isKnownJPEGMarker(marker)) {
marker &= 0xff;
marker = 0xff00 | stream.readUnsignedByte();
// Skip bad padding before the marker
while (marker != 0xff) {
marker = stream.readUnsignedByte();
trash++;
}
// Skip over 0xff padding between markers
while (marker == 0xffff) {
realPosition++;
marker = 0xff00 | stream.readUnsignedByte();
// Skip over 0xff padding between markers
while (marker == 0xffff) {
marker = 0xff00 | stream.readUnsignedByte();
trash++;
}
}
if (trash != 0) {
@@ -131,6 +133,8 @@ final class JPEGSegmentImageInputStream extends ImageInputStreamImpl {
processWarningOccured(String.format("Corrupt JPEG data: %d extraneous bytes before marker 0x%02x", trash, marker & 0xff));
}
long realPosition = stream.getStreamPosition() - 2;
// We are now handling all important segments ourselves, except APP1/Exif and APP14/Adobe,
// as these segments affects image decoding.
boolean appSegmentMarker = isAppSegmentMarker(marker);
@@ -380,6 +384,7 @@ final class JPEGSegmentImageInputStream extends ImageInputStreamImpl {
fetchSegment();
}
catch (EOFException ignore) {
segments.add(new Segment(0, segment.realEnd(), segment.end(), Integer.MAX_VALUE * 2L - segment.realEnd()));
// This might happen if the segment lengths in the stream are bad.
// We MUST leave internal state untouched in this case.
// We ignore this exception here, but client code will get
@@ -415,7 +420,7 @@ final class JPEGSegmentImageInputStream extends ImageInputStreamImpl {
repositionAsNecessary();
long bytesLeft = segment.end() - streamPos; // If no more bytes after reposition, we're at EOF
int count = bytesLeft == 0 ? -1 : segment.read(stream, b, off + total, (int) Math.min(len - total, bytesLeft));
int count = bytesLeft <= 0 ? -1 : segment.read(stream, b, off + total, (int) Math.min(len - total, bytesLeft));
if (count == -1) {
// EOF