diff options
author | Kenny Root <kroot@google.com> | 2012-05-10 10:21:06 -0700 |
---|---|---|
committer | Kenny Root <kroot@google.com> | 2012-05-10 11:48:21 -0700 |
commit | 103d53005e7a3c2735f4ac76fa9b795a7e7e39d7 (patch) | |
tree | da5b4a423467f932654ca2db1494bd9e34210f58 | |
parent | a25079e6bafcfd77135a852f0e838738d80606ef (diff) | |
download | frameworks_base-103d53005e7a3c2735f4ac76fa9b795a7e7e39d7.zip frameworks_base-103d53005e7a3c2735f4ac76fa9b795a7e7e39d7.tar.gz frameworks_base-103d53005e7a3c2735f4ac76fa9b795a7e7e39d7.tar.bz2 |
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
4 files changed, 63 insertions, 28 deletions
diff --git a/core/java/android/content/pm/ContainerEncryptionParams.java b/core/java/android/content/pm/ContainerEncryptionParams.java index 5b1440d..88112a7 100644 --- a/core/java/android/content/pm/ContainerEncryptionParams.java +++ b/core/java/android/content/pm/ContainerEncryptionParams.java @@ -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: diff --git a/core/java/android/content/pm/LimitedLengthInputStream.java b/core/java/android/content/pm/LimitedLengthInputStream.java index 25a490f..e787277 100644 --- a/core/java/android/content/pm/LimitedLengthInputStream.java +++ b/core/java/android/content/pm/LimitedLengthInputStream.java @@ -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); diff --git a/core/tests/coretests/src/android/content/pm/LimitedLengthInputStreamTest.java b/core/tests/coretests/src/android/content/pm/LimitedLengthInputStreamTest.java index 0a0152b..1f762fd 100644 --- a/core/tests/coretests/src/android/content/pm/LimitedLengthInputStreamTest.java +++ b/core/tests/coretests/src/android/content/pm/LimitedLengthInputStreamTest.java @@ -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); } - } diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java index 17e5f4e..3b87b96 100644 --- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java +++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java @@ -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; |