mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2025-08-05 04:25:29 -04:00
#652: Avoid OOME for large values outside TIFF, even if length is unknown
(cherry picked from commit 33419ef291fcd6c3a2b706446bb41bdcd8da1d51)
This commit is contained in:
parent
46db5a2fbf
commit
3c0b78549e
@ -80,7 +80,7 @@ public final class TIFFReader extends MetadataReader {
|
|||||||
|
|
||||||
private final Set<Long> parsedIFDs = new TreeSet<>();
|
private final Set<Long> parsedIFDs = new TreeSet<>();
|
||||||
|
|
||||||
private long length;
|
private long inputLength;
|
||||||
private boolean longOffsets;
|
private boolean longOffsets;
|
||||||
private int offsetSize;
|
private int offsetSize;
|
||||||
|
|
||||||
@ -127,7 +127,7 @@ 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 = input.length();
|
inputLength = input.length();
|
||||||
|
|
||||||
return readLinkedIFDs(input);
|
return readLinkedIFDs(input);
|
||||||
}
|
}
|
||||||
@ -140,7 +140,7 @@ public final class TIFFReader extends MetadataReader {
|
|||||||
// Read linked IFDs
|
// Read linked IFDs
|
||||||
while (ifdOffset != 0) {
|
while (ifdOffset != 0) {
|
||||||
try {
|
try {
|
||||||
if ((length > 0 && ifdOffset >= length) || !parsedIFDs.add(ifdOffset)) {
|
if ((inputLength > 0 && ifdOffset >= inputLength) || !isValidOffset(input, ifdOffset) || !parsedIFDs.add(ifdOffset)) {
|
||||||
// TODO: Issue warning
|
// TODO: Issue warning
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
System.err.println("Bad IFD offset: " + ifdOffset);
|
System.err.println("Bad IFD offset: " + ifdOffset);
|
||||||
@ -218,7 +218,7 @@ public final class TIFFReader extends MetadataReader {
|
|||||||
|
|
||||||
for (long ifdOffset : ifdOffsets) {
|
for (long ifdOffset : ifdOffsets) {
|
||||||
try {
|
try {
|
||||||
if ((length > 0 && ifdOffset >= length) || !parsedIFDs.add(ifdOffset)) {
|
if ((inputLength > 0 && ifdOffset >= inputLength) || !isValidOffset(input, ifdOffset) || !parsedIFDs.add(ifdOffset)) {
|
||||||
// TODO: Issue warning
|
// TODO: Issue warning
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
System.err.println("Bad IFD offset: " + ifdOffset);
|
System.err.println("Bad IFD offset: " + ifdOffset);
|
||||||
@ -330,20 +330,14 @@ public final class TIFFReader extends MetadataReader {
|
|||||||
long valueLength = getValueLength(type, count);
|
long valueLength = getValueLength(type, count);
|
||||||
|
|
||||||
Object value;
|
Object value;
|
||||||
|
|
||||||
if (valueLength > 0 && valueLength <= offsetSize) {
|
if (valueLength > 0 && valueLength <= offsetSize) {
|
||||||
value = readValueInLine(pInput, type, count);
|
value = readValueInLine(pInput, type, count);
|
||||||
pInput.skipBytes(offsetSize - valueLength);
|
pInput.skipBytes(offsetSize - valueLength);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
long valueOffset = readOffset(pInput); // This is the *value* iff the value size is <= offsetSize
|
long valueOffset = readOffset(pInput); // This is the *value* iff the value size is <= offsetSize
|
||||||
|
value = readValueAt(pInput, valueOffset, valueLength, type, count);
|
||||||
// Note: This a precaution
|
|
||||||
if (count >= Integer.MAX_VALUE || length > 0 && length < valueOffset + valueLength) {
|
|
||||||
value = new EOFException(String.format("TIFF value offset or size too large: %d/%d bytes (length: %d bytes)", valueOffset, valueLength, length));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
value = readValueAt(pInput, valueOffset, type, count);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new TIFFEntry(tagId, type, value);
|
return new TIFFEntry(tagId, type, value);
|
||||||
@ -365,18 +359,52 @@ public final class TIFFReader extends MetadataReader {
|
|||||||
return (int) count;
|
return (int) count;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object readValueAt(final ImageInputStream pInput, final long pOffset, final short pType, final int pCount) throws IOException {
|
private boolean isValidOffset(final ImageInputStream input, final long pos) throws IOException {
|
||||||
long pos = pInput.getStreamPosition();
|
// TODO: If the position returns false, we could limit the length to pos for further reads...
|
||||||
try {
|
try {
|
||||||
pInput.seek(pOffset);
|
input.mark();
|
||||||
return readValue(pInput, pType, pCount, longOffsets);
|
input.seek(pos);
|
||||||
|
|
||||||
|
return input.read() >= 0;
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
input.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isValidLengthAtOffset(final ImageInputStream input, long offset, long valueLength) throws IOException {
|
||||||
|
// NOTE: For values smaller than Short.MAX_VALUE, we simply try, and handle the potential EOFException when reading
|
||||||
|
return (inputLength < 0 || inputLength >= offset + valueLength)
|
||||||
|
&& (valueLength < Short.MAX_VALUE || isValidOffset(input, offset + valueLength - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object readValueAt(final ImageInputStream input, final long offset, final long length, final short type, final int count) throws IOException {
|
||||||
|
long pos = input.getStreamPosition();
|
||||||
|
|
||||||
|
try {
|
||||||
|
input.seek(offset);
|
||||||
|
|
||||||
|
// Avoid OOME due to corrupted/malicious data
|
||||||
|
if (count < Integer.MAX_VALUE && isValidLengthAtOffset(input, offset, length)) {
|
||||||
|
return readValue(input, type, count, longOffsets);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new EOFException(String.format("TIFF value offset or size too large: @%08x/%d bytes (input length: %s)", offset, length, inputLength >= 0 ? inputLength + " bytes" : "unknown"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (EOFException e) {
|
catch (EOFException e) {
|
||||||
// TODO: Add warning listener API and report problem to client code
|
// TODO: Add warning listener API and report problem to client code
|
||||||
|
if (DEBUG) {
|
||||||
|
System.err.println(e);
|
||||||
|
}
|
||||||
|
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
pInput.seek(pos);
|
input.seek(pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user