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

Commit 621b800c authored by Kenny Root's avatar Kenny Root Committed by The Android Automerger
Browse files

Use long instead of int for file offsets

Use long instead of int so we don't run into a 2GB file limit.

Fix possible overflows in offset and length.

Change-Id: Idb3a34f5600f9c2372b9c89256f21757049fa43b
parent 0d30be29
Loading
Loading
Loading
Loading
+15 −13
Original line number Diff line number Diff line
@@ -70,16 +70,16 @@ public class ContainerEncryptionParams implements Parcelable {
    private final byte[] mMacTag;

    /** Offset into file where authenticated (e.g., MAC protected) data begins. */
    private final int mAuthenticatedDataStart;
    private final long mAuthenticatedDataStart;

    /** Offset into file where encrypted data begins. */
    private final int mEncryptedDataStart;
    private final long mEncryptedDataStart;

    /**
     * Offset into file for the end of encrypted data (and, by extension,
     * authenticated data) in file.
     */
    private final int mDataEnd;
    private final long mDataEnd;

    public ContainerEncryptionParams(String encryptionAlgorithm,
            AlgorithmParameterSpec encryptionSpec, SecretKey encryptionKey)
@@ -99,6 +99,8 @@ public class ContainerEncryptionParams implements Parcelable {
     * @param macAlgorithm MAC algorithm to use; format matches JCE
     * @param macSpec algorithm parameters specification, may be {@code null}
     * @param macKey key used for authentication (i.e., for the MAC tag)
     * @param macTag message authentication code (MAC) tag for the authenticated
     *            data
     * @param authenticatedDataStart offset of start of authenticated data in
     *            stream
     * @param encryptedDataStart offset of start of encrypted data in stream
@@ -109,7 +111,7 @@ public class ContainerEncryptionParams implements Parcelable {
    public ContainerEncryptionParams(String encryptionAlgorithm,
            AlgorithmParameterSpec encryptionSpec, SecretKey encryptionKey, String macAlgorithm,
            AlgorithmParameterSpec macSpec, SecretKey macKey, byte[] macTag,
            int authenticatedDataStart, int encryptedDataStart, int dataEnd)
            long authenticatedDataStart, long encryptedDataStart, long dataEnd)
            throws InvalidAlgorithmParameterException {
        if (TextUtils.isEmpty(encryptionAlgorithm)) {
            throw new NullPointerException("algorithm == null");
@@ -172,15 +174,15 @@ public class ContainerEncryptionParams implements Parcelable {
        return mMacTag;
    }

    public int getAuthenticatedDataStart() {
    public long getAuthenticatedDataStart() {
        return mAuthenticatedDataStart;
    }

    public int getEncryptedDataStart() {
    public long getEncryptedDataStart() {
        return mEncryptedDataStart;
    }

    public int getDataEnd() {
    public long getDataEnd() {
        return mDataEnd;
    }

@@ -315,9 +317,9 @@ public class ContainerEncryptionParams implements Parcelable {

        dest.writeByteArray(mMacTag);

        dest.writeInt(mAuthenticatedDataStart);
        dest.writeInt(mEncryptedDataStart);
        dest.writeInt(mDataEnd);
        dest.writeLong(mAuthenticatedDataStart);
        dest.writeLong(mEncryptedDataStart);
        dest.writeLong(mDataEnd);
    }

    private ContainerEncryptionParams(Parcel source) throws InvalidAlgorithmParameterException {
@@ -333,9 +335,9 @@ public class ContainerEncryptionParams implements Parcelable {

        mMacTag = source.createByteArray();

        mAuthenticatedDataStart = source.readInt();
        mEncryptedDataStart = source.readInt();
        mDataEnd = source.readInt();
        mAuthenticatedDataStart = source.readLong();
        mEncryptedDataStart = source.readLong();
        mDataEnd = source.readLong();

        switch (encParamType) {
            case ENC_PARAMS_IV_PARAMETERS:
+19 −7
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@ package android.content.pm;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;

/**
 * A class that limits the amount of data that is read from an InputStream. When
@@ -15,20 +16,20 @@ public class LimitedLengthInputStream extends FilterInputStream {
    /**
     * The end of the stream where we don't want to allow more data to be read.
     */
    private final int mEnd;
    private final long mEnd;

    /**
     * Current offset in the stream.
     */
    private int mOffset;
    private long mOffset;

    /**
     * @param in underlying stream to wrap
     * @param offset offset into stream where data starts
     * @param length length of data at offset
     * @throws IOException if an error occured with the underlying stream
     * @throws IOException if an error occurred with the underlying stream
     */
    public LimitedLengthInputStream(InputStream in, int offset, int length) throws IOException {
    public LimitedLengthInputStream(InputStream in, long offset, long length) throws IOException {
        super(in);

        if (in == null) {
@@ -36,11 +37,15 @@ public class LimitedLengthInputStream extends FilterInputStream {
        }

        if (offset < 0) {
            throw new IOException("offset == " + offset);
            throw new IOException("offset < 0");
        }

        if (length < 0) {
            throw new IOException("length must be non-negative; is " + length);
            throw new IOException("length < 0");
        }

        if (length > Long.MAX_VALUE - offset) {
            throw new IOException("offset + length > Long.MAX_VALUE");
        }

        mEnd = offset + length;
@@ -65,8 +70,15 @@ public class LimitedLengthInputStream extends FilterInputStream {
            return -1;
        }

        final int arrayLength = buffer.length;
        Arrays.checkOffsetAndCount(arrayLength, offset, byteCount);

        if (mOffset > Long.MAX_VALUE - byteCount) {
            throw new IOException("offset out of bounds: " + mOffset + " + " + byteCount);
        }

        if (mOffset + byteCount > mEnd) {
            byteCount = mEnd - mOffset;
            byteCount = (int) (mEnd - mOffset);
        }

        final int numRead = super.read(buffer, offset, byteCount);
+11 −1
Original line number Diff line number Diff line
@@ -66,6 +66,17 @@ public class LimitedLengthInputStreamTest extends AndroidTestCase {
        }
    }

    @MediumTest
    public void testConstructor_OffsetLengthOverflow_Fail() throws Exception {
        try {
        InputStream is = new LimitedLengthInputStream(mTestStream1, Long.MAX_VALUE - 1,
                Long.MAX_VALUE - 1);
            fail("Should fail when offset + length is > Long.MAX_VALUE");
        } catch (IOException e) {
            // success
        }
    }

    private void checkReadBytesWithOffsetAndLength_WithString1(int offset, int length)
            throws Exception {
        byte[] temp = new byte[TEST_STRING1.length];
@@ -182,5 +193,4 @@ public class LimitedLengthInputStreamTest extends AndroidTestCase {
    public void testSingleByteRead_NonZeroOffset_FullLength_Success() throws Exception {
        checkSingleByteRead_WithString1(3, TEST_STRING1.length - 3);
    }

}
+18 −7
Original line number Diff line number Diff line
@@ -473,6 +473,8 @@ public class DefaultContainerService extends IntentService {
    }

    private static class ApkContainer {
        private static final int MAX_AUTHENTICATED_DATA_SIZE = 16384;

        private final InputStream mInStream;

        private MacAuthenticatedInputStream mAuthenticatedStream;
@@ -540,26 +542,35 @@ public class DefaultContainerService extends IntentService {
                throw new IOException(e);
            }

            final int encStart = encryptionParams.getEncryptedDataStart();
            final int end = encryptionParams.getDataEnd();
            final long encStart = encryptionParams.getEncryptedDataStart();
            final long end = encryptionParams.getDataEnd();
            if (end < encStart) {
                throw new IOException("end <= encStart");
            }

            final Mac mac = getMacInstance(encryptionParams);
            if (mac != null) {
                final int macStart = encryptionParams.getAuthenticatedDataStart();
                final long macStart = encryptionParams.getAuthenticatedDataStart();
                if (macStart >= Integer.MAX_VALUE) {
                    throw new IOException("macStart >= Integer.MAX_VALUE");
                }

                final int furtherOffset;
                final long furtherOffset;
                if (macStart >= 0 && encStart >= 0 && macStart < encStart) {
                    /*
                     * If there is authenticated data at the beginning, read
                     * that into our MAC first.
                     */
                    final int authenticatedLength = encStart - macStart;
                    final byte[] authenticatedData = new byte[authenticatedLength];
                    final long authenticatedLengthLong = encStart - macStart;
                    if (authenticatedLengthLong > MAX_AUTHENTICATED_DATA_SIZE) {
                        throw new IOException("authenticated data is too long");
                    }
                    final int authenticatedLength = (int) authenticatedLengthLong;

                    final byte[] authenticatedData = new byte[(int) authenticatedLength];

                    Streams.readFully(inStream, authenticatedData, macStart, authenticatedLength);
                    Streams.readFully(inStream, authenticatedData, (int) macStart,
                            authenticatedLength);
                    mac.update(authenticatedData, 0, authenticatedLength);

                    furtherOffset = 0;