Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 977ee2d4 authored by Kholoud Mohamed's avatar Kholoud Mohamed
Browse files

Add bundle policy size verifier

Bug: 326662716
Test: manual testing
Change-Id: I3637559d987ef0be625e4fa30654018511d40762
parent ea94f6db
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -32,7 +32,7 @@ public final class BundlePolicyValue extends PolicyValue<Bundle> {
    public BundlePolicyValue(Bundle value) {
        super(value);
        if (Flags.devicePolicySizeTrackingInternalEnabled()) {
            PolicySizeVerifier.enforceMaxParcelableFieldsLength(value);
            PolicySizeVerifier.enforceMaxBundleFieldsLength(value);
        }
    }

+0 −4
Original line number Diff line number Diff line
@@ -24,7 +24,6 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.app.admin.flags.Flags;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Parcel;
@@ -60,9 +59,6 @@ public final class IntentFilterPolicyKey extends PolicyKey {
    @TestApi
    public IntentFilterPolicyKey(@NonNull String identifier, @NonNull IntentFilter filter) {
        super(identifier);
        if (Flags.devicePolicySizeTrackingInternalEnabled()) {
            PolicySizeVerifier.enforceMaxParcelableFieldsLength(filter);
        }
        mFilter = Objects.requireNonNull(filter);
    }

+35 −28
Original line number Diff line number Diff line
@@ -17,12 +17,12 @@
package android.app.admin;

import android.content.ComponentName;
import android.os.Bundle;
import android.os.Parcelable;
import android.os.PersistableBundle;

import com.android.internal.util.Preconditions;

import java.lang.reflect.Field;
import java.util.ArrayDeque;
import java.util.Queue;

@@ -71,44 +71,51 @@ public class PolicySizeVerifier {
            for (String key : current.keySet()) {
                enforceMaxStringLength(key, "key in " + argName);
                Object value = current.get(key);
                if (value instanceof String) {
                    enforceMaxStringLength((String) value, "string value in " + argName);
                } else if (value instanceof String[]) {
                    for (String str : (String[]) value) {
                if (value instanceof String str) {
                    enforceMaxStringLength(str, "string value in " + argName);
                } else if (value instanceof String[] strArray) {
                    for (String str : strArray) {
                        enforceMaxStringLength(str, "string value in " + argName);
                    }
                } else if (value instanceof PersistableBundle) {
                    queue.add((PersistableBundle) value);
                } else if (value instanceof PersistableBundle persistableBundle) {
                    queue.add(persistableBundle);
                }
            }
        }
    }

    /**
     * Throw if Parcelable contains any string that's too long to be serialized.
     * Throw if bundle contains any string that's too long to be serialized. This follows the
     * serialization logic in BundlePolicySerializer#writeBundle.
     */
    public static void enforceMaxParcelableFieldsLength(Parcelable parcelable) {
        // TODO(b/326662716) rework to protect against infinite recursion.
        if (true) {
            return;
    public static void enforceMaxBundleFieldsLength(Bundle bundle) {
        Queue<Bundle> queue = new ArrayDeque<>();
        queue.add(bundle);
        while (!queue.isEmpty()) {
            Bundle current = queue.remove();
            for (String key : current.keySet()) {
                enforceMaxStringLength(key, "key in Bundle");
                Object value = current.get(key);
                if (value instanceof String str) {
                    enforceMaxStringLength(str, "string value in Bundle with "
                            + "key" + key);
                } else if (value instanceof String[] strArray) {
                    for (String str : strArray) {
                        enforceMaxStringLength(str, "string value in Bundle with"
                                + " key" + key);
                    }
        Class<?> clazz = parcelable.getClass();

        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            try {
                Object value = field.get(parcelable);
                if (value instanceof String) {
                    String stringValue = (String) value;
                    enforceMaxStringLength(stringValue, field.getName());
                } else if (value instanceof Bundle b) {
                    queue.add(b);
                }
                else if (value instanceof Parcelable[] parcelableArray) {
                    for (Parcelable parcelable : parcelableArray) {
                        if (!(parcelable instanceof Bundle)) {
                            throw new IllegalArgumentException("bundle-array can only hold "
                                    + "Bundles");
                        }
                        queue.add((Bundle) parcelable);
                    }

                if (value instanceof Parcelable) {
                    enforceMaxParcelableFieldsLength((Parcelable) value);
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }