#477: Avoid cyclic loops in IFDs.

This commit is contained in:
Harald Kuhr 2019-08-08 22:41:23 +02:00
parent e6f437f55b
commit 8480c929c1
3 changed files with 38 additions and 16 deletions

View File

@ -81,6 +81,7 @@ public final class TIFFReader extends MetadataReader {
private long length; private long length;
private boolean longOffsets; private boolean longOffsets;
private int offsetSize; private int offsetSize;
private Set<Long> parsedIFDs = new TreeSet<>();
@Override @Override
public Directory read(final ImageInputStream input) throws IOException { public Directory read(final ImageInputStream input) throws IOException {
@ -125,32 +126,34 @@ public final class TIFFReader extends MetadataReader {
throw new IIOException(String.format("Wrong TIFF magic in input data: %04x, expected: %04x", magic, TIFF.TIFF_MAGIC)); throw new IIOException(String.format("Wrong TIFF magic in input data: %04x, expected: %04x", magic, TIFF.TIFF_MAGIC));
} }
length = getTIFFLength(input); length = input.length();
return readLinkedIFDs(input); return readLinkedIFDs(input);
} }
private long getTIFFLength(final ImageInputStream input) throws IOException {
// TODO: Scan to end, if length is unknown?
// Set to fixed size? 4 GB for TIFF, BigTIFF may be huge...
return input.length();
}
private TIFFDirectory readLinkedIFDs(final ImageInputStream input) throws IOException { private TIFFDirectory readLinkedIFDs(final ImageInputStream input) throws IOException {
long nextOffset = readOffset(input); long ifdOffset = readOffset(input);
List<IFD> ifds = new ArrayList<>(); List<IFD> ifds = new ArrayList<>();
// Read linked IFDs // Read linked IFDs
while (nextOffset != 0 && (length < 0 || length > nextOffset)) { while (ifdOffset != 0) {
try { try {
ifds.add(readIFD(input, nextOffset, VALID_TOP_LEVEL_IFDS)); if ((length > 0 && ifdOffset >= length) || !parsedIFDs.add(ifdOffset)) {
// TODO: Issue warning
if (DEBUG) {
System.err.println("Bad IFD offset: " + ifdOffset);
}
break;
}
nextOffset = readOffset(input); ifds.add(readIFD(input, ifdOffset, VALID_TOP_LEVEL_IFDS));
ifdOffset = readOffset(input);
} }
catch (EOFException eof) { catch (EOFException eof) {
// catch EOF here as missing EOF marker // catch EOF here as missing EOF marker
nextOffset = 0; ifdOffset = 0;
} }
} }
@ -208,12 +211,20 @@ public final class TIFFReader extends MetadataReader {
if (subIFDIds.contains(tagId)) { if (subIFDIds.contains(tagId)) {
try { try {
long[] pointerOffsets = getPointerOffsets(entry); long[] ifdOffsets = getPointerOffsets(entry);
List<IFD> subIFDs = new ArrayList<>(pointerOffsets.length); List<IFD> subIFDs = new ArrayList<>(ifdOffsets.length);
for (long pointerOffset : pointerOffsets) { for (long ifdOffset : ifdOffsets) {
try { try {
subIFDs.add(readIFD(input, pointerOffset, VALID_SUB_IFDS.get(tagId))); if ((length > 0 && ifdOffset >= length) || !parsedIFDs.add(ifdOffset)) {
// TODO: Issue warning
if (DEBUG) {
System.err.println("Bad IFD offset: " + ifdOffset);
}
break;
}
subIFDs.add(readIFD(input, ifdOffset, VALID_SUB_IFDS.get(tagId)));
} }
catch (EOFException eof) { catch (EOFException eof) {
// TODO: Issue warning // TODO: Issue warning

View File

@ -344,4 +344,15 @@ public class TIFFReaderTest extends MetadataReaderAbstractTest {
assertEquals(3, directory.getDirectory(1).size()); assertEquals(3, directory.getDirectory(1).size());
} }
} }
@Test(timeout = 500)
public void testReadCyclicExifWithoutLoopOrOOME() throws IOException {
try (ImageInputStream stream = ImageIO.createImageInputStream(getResource("/exif/exif-loop.bin"))) {
CompoundDirectory directory = (CompoundDirectory) createReader().read(stream);
assertEquals(1, directory.directoryCount());
assertEquals(12, directory.getDirectory(0).size());
assertEquals("Polarr Photo Editor", directory.getDirectory(0).getEntryById(TIFF.TAG_SOFTWARE).getValue());
assertEquals("2019:02:27 09:22:59", directory.getDirectory(0).getEntryById(TIFF.TAG_DATE_TIME).getValueAsString());
}
}
} }