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

Commit 80c32681 authored by Elis Elliott's avatar Elis Elliott
Browse files

Create permission check methods in DPMS

Bug: 234609037

Test: atest
android.devicepolicy.cts.DevicePolicyManagementRoleHolderTest

Change-Id: I4e7182dbafabc66fecbe7725684f374356800fcd
parent 5829ea74
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
@@ -270,6 +270,31 @@ public abstract class DevicePolicyManagerInternal {
     */
    public abstract void resetOp(int op, String packageName, @UserIdInt int userId);

    /**
     * Checks if the calling process has been granted permission to apply a device policy on a
     * specific user.
     *
     * The given permission will be checked along with its associated cross-user permission, if it
     * exists and the target user is different to the calling user.
     *
     * @param permission The name of the permission being checked.
     * @param targetUserId The userId of the user which the caller needs permission to act on.
     * @throws SecurityException If the calling process has not been granted the permission.
     */
    public abstract void enforcePermission(String permission, int targetUserId);

    /**
     * Return whether the calling process has been granted permission to apply a device policy on
     * a specific user.
     *
     * The given permission will be checked along with its associated cross-user
     * permission, if it exists and the target user is different to the calling user.
     *
     * @param permission The name of the permission being checked.
     * @param targetUserId The userId of the user which the caller needs permission to act on.
     */
    public abstract boolean hasPermission(String permission, int targetUserId);

    /**
     * Returns whether new "turn off work" behavior is enabled via feature flag.
     */
+200 −6
Original line number Diff line number Diff line
@@ -18,6 +18,10 @@ package com.android.server.devicepolicy;
import static android.Manifest.permission.BIND_DEVICE_ADMIN;
import static android.Manifest.permission.MANAGE_CA_CERTIFICATES;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_ACROSS_USERS;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL;
import static android.Manifest.permission.QUERY_ADMIN_POLICY;
import static android.Manifest.permission.REQUEST_PASSWORD_COMPLEXITY;
import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_ALL_MASK;
import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
@@ -137,6 +141,7 @@ import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_DEFAULT;
import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE;
import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK;
@@ -13393,6 +13398,16 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
            broadcastIntentToDevicePolicyManagerRoleHolder(intent, parentHandle);
        }
        @Override
        public void enforcePermission(String permission, int targetUserId) {
            DevicePolicyManagerService.this.enforcePermission(permission, targetUserId);
        }
        @Override
        public boolean hasPermission(String permission, int targetUserId) {
            return DevicePolicyManagerService.this.hasPermission(permission, targetUserId);
        }
        private void broadcastIntentToCrossProfileManifestReceivers(
                Intent intent, UserHandle userHandle, boolean requiresPermission) {
            final int userId = userHandle.getIdentifier();
@@ -18137,14 +18152,25 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        }
    }
    private String getDevicePolicyManagementRoleHolderPackageName(Context context) {
        RoleManager roleManager = context.getSystemService(RoleManager.class);
        // Calling identity needs to be cleared as this method is used in the permissions checks.
        return mInjector.binderWithCleanCallingIdentity(() -> {
            List<String> roleHolders =
                    roleManager.getRoleHolders(RoleManager.ROLE_DEVICE_POLICY_MANAGEMENT);
            if (roleHolders.isEmpty()) {
                return null;
            }
            return roleHolders.get(0);
        });
    }
    private boolean isDevicePolicyManagementRoleHolder(CallerIdentity caller) {
        String devicePolicyManagementRoleHolderPackageName =
                getDevicePolicyManagementRoleHolderPackageName(mContext);
        return caller.getPackageName().equals(devicePolicyManagementRoleHolderPackageName);
    }
    private void resetInteractAcrossProfilesAppOps() {
@@ -19221,6 +19247,174 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        });
    }
    // DPC types
    private static final int DEFAULT_DEVICE_OWNER = 0;
    private static final int FINANCED_DEVICE_OWNER = 1;
    private static final int PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE = 2;
    private static final int PROFILE_OWNER_ON_USER_0 = 3;
    private static final int PROFILE_OWNER = 4;
    // Permissions of existing DPC types.
    private static final List<String> DEFAULT_DEVICE_OWNER_PERMISSIONS = List.of(
            MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL,
            MANAGE_DEVICE_POLICY_ACROSS_USERS,
            MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL);
    private static final List<String> FINANCED_DEVICE_OWNER_PERMISSIONS = List.of(
            MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL,
            MANAGE_DEVICE_POLICY_ACROSS_USERS,
            MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL);
    private static final List<String> PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE_PERMISSIONS =
            List.of(
                MANAGE_DEVICE_POLICY_ACROSS_USERS,
                MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL);
    private static final List<String> PROFILE_OWNER_ON_USER_0_PERMISSIONS  = List.of();
    private static final List<String> PROFILE_OWNER_PERMISSIONS  = List.of(
            MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL);
    private static final HashMap<Integer, List<String>> DPC_PERMISSIONS = new HashMap<>();
    {
        DPC_PERMISSIONS.put(DEFAULT_DEVICE_OWNER, DEFAULT_DEVICE_OWNER_PERMISSIONS);
        DPC_PERMISSIONS.put(FINANCED_DEVICE_OWNER, FINANCED_DEVICE_OWNER_PERMISSIONS);
        DPC_PERMISSIONS.put(PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE,
                PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE_PERMISSIONS);
        DPC_PERMISSIONS.put(PROFILE_OWNER_ON_USER_0, PROFILE_OWNER_ON_USER_0_PERMISSIONS);
        DPC_PERMISSIONS.put(PROFILE_OWNER, PROFILE_OWNER_PERMISSIONS);
    }
    //TODO(b/254253251) Fill this map in as new permissions are added for policies.
    private static final HashMap<String, Integer> ACTIVE_ADMIN_POLICIES = new HashMap<>();
    private static final HashMap<String, String> CROSS_USER_PERMISSIONS = new HashMap<>();
    /**
     * Checks if the calling process has been granted permission to apply a device policy on a
     * specific user.
     * The given permission will be checked along with its associated cross-user permission if it
     * exists and the target user is different to the calling user.
     *
     * @param permission The name of the permission being checked.
     * @param targetUserId The userId of the user which the caller needs permission to act on.
     * @throws SecurityException if the caller has not been granted the given permission,
     * the associtated cross-user permission if the caller's user is different to the target user.
     */
    private void enforcePermission(String permission, int targetUserId)
            throws SecurityException {
        if (!hasPermission(permission, targetUserId)) {
            throw new SecurityException("Caller does not have the required permissions for "
                    + "this user. Permissions required: {"
                    + permission
                    + ", "
                    + CROSS_USER_PERMISSIONS.get(permission)
                    + "}");
        }
    }
    /**
     * Return whether the calling process has been granted permission to query a device policy on
     * a specific user.
     *
     * @param permission The name of the permission being checked.
     * @param targetUserId The userId of the user which the caller needs permission to act on.
     * @throws SecurityException if the caller has not been granted the given permission,
     * the associatated cross-user permission if the caller's user is different to the target user
     * and if the user has not been granted {@link QUERY_ADMIN_POLICY}.
     */
    private void enforceCanQuery(String permission, int targetUserId) throws SecurityException {
        if (hasPermission(QUERY_ADMIN_POLICY)) {
            return;
        }
        enforcePermission(permission, targetUserId);
    }
    /**
     * Return whether the calling process has been granted permission to apply a device policy on
     * a specific user.
     *
     * @param permission The name of the permission being checked.
     * @param targetUserId The userId of the user which the caller needs permission to act on.
     */
    private boolean hasPermission(String permission, int targetUserId) {
        boolean hasPermission = hasPermission(permission);
        if (getCallerIdentity().getUserId() != targetUserId) {
            hasPermission = hasPermission
                    && hasPermission(CROSS_USER_PERMISSIONS.get(permission));
        }
        return hasPermission;
    }
    /**
     * Return whether the calling process has been granted the given permission.
     *
     * @param permission The name of the permission being checked.
     */
    private boolean hasPermission(String permission) {
        if (permission == null) {
            return true;
        }
        CallerIdentity caller = getCallerIdentity();
        // Check if the caller holds the permission
        if (mContext.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED) {
            return true;
        }
        // Check the permissions of DPCs
        if (isDefaultDeviceOwner(caller)) {
            return DPC_PERMISSIONS.get(DEFAULT_DEVICE_OWNER).contains(permission);
        }
        if (isFinancedDeviceOwner(caller)) {
            return DPC_PERMISSIONS.get(FINANCED_DEVICE_OWNER).contains(permission);
        }
        if (isProfileOwnerOfOrganizationOwnedDevice(caller)) {
            return DPC_PERMISSIONS.get(PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE).contains(
                    permission);
        }
        if (isProfileOwnerOnUser0(caller)) {
            return DPC_PERMISSIONS.get(PROFILE_OWNER_ON_USER_0).contains(permission);
        }
        if (isProfileOwner(caller)) {
            return DPC_PERMISSIONS.get(PROFILE_OWNER).contains(permission);
        }
        // Check the permission for the role-holder
        if (isDevicePolicyManagementRoleHolder(caller)) {
            return anyDpcHasPermission(permission, mContext.getUserId());
        }
        // Check if the caller is an active admin that uses a certain policy.
        if (ACTIVE_ADMIN_POLICIES.containsKey(permission)) {
            return getActiveAdminForCallerLocked(
                    null, ACTIVE_ADMIN_POLICIES.get(permission), false) != null;
        }
        return false;
    }
    /**
     * Returns whether there is a DPC on the given user that has been granted the given permission.
     *
     * @param permission The name of the permission being checked.
     * @param userId The id of the user to check.
     */
    private boolean anyDpcHasPermission(String permission, int userId) {
        if (mOwners.isDefaultDeviceOwnerUserId(userId)) {
            return DPC_PERMISSIONS.get(DEFAULT_DEVICE_OWNER).contains(permission);
        }
        if (mOwners.isFinancedDeviceOwnerUserId(userId)) {
            return DPC_PERMISSIONS.get(FINANCED_DEVICE_OWNER).contains(permission);
        }
        if (mOwners.isProfileOwnerOfOrganizationOwnedDevice(userId)) {
            return DPC_PERMISSIONS.get(PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE).contains(
                    permission);
        }
        if (userId == 0 && mOwners.hasProfileOwner(0)) {
            return DPC_PERMISSIONS.get(PROFILE_OWNER_ON_USER_0).contains(permission);
        }
        if (mOwners.hasProfileOwner(userId)) {
            return DPC_PERMISSIONS.get(PROFILE_OWNER).contains(permission);
        }
        return false;
    }
    // TODO(b/260560985): properly gate coexistence changes
    private boolean isCoexistenceEnabled(CallerIdentity caller) {
        return isCoexistenceFlagEnabled()
+18 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.server.devicepolicy;
import static android.app.admin.DevicePolicyManager.DEPRECATE_USERMANAGERINTERNAL_DEVICEPOLICY_DEFAULT;
import static android.app.admin.DevicePolicyManager.DEPRECATE_USERMANAGERINTERNAL_DEVICEPOLICY_FLAG;
import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_DEFAULT;
import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_FINANCED;

import static com.android.server.devicepolicy.DeviceStateCacheImpl.NO_DEVICE_OWNER;

@@ -455,6 +456,23 @@ class Owners {
        }
    }

    boolean isDefaultDeviceOwnerUserId(int userId) {
        synchronized (mData) {
            return mData.mDeviceOwner != null
                    && mData.mDeviceOwnerUserId == userId
                    && getDeviceOwnerType(getDeviceOwnerPackageName()) == DEVICE_OWNER_TYPE_DEFAULT;
        }
    }

    boolean isFinancedDeviceOwnerUserId(int userId) {
        synchronized (mData) {
            return mData.mDeviceOwner != null
                    && mData.mDeviceOwnerUserId == userId
                    && getDeviceOwnerType(getDeviceOwnerPackageName())
                        == DEVICE_OWNER_TYPE_FINANCED;
        }
    }

    boolean hasProfileOwner(int userId) {
        synchronized (mData) {
            return getProfileOwnerComponent(userId) != null;