diff options
| author | 2016-03-15 08:27:37 +0000 | |
|---|---|---|
| committer | 2016-03-15 08:27:38 +0000 | |
| commit | 1a506af9a2b4baf3ea2411bd6680b36a16848d9c (patch) | |
| tree | a7bef19e66aa5293e27d311463ce142b36514077 | |
| parent | 531d8d2faee92f8ea173440b74761bd91add2dd8 (diff) | |
| parent | 49371caff0294b474d97ba11fb9c2bb166052d66 (diff) | |
Merge "ExifInterface: handle the invalid offsets and count numbers" into nyc-dev
| -rw-r--r-- | media/java/android/media/ExifInterface.java | 137 |
1 files changed, 94 insertions, 43 deletions
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java index ce12e76b6588..e35fcf62f6af 100644 --- a/media/java/android/media/ExifInterface.java +++ b/media/java/android/media/ExifInterface.java @@ -1197,8 +1197,9 @@ public class ExifInterface { } bytesRead += 2; int length = dataInputStream.readUnsignedShort() - 2; - if (length < 0) + if (length < 0) { throw new IOException("Invalid length"); + } bytesRead += length; switch (marker) { case MARKER_APP1: { @@ -1221,6 +1222,9 @@ public class ExifInterface { if (length <= 0) { throw new IOException("Invalid exif"); } + if (DEBUG) { + Log.d(TAG, "readExifSegment with a byte array (length: " + length + ")"); + } byte[] bytes = new byte[length]; if (dataInputStream.read(bytes) != length) { throw new IOException("Invalid exif"); @@ -1309,8 +1313,9 @@ public class ExifInterface { case MARKER_APP1: { // Rewrite EXIF segment int length = dataInputStream.readUnsignedShort() - 2; - if (length < 0) + if (length < 0) { throw new IOException("Invalid length"); + } bytesRead += 2; int read; while ((read = dataInputStream.read( @@ -1331,8 +1336,9 @@ public class ExifInterface { // Copy JPEG segment int length = dataInputStream.readUnsignedShort(); dataOutputStream.writeUnsignedShort(length); - if (length < 0) + if (length < 0) { throw new IOException("Invalid length"); + } length -= 2; bytesRead += 2; int read; @@ -1385,8 +1391,9 @@ public class ExifInterface { } firstIfdOffset -= 8; if (firstIfdOffset > 0) { - if (dataInputStream.skip(firstIfdOffset) != firstIfdOffset) + if (dataInputStream.skip(firstIfdOffset) != firstIfdOffset) { throw new IOException("Couldn't jump to first Ifd: " + firstIfdOffset); + } } // Read primary image TIFF image file directory. @@ -1582,8 +1589,16 @@ public class ExifInterface { // Reads image file directory, which is a tag group in EXIF. private void readImageFileDirectory(ByteOrderAwarenessDataInputStream dataInputStream, int hint) throws IOException { + if (dataInputStream.peek() + 2 > dataInputStream.mLength) { + // Return if there is no data from the offset. + return; + } // See JEITA CP-3451 Figure 5. page 9. short numberOfDirectoryEntry = dataInputStream.readShort(); + if (dataInputStream.peek() + 12 * numberOfDirectoryEntry > dataInputStream.mLength) { + // Return if the size of entries is too big. + return; + } if (DEBUG) { Log.d(TAG, "numberOfDirectoryEntry: " + numberOfDirectoryEntry); @@ -1595,10 +1610,25 @@ public class ExifInterface { int numberOfComponents = dataInputStream.readInt(); long nextEntryOffset = dataInputStream.peek() + 4; // next four bytes is for data // offset or value. + // Look up a corresponding tag from tag number + String tagName = (String) sExifTagMapsForReading[hint].get(tagNumber); if (DEBUG) { - Log.d(TAG, String.format("tagNumber: %d, dataFormat: %d, numberOfComponents: %d", - tagNumber, dataFormat, numberOfComponents)); + Log.d(TAG, String.format("hint: %d, tagNumber: %d, tagName: %s, dataFormat: %d," + + "numberOfComponents: %d", hint, tagNumber, tagName, dataFormat, + numberOfComponents)); + } + + if (tagName == null || dataFormat <= 0 || + dataFormat >= IFD_FORMAT_BYTES_PER_FORMAT.length) { + // Skip if the parsed tag number is not defined or invalid data format. + if (tagName == null) { + Log.w(TAG, "Skip the tag entry since tag number is not defined: " + tagNumber); + } else { + Log.w(TAG, "Skip the tag entry since data format is invalid: " + dataFormat); + } + dataInputStream.seek(nextEntryOffset); + continue; } // Read a value from data field or seek to the value offset which is stored in data @@ -1609,19 +1639,21 @@ public class ExifInterface { if (DEBUG) { Log.d(TAG, "seek to data offset: " + offset); } - dataInputStream.seek(offset); - } - - // Look up a corresponding tag from tag number - String tagName = (String) sExifTagMapsForReading[hint].get(tagNumber); - // Skip if the parsed tag number is not defined. - if (tagName == null) { - dataInputStream.seek(nextEntryOffset); - continue; + if (offset + byteCount <= dataInputStream.mLength) { + dataInputStream.seek(offset); + } else { + // Skip if invalid data offset. + Log.w(TAG, "Skip the tag entry since data offset is invalid: " + offset); + dataInputStream.seek(nextEntryOffset); + continue; + } } // Recursively parse IFD when a IFD pointer tag appears. int innerIfdHint = getIfdHintFromTagNumber(tagNumber); + if (DEBUG) { + Log.d(TAG, "innerIfdHint: " + innerIfdHint + " byteCount: " + byteCount); + } if (innerIfdHint >= 0) { long offset = -1L; // Get offset from data field @@ -1650,9 +1682,11 @@ public class ExifInterface { if (DEBUG) { Log.d(TAG, String.format("Offset: %d, tagName: %s", offset, tagName)); } - if (offset > 0L) { + if (offset > 0L && offset < dataInputStream.mLength) { dataInputStream.seek(offset); readImageFileDirectory(dataInputStream, innerIfdHint); + } else { + Log.w(TAG, "Skip jump into the IFD since its offset is invalid: " + offset); } dataInputStream.seek(nextEntryOffset); @@ -1683,14 +1717,17 @@ public class ExifInterface { } } - long nextIfdOffset = dataInputStream.readUnsignedInt(); - if (DEBUG) { - Log.d(TAG, String.format("nextIfdOffset: %d", nextIfdOffset)); - } - // The next IFD offset needs to be bigger than 8 since the first IFD offset is at least 8. - if (nextIfdOffset > 8) { - dataInputStream.seek(nextIfdOffset); - readImageFileDirectory(dataInputStream, IFD_THUMBNAIL_HINT); + if (dataInputStream.peek() + 4 <= dataInputStream.mLength) { + long nextIfdOffset = dataInputStream.readUnsignedInt(); + if (DEBUG) { + Log.d(TAG, String.format("nextIfdOffset: %d", nextIfdOffset)); + } + // The next IFD offset needs to be bigger than 8 + // since the first IFD offset is at least 8. + if (nextIfdOffset > 8 && nextIfdOffset < dataInputStream.mLength) { + dataInputStream.seek(nextIfdOffset); + readImageFileDirectory(dataInputStream, IFD_THUMBNAIL_HINT); + } } } @@ -1748,17 +1785,18 @@ public class ExifInterface { } StringBuilder stringBuilder = new StringBuilder(); - while (true) { + while (index < numberOfComponents) { int ch = bytes[index]; - if (ch == 0) + if (ch == 0) { break; - if (ch >= 32) + } + if (ch >= 32) { stringBuilder.append((char) ch); - else + } + else { stringBuilder.append('?'); + } ++index; - if (index == numberOfComponents) - break; } return stringBuilder.toString(); } @@ -1772,8 +1810,9 @@ public class ExifInterface { // Gets the corresponding IFD group index of the given tag number for writing Exif Tags. private static int getIfdHintFromTagNumber(int tagNumber) { for (int i = 0; i < IFD_POINTER_TAG_HINTS.length; ++i) { - if (IFD_POINTER_TAGS[i].number == tagNumber) + if (IFD_POINTER_TAGS[i].number == tagNumber) { return IFD_POINTER_TAG_HINTS[i]; + } } return -1; } @@ -2076,8 +2115,9 @@ public class ExifInterface { public void seek(long byteCount) throws IOException { mPosition = 0L; reset(); - if (skip(byteCount) != byteCount) + if (skip(byteCount) != byteCount) { throw new IOException("Couldn't seek up to the byteCount"); + } } public long peek() { @@ -2086,8 +2126,9 @@ public class ExifInterface { public void readFully(byte[] buffer) throws IOException { mPosition += buffer.length; - if (mPosition > mLength) + if (mPosition > mLength) { throw new EOFException(); + } if (super.read(buffer, 0, buffer.length) != buffer.length) { throw new IOException("Couldn't read up to the length of buffer"); } @@ -2095,22 +2136,26 @@ public class ExifInterface { public byte readByte() throws IOException { ++mPosition; - if (mPosition > mLength) + if (mPosition > mLength) { throw new EOFException(); + } int ch = super.read(); - if (ch < 0) + if (ch < 0) { throw new EOFException(); + } return (byte) ch; } public short readShort() throws IOException { mPosition += 2; - if (mPosition > mLength) + if (mPosition > mLength) { throw new EOFException(); + } int ch1 = super.read(); int ch2 = super.read(); - if ((ch1 | ch2) < 0) + if ((ch1 | ch2) < 0) { throw new EOFException(); + } if (mByteOrder == LITTLE_ENDIAN) { return (short) ((ch2 << 8) + (ch1)); } else if (mByteOrder == BIG_ENDIAN) { @@ -2121,14 +2166,16 @@ public class ExifInterface { public int readInt() throws IOException { mPosition += 4; - if (mPosition > mLength) + if (mPosition > mLength) { throw new EOFException(); + } int ch1 = super.read(); int ch2 = super.read(); int ch3 = super.read(); int ch4 = super.read(); - if ((ch1 | ch2 | ch3 | ch4) < 0) + if ((ch1 | ch2 | ch3 | ch4) < 0) { throw new EOFException(); + } if (mByteOrder == LITTLE_ENDIAN) { return ((ch4 << 24) + (ch3 << 16) + (ch2 << 8) + ch1); } else if (mByteOrder == BIG_ENDIAN) { @@ -2146,12 +2193,14 @@ public class ExifInterface { public int readUnsignedShort() throws IOException { mPosition += 2; - if (mPosition > mLength) + if (mPosition > mLength) { throw new EOFException(); + } int ch1 = super.read(); int ch2 = super.read(); - if ((ch1 | ch2) < 0) + if ((ch1 | ch2) < 0) { throw new EOFException(); + } if (mByteOrder == LITTLE_ENDIAN) { return ((ch2 << 8) + (ch1)); } else if (mByteOrder == BIG_ENDIAN) { @@ -2166,8 +2215,9 @@ public class ExifInterface { public long readLong() throws IOException { mPosition += 8; - if (mPosition > mLength) + if (mPosition > mLength) { throw new EOFException(); + } int ch1 = super.read(); int ch2 = super.read(); int ch3 = super.read(); @@ -2176,8 +2226,9 @@ public class ExifInterface { int ch6 = super.read(); int ch7 = super.read(); int ch8 = super.read(); - if ((ch1 | ch2 | ch3 | ch4 | ch5 | ch6 | ch7 | ch8) < 0) + if ((ch1 | ch2 | ch3 | ch4 | ch5 | ch6 | ch7 | ch8) < 0) { throw new EOFException(); + } if (mByteOrder == LITTLE_ENDIAN) { return (((long) ch8 << 56) + ((long) ch7 << 48) + ((long) ch6 << 40) + ((long) ch5 << 32) + ((long) ch4 << 24) + ((long) ch3 << 16) |