2121import android .annotation .NonNull ;
2222import android .annotation .Nullable ;
2323import android .util .ArrayMap ;
24+ import android .util .Slog ;
2425import android .util .TypedXmlPullParser ;
2526import android .util .TypedXmlSerializer ;
2627import android .util .Xml ;
5051 */
5152public final class PersistableBundle extends BaseBundle implements Cloneable , Parcelable ,
5253 XmlUtils .WriteMapCallback {
54+ private static final String TAG = "PersistableBundle" ;
55+
5356 private static final String TAG_PERSISTABLEMAP = "pbundle_as_map" ;
5457
5558 /** An unmodifiable {@code PersistableBundle} that is always {@link #isEmpty() empty}. */
@@ -118,7 +121,11 @@ public PersistableBundle(PersistableBundle b) {
118121 * @hide
119122 */
120123 public PersistableBundle (Bundle b ) {
121- this (b .getItemwiseMap ());
124+ this (b , true );
125+ }
126+
127+ private PersistableBundle (Bundle b , boolean throwException ) {
128+ this (b .getItemwiseMap (), throwException );
122129 }
123130
124131 /**
@@ -127,7 +134,7 @@ public PersistableBundle(Bundle b) {
127134 * @param map a Map containing only those items that can be persisted.
128135 * @throws IllegalArgumentException if any element of #map cannot be persisted.
129136 */
130- private PersistableBundle (ArrayMap <String , Object > map ) {
137+ private PersistableBundle (ArrayMap <String , Object > map , boolean throwException ) {
131138 super ();
132139 mFlags = FLAG_DEFUSABLE ;
133140
@@ -136,16 +143,23 @@ private PersistableBundle(ArrayMap<String, Object> map) {
136143
137144 // Now verify each item throwing an exception if there is a violation.
138145 final int N = mMap .size ();
139- for (int i = 0 ; i < N ; i ++ ) {
146+ for (int i = N - 1 ; i >= 0 ; -- i ) {
140147 Object value = mMap .valueAt (i );
141148 if (value instanceof ArrayMap ) {
142149 // Fix up any Maps by replacing them with PersistableBundles.
143- mMap .setValueAt (i , new PersistableBundle ((ArrayMap <String , Object >) value ));
150+ mMap .setValueAt (i ,
151+ new PersistableBundle ((ArrayMap <String , Object >) value , throwException ));
144152 } else if (value instanceof Bundle ) {
145- mMap .setValueAt (i , new PersistableBundle ((( Bundle ) value ) ));
153+ mMap .setValueAt (i , new PersistableBundle ((Bundle ) value , throwException ));
146154 } else if (!isValidType (value )) {
147- throw new IllegalArgumentException ("Bad value in PersistableBundle key="
148- + mMap .keyAt (i ) + " value=" + value );
155+ final String errorMsg = "Bad value in PersistableBundle key="
156+ + mMap .keyAt (i ) + " value=" + value ;
157+ if (throwException ) {
158+ throw new IllegalArgumentException (errorMsg );
159+ } else {
160+ Slog .wtfStack (TAG , errorMsg );
161+ mMap .removeAt (i );
162+ }
149163 }
150164 }
151165 }
@@ -268,6 +282,15 @@ public void saveToXml(XmlSerializer out) throws IOException, XmlPullParserExcept
268282 /** @hide */
269283 public void saveToXml (TypedXmlSerializer out ) throws IOException , XmlPullParserException {
270284 unparcel ();
285+ // Explicitly drop invalid types an attacker may have added before persisting.
286+ for (int i = mMap .size () - 1 ; i >= 0 ; --i ) {
287+ final Object value = mMap .valueAt (i );
288+ if (!isValidType (value )) {
289+ Slog .e (TAG , "Dropping bad data before persisting: "
290+ + mMap .keyAt (i ) + "=" + value );
291+ mMap .removeAt (i );
292+ }
293+ }
271294 XmlUtils .writeMapXml (mMap , out , this );
272295 }
273296
@@ -322,9 +345,12 @@ public static PersistableBundle restoreFromXml(TypedXmlPullParser in) throws IOE
322345 while (((event = in .next ()) != XmlPullParser .END_DOCUMENT ) &&
323346 (event != XmlPullParser .END_TAG || in .getDepth () < outerDepth )) {
324347 if (event == XmlPullParser .START_TAG ) {
348+ // Don't throw an exception when restoring from XML since an attacker could try to
349+ // input invalid data in the persisted file.
325350 return new PersistableBundle ((ArrayMap <String , Object >)
326351 XmlUtils .readThisArrayMapXml (in , startTag , tagName ,
327- new MyReadMapCallback ()));
352+ new MyReadMapCallback ()),
353+ /* throwException */ false );
328354 }
329355 }
330356 return new PersistableBundle (); // An empty mutable PersistableBundle
0 commit comments