diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java index 7425f67e17d2d..575b072732f3b 100644 --- a/core/java/android/os/Parcel.java +++ b/core/java/android/os/Parcel.java @@ -599,7 +599,7 @@ public final class Parcel { * Flatten an ArrayMap into the parcel at the current dataPosition(), * growing dataCapacity() if needed. The Map keys must be String objects. */ - /* package */ void writeArrayMapInternal(ArrayMap val) { + /* package */ void writeArrayMapInternal(ArrayMap val) { if (val == null) { writeInt(-1); return; @@ -614,7 +614,7 @@ public final class Parcel { int startPos; for (int i=0; i val) { + writeArrayMapInternal(val); + } + /** * Flatten a Bundle into the parcel at the current dataPosition(), * growing dataCapacity() if needed. @@ -2321,7 +2328,7 @@ public final class Parcel { int startPos; while (N > 0) { if (DEBUG_ARRAY_MAP) startPos = dataPosition(); - Object key = readValue(loader); + String key = readString(); Object value = readValue(loader); if (DEBUG_ARRAY_MAP) Log.d(TAG, " Read #" + (N-1) + " " + (dataPosition()-startPos) + " bytes: key=0x" @@ -2329,6 +2336,7 @@ public final class Parcel { outVal.append(key, value); N--; } + outVal.validate(); } /* package */ void readArrayMapSafelyInternal(ArrayMap outVal, int N, @@ -2339,7 +2347,7 @@ public final class Parcel { Log.d(TAG, "Reading safely " + N + " ArrayMap entries", here); } while (N > 0) { - Object key = readValue(loader); + String key = readString(); if (DEBUG_ARRAY_MAP) Log.d(TAG, " Read safe #" + (N-1) + ": key=0x" + (key != null ? key.hashCode() : 0) + " " + key); Object value = readValue(loader); @@ -2348,6 +2356,17 @@ public final class Parcel { } } + /** + * @hide For testing only. + */ + public void readArrayMap(ArrayMap outVal, ClassLoader loader) { + final int N = readInt(); + if (N < 0) { + return; + } + readArrayMapInternal(outVal, N, loader); + } + private void readListInternal(List outVal, int N, ClassLoader loader) { while (N > 0) { diff --git a/core/java/android/util/ArrayMap.java b/core/java/android/util/ArrayMap.java index df1d4cd7047a6..8ea23ba12c5c8 100644 --- a/core/java/android/util/ArrayMap.java +++ b/core/java/android/util/ArrayMap.java @@ -493,6 +493,44 @@ public final class ArrayMap implements Map { mArray[index+1] = value; } + /** + * The use of the {@link #append} function can result in invalid array maps, in particular + * an array map where the same key appears multiple times. This function verifies that + * the array map is valid, throwing IllegalArgumentException if a problem is found. The + * main use for this method is validating an array map after unpacking from an IPC, to + * protect against malicious callers. + * @hide + */ + public void validate() { + final int N = mSize; + if (N <= 1) { + // There can't be dups. + return; + } + int basehash = mHashes[0]; + int basei = 0; + for (int i=1; i=basei; j--) { + final Object prev = mArray[j<<1]; + if (cur == prev) { + throw new IllegalArgumentException("Duplicate key in ArrayMap: " + cur); + } + if (cur != null && prev != null && cur.equals(prev)) { + throw new IllegalArgumentException("Duplicate key in ArrayMap: " + cur); + } + } + } + } + /** * Perform a {@link #put(Object, Object)} of all key/value pairs in array * @param array The array whose contents are to be retrieved.