#477: Avoid cyclic loops in IFDs.

(cherry picked from commit 8480c929c107c4d700bbc2e9e427ca3d327e5daf)
This commit is contained in:
Harald Kuhr 2019-08-08 22:41:23 +02:00
parent 653360e054
commit 0e41d4a5f7
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 boolean longOffsets;
private int offsetSize;
private Set<Long> parsedIFDs = new TreeSet<>();
@Override
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));
}
length = getTIFFLength(input);
length = input.length();
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 {
long nextOffset = readOffset(input);
long ifdOffset = readOffset(input);
List<IFD> ifds = new ArrayList<>();
// Read linked IFDs
while (nextOffset != 0 && (length < 0 || length > nextOffset)) {
while (ifdOffset != 0) {
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 EOF here as missing EOF marker
nextOffset = 0;
ifdOffset = 0;
}
}
@ -208,12 +211,20 @@ public final class TIFFReader extends MetadataReader {
if (subIFDIds.contains(tagId)) {
try {
long[] pointerOffsets = getPointerOffsets(entry);
List<IFD> subIFDs = new ArrayList<>(pointerOffsets.length);
long[] ifdOffsets = getPointerOffsets(entry);
List<IFD> subIFDs = new ArrayList<>(ifdOffsets.length);
for (long pointerOffset : pointerOffsets) {
for (long ifdOffset : ifdOffsets) {
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) {
// TODO: Issue warning

View File

@ -344,4 +344,15 @@ public class TIFFReaderTest extends MetadataReaderAbstractTest {
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());
}
}
}