Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6cc4575c authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "ExifInterface: Prevent infinite loop" into pi-dev

parents d101084d 12e7aa58
Loading
Loading
Loading
Loading
+38 −14
Original line number Diff line number Diff line
@@ -1222,7 +1222,7 @@ public class ExifInterface {
            TAG_F_NUMBER, TAG_DIGITAL_ZOOM_RATIO, TAG_EXPOSURE_TIME, TAG_SUBJECT_DISTANCE,
            TAG_GPS_TIMESTAMP));
    // Mappings from tag number to IFD type for pointer tags.
    private static final HashMap sExifPointerTagMap = new HashMap();
    private static final HashMap<Integer, Integer> sExifPointerTagMap = new HashMap();

    // See JPEG File Interchange Format Version 1.02.
    // The following values are defined for handling JPEG streams. In this implementation, we are
@@ -1299,6 +1299,7 @@ public class ExifInterface {
    private final boolean mIsInputStream;
    private int mMimeType;
    private final HashMap[] mAttributes = new HashMap[EXIF_TAGS.length];
    private Set<Integer> mAttributesOffsets = new HashSet<>(EXIF_TAGS.length);
    private ByteOrder mExifByteOrder = ByteOrder.BIG_ENDIAN;
    private boolean mHasThumbnail;
    // The following values used for indicating a thumbnail position.
@@ -2957,8 +2958,9 @@ public class ExifInterface {
        }
        // See TIFF 6.0 Section 2: TIFF Structure, Figure 1.
        short numberOfDirectoryEntry = dataInputStream.readShort();
        if (dataInputStream.mPosition + 12 * numberOfDirectoryEntry > dataInputStream.mLength) {
            // Return if the size of entries is too big.
        if (dataInputStream.mPosition + 12 * numberOfDirectoryEntry > dataInputStream.mLength
                || numberOfDirectoryEntry <= 0) {
            // Return if the size of entries is either too big or negative.
            return;
        }

@@ -3049,7 +3051,7 @@ public class ExifInterface {
            }

            // Recursively parse IFD when a IFD pointer tag appears.
            Object nextIfdType = sExifPointerTagMap.get(tagNumber);
            Integer nextIfdType = sExifPointerTagMap.get(tagNumber);
            if (DEBUG) {
                Log.d(TAG, "nextIfdType: " + nextIfdType + " byteCount: " + byteCount);
            }
@@ -3083,9 +3085,20 @@ public class ExifInterface {
                if (DEBUG) {
                    Log.d(TAG, String.format("Offset: %d, tagName: %s", offset, tag.name));
                }

                // Check if the next IFD offset
                // 1. Exists within the boundaries of the input stream
                // 2. Does not point to a previously read IFD.
                if (offset > 0L && offset < dataInputStream.mLength) {
                    if (!mAttributesOffsets.contains((int) offset)) {
                        // Save offset of current IFD to prevent reading an IFD that is already read
                        mAttributesOffsets.add(dataInputStream.mPosition);
                        dataInputStream.seek(offset);
                    readImageFileDirectory(dataInputStream, (int) nextIfdType);
                        readImageFileDirectory(dataInputStream, nextIfdType);
                    } else {
                        Log.w(TAG, "Skip jump into the IFD since it has already been read: "
                                + "IfdType " + nextIfdType + " (at " + offset + ")");
                    }
                } else {
                    Log.w(TAG, "Skip jump into the IFD since its offset is invalid: " + offset);
                }
@@ -3127,16 +3140,27 @@ public class ExifInterface {
            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) {
            // Check if the next IFD offset
            // 1. Exists within the boundaries of the input stream
            // 2. Does not point to a previously read IFD.
            if (nextIfdOffset > 0L && nextIfdOffset < dataInputStream.mLength) {
                if (!mAttributesOffsets.contains(nextIfdOffset)) {
                    // Save offset of current IFD to prevent reading an IFD that is already read.
                    mAttributesOffsets.add(dataInputStream.mPosition);
                    dataInputStream.seek(nextIfdOffset);
                if (mAttributes[IFD_TYPE_THUMBNAIL].isEmpty()) {
                    // Do not overwrite thumbnail IFD data if it alreay exists.
                    if (mAttributes[IFD_TYPE_THUMBNAIL].isEmpty()) {
                        readImageFileDirectory(dataInputStream, IFD_TYPE_THUMBNAIL);
                    } else if (mAttributes[IFD_TYPE_PREVIEW].isEmpty()) {
                        readImageFileDirectory(dataInputStream, IFD_TYPE_PREVIEW);
                    }
                } else {
                    Log.w(TAG, "Stop reading file since re-reading an IFD may cause an "
                            + "infinite loop: " + nextIfdOffset);
                }
            } else {
                Log.w(TAG, "Stop reading file since a wrong offset may cause an infinite loop: "
                        + nextIfdOffset);
            }
        }
    }