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

Commit dadd7c98 authored by Pavel Grafov's avatar Pavel Grafov Committed by Android Build Coastguard Worker
Browse files

Ensure policy has no absurdly long strings

The following APIs now enforce limits and throw IllegalArgumentException
when limits are violated:
* DPM.setTrustAgentConfiguration() limits agent packgage name,
  component name, and strings within configuration bundle.
* DPM.setPermittedAccessibilityServices() limits package names.
* DPM.setPermittedInputMethods() limits package names.
* DPM.setAccountManagementDisabled() limits account name.
* DPM.setLockTaskPackages() limits package names.
* DPM.setAffiliationIds() limits id.
* DPM.transferOwnership() limits strings inside the bundle.

Package names are limited at 223, because they become directory names
and it is a filesystem restriction, see FrameworkParsingPackageUtils.

All other strings are limited at 65535, because longer ones break binary
XML serializer.

The following APIs silently truncate strings that are long beyond reason:
* DPM.setShortSupportMessage() truncates message at 200.
* DPM.setLongSupportMessage() truncates message at 20000.
* DPM.setOrganizationName() truncates org name at 200.

Bug: 260729089
Test: atest com.android.server.devicepolicy
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:456dbcae5ae4bc0d8f73f8cb97b57c8de6958f9c)
Merged-In: Idcf54e408722f164d16bf2f24a00cd1f5b626d23
Change-Id: Idcf54e408722f164d16bf2f24a00cd1f5b626d23
parent 132c85c4
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -12402,7 +12402,8 @@ public class DevicePolicyManager {
    /**
     * Called by a device admin to set the long support message. This will be displayed to the user
     * in the device administators settings screen.
     * in the device administrators settings screen. If the message is longer than 20000 characters
     * it may be truncated.
     * <p>
     * If the long support message needs to be localized, it is the responsibility of the
     * {@link DeviceAdminReceiver} to listen to the {@link Intent#ACTION_LOCALE_CHANGED} broadcast
+89 −3
Original line number Diff line number Diff line
@@ -397,6 +397,7 @@ import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.text.DateFormat;
import java.time.LocalDate;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -408,6 +409,7 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
@@ -439,7 +441,15 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
    private static final int REQUEST_PROFILE_OFF_DEADLINE = 5572;
    // Binary XML serializer doesn't support longer strings
    private static final int MAX_POLICY_STRING_LENGTH = 65535;
    // FrameworkParsingPackageUtils#MAX_FILE_NAME_SIZE, Android packages are used in dir names.
    private static final int MAX_PACKAGE_NAME_LENGTH = 223;
    private static final int MAX_PROFILE_NAME_LENGTH = 200;
    private static final int MAX_LONG_SUPPORT_MESSAGE_LENGTH = 20000;
    private static final int MAX_SHORT_SUPPORT_MESSAGE_LENGTH = 200;
    private static final int MAX_ORG_NAME_LENGTH = 200;
    private static final long MS_PER_DAY = TimeUnit.DAYS.toMillis(1);
@@ -10053,6 +10063,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        }
        Objects.requireNonNull(admin, "admin is null");
        Objects.requireNonNull(agent, "agent is null");
        enforceMaxPackageNameLength(agent.getPackageName());
        final String agentAsString = agent.flattenToString();
        enforceMaxStringLength(agentAsString, "agent name");
        if (args != null) {
            enforceMaxStringLength(args, "args");
        }
        final int userHandle = UserHandle.getCallingUserId();
        synchronized (getLockObject()) {
            ActiveAdmin ap = getActiveAdminForCallerLocked(admin,
@@ -10294,6 +10310,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        final CallerIdentity caller = getCallerIdentity(who);
        if (packageList != null) {
            for (String pkg : packageList) {
                enforceMaxPackageNameLength(pkg);
            }
            int userId = caller.getUserId();
            final List<AccessibilityServiceInfo> enabledServices;
            long id = mInjector.binderClearCallingIdentity();
@@ -10463,6 +10483,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        }
        if (packageList != null) {
            for (String pkg : packageList) {
                enforceMaxPackageNameLength(pkg);
            }
            List<InputMethodInfo> enabledImes = mInjector.binderWithCleanCallingIdentity(() ->
                    InputMethodManagerInternal.get().getEnabledInputMethodListAsUser(userId));
            if (enabledImes != null) {
@@ -11793,6 +11817,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
            return;
        }
        Objects.requireNonNull(who, "ComponentName is null");
        enforceMaxStringLength(accountType, "account type");
        final CallerIdentity caller = getCallerIdentity(who);
        synchronized (getLockObject()) {
            /*
@@ -12214,6 +12240,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
            throws SecurityException {
        Objects.requireNonNull(who, "ComponentName is null");
        Objects.requireNonNull(packages, "packages is null");
        for (String pkg : packages) {
            enforceMaxPackageNameLength(pkg);
        }
        final CallerIdentity caller = getCallerIdentity(who);
        synchronized (getLockObject()) {
@@ -14333,6 +14363,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
            return;
        }
        Objects.requireNonNull(who, "ComponentName is null");
        message = truncateIfLonger(message, MAX_SHORT_SUPPORT_MESSAGE_LENGTH);
        final CallerIdentity caller = getCallerIdentity(who);
        synchronized (getLockObject()) {
            ActiveAdmin admin = getActiveAdminForUidLocked(who, caller.getUid());
@@ -14365,6 +14397,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        if (!mHasFeature) {
            return;
        }
        message = truncateIfLonger(message, MAX_LONG_SUPPORT_MESSAGE_LENGTH);
        Objects.requireNonNull(who, "ComponentName is null");
        final CallerIdentity caller = getCallerIdentity(who);
        synchronized (getLockObject()) {
@@ -14514,6 +14549,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        Objects.requireNonNull(who, "ComponentName is null");
        final CallerIdentity caller = getCallerIdentity(who);
        text = truncateIfLonger(text, MAX_ORG_NAME_LENGTH);
        synchronized (getLockObject()) {
            ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
            if (!TextUtils.equals(admin.organizationName, text)) {
@@ -14786,9 +14823,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
            throw new IllegalArgumentException("ids must not be null");
        }
        for (String id : ids) {
            if (TextUtils.isEmpty(id)) {
                throw new IllegalArgumentException("ids must not contain empty string");
            }
            Preconditions.checkArgument(!TextUtils.isEmpty(id), "ids must not have empty string");
            enforceMaxStringLength(id, "affiliation id");
        }
        final Set<String> affiliationIds = new ArraySet<>(ids);
@@ -16099,6 +16135,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
                "Provided administrator and target are the same object.");
        Preconditions.checkArgument(!admin.getPackageName().equals(target.getPackageName()),
                "Provided administrator and target have the same package name.");
        if (bundle != null) {
            enforceMaxStringLength(bundle, "bundle");
        }
        final CallerIdentity caller = getCallerIdentity(admin);
        Preconditions.checkCallAuthorization(
@@ -18900,4 +18939,51 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
            return result;
        });
    }
    /**
     * Truncates char sequence to maximum length, nulls are ignored.
     */
    private static CharSequence truncateIfLonger(CharSequence input, int maxLength) {
        return input == null || input.length() <= maxLength
                ? input
                : input.subSequence(0, maxLength);
    }
    /**
     * Throw if string argument is too long to be serialized.
     */
    private static void enforceMaxStringLength(String str, String argName) {
        Preconditions.checkArgument(
                str.length() <= MAX_POLICY_STRING_LENGTH, argName + " loo long");
    }
    private static void enforceMaxPackageNameLength(String pkg) {
        Preconditions.checkArgument(
                pkg.length() <= MAX_PACKAGE_NAME_LENGTH, "Package name too long");
    }
    /**
     * Throw if persistable bundle contains any string that we can't serialize.
     */
    private static void enforceMaxStringLength(PersistableBundle bundle, String argName) {
        // Persistable bundles can have other persistable bundles as values, traverse with a queue.
        Queue<PersistableBundle> queue = new ArrayDeque<>();
        queue.add(bundle);
        while (!queue.isEmpty()) {
            PersistableBundle current = queue.remove();
            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) {
                        enforceMaxStringLength(str, "string value in " + argName);
                    }
                } else if (value instanceof PersistableBundle) {
                    queue.add((PersistableBundle) value);
                }
            }
        }
    }
}