summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKweku Adams <kwekua@google.com>2022-09-23 21:06:53 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-10-11 22:46:47 +0000
commitae1a63390d4b7fc2152417ca2bdd2ef09c18598b (patch)
tree90a96f0fdca4f0af1fb88fc11d040ee67c427cb6
parent92d2e8793938b640c149c8e911261696e9de6e7b (diff)
downloadbase-ae1a63390d4b7fc2152417ca2bdd2ef09c18598b.tar.gz
RESTRICT AUTOMERGE: Drop invalid data.
Drop invalid data when writing or reading from XML. PersistableBundle does lazy unparcelling, so checking the values during unparcelling would remove the benefit of the lazy unparcelling. Checking the validity when writing to or reading from XML seems like the best alternative. Bug: 246542285 Bug: 247513680 Test: install test app with invalid job config, start app to schedule job, then check logcat and jobscheduler persisted file (cherry picked from commit 666e8ac60a31e2cc52b335b41004263f28a8db06) (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:0e0819c9d6a957e56764c89e68542bb51bdb7db4) Merged-In: Ie817aa0993e9046cb313a750d2323cadc8c1ef15 Change-Id: Ie817aa0993e9046cb313a750d2323cadc8c1ef15
-rw-r--r--core/java/android/os/PersistableBundle.java42
1 files changed, 34 insertions, 8 deletions
diff --git a/core/java/android/os/PersistableBundle.java b/core/java/android/os/PersistableBundle.java
index e5e9b5f6f53c..9718b52eafeb 100644
--- a/core/java/android/os/PersistableBundle.java
+++ b/core/java/android/os/PersistableBundle.java
@@ -21,6 +21,7 @@ import static java.nio.charset.StandardCharsets.UTF_8;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.util.ArrayMap;
+import android.util.Slog;
import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
import android.util.Xml;
@@ -46,6 +47,8 @@ import java.util.ArrayList;
*/
public final class PersistableBundle extends BaseBundle implements Cloneable, Parcelable,
XmlUtils.WriteMapCallback {
+ private static final String TAG = "PersistableBundle";
+
private static final String TAG_PERSISTABLEMAP = "pbundle_as_map";
/** An unmodifiable {@code PersistableBundle} that is always {@link #isEmpty() empty}. */
@@ -110,7 +113,11 @@ public final class PersistableBundle extends BaseBundle implements Cloneable, Pa
* @hide
*/
public PersistableBundle(Bundle b) {
- this(b.getMap());
+ this(b, true);
+ }
+
+ private PersistableBundle(Bundle b, boolean throwException) {
+ this(b.getMap(), throwException);
}
/**
@@ -119,7 +126,7 @@ public final class PersistableBundle extends BaseBundle implements Cloneable, Pa
* @param map a Map containing only those items that can be persisted.
* @throws IllegalArgumentException if any element of #map cannot be persisted.
*/
- private PersistableBundle(ArrayMap<String, Object> map) {
+ private PersistableBundle(ArrayMap<String, Object> map, boolean throwException) {
super();
mFlags = FLAG_DEFUSABLE;
@@ -128,16 +135,23 @@ public final class PersistableBundle extends BaseBundle implements Cloneable, Pa
// Now verify each item throwing an exception if there is a violation.
final int N = mMap.size();
- for (int i=0; i<N; i++) {
+ for (int i = N - 1; i >= 0; --i) {
Object value = mMap.valueAt(i);
if (value instanceof ArrayMap) {
// Fix up any Maps by replacing them with PersistableBundles.
- mMap.setValueAt(i, new PersistableBundle((ArrayMap<String, Object>) value));
+ mMap.setValueAt(i,
+ new PersistableBundle((ArrayMap<String, Object>) value, throwException));
} else if (value instanceof Bundle) {
- mMap.setValueAt(i, new PersistableBundle(((Bundle) value)));
+ mMap.setValueAt(i, new PersistableBundle((Bundle) value, throwException));
} else if (!isValidType(value)) {
- throw new IllegalArgumentException("Bad value in PersistableBundle key="
- + mMap.keyAt(i) + " value=" + value);
+ final String errorMsg = "Bad value in PersistableBundle key="
+ + mMap.keyAt(i) + " value=" + value;
+ if (throwException) {
+ throw new IllegalArgumentException(errorMsg);
+ } else {
+ Slog.wtfStack(TAG, errorMsg);
+ mMap.removeAt(i);
+ }
}
}
}
@@ -257,6 +271,15 @@ public final class PersistableBundle extends BaseBundle implements Cloneable, Pa
/** @hide */
public void saveToXml(TypedXmlSerializer out) throws IOException, XmlPullParserException {
unparcel();
+ // Explicitly drop invalid types an attacker may have added before persisting.
+ for (int i = mMap.size() - 1; i >= 0; --i) {
+ final Object value = mMap.valueAt(i);
+ if (!isValidType(value)) {
+ Slog.e(TAG, "Dropping bad data before persisting: "
+ + mMap.keyAt(i) + "=" + value);
+ mMap.removeAt(i);
+ }
+ }
XmlUtils.writeMapXml(mMap, out, this);
}
@@ -311,9 +334,12 @@ public final class PersistableBundle extends BaseBundle implements Cloneable, Pa
while (((event = in.next()) != XmlPullParser.END_DOCUMENT) &&
(event != XmlPullParser.END_TAG || in.getDepth() < outerDepth)) {
if (event == XmlPullParser.START_TAG) {
+ // Don't throw an exception when restoring from XML since an attacker could try to
+ // input invalid data in the persisted file.
return new PersistableBundle((ArrayMap<String, Object>)
XmlUtils.readThisArrayMapXml(in, startTag, tagName,
- new MyReadMapCallback()));
+ new MyReadMapCallback()),
+ /* throwException */ false);
}
}
return EMPTY;