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

Commit a3968751 authored by Hai Zhang's avatar Hai Zhang
Browse files

Add role as a new permission protection flag.

Permissions with the role protection flag will be able to be managed
by role via grant/revokeRuntimePermission(), similar to development
permissions but only manageable by role.

Also fixed a bug that PermissionController can get any signature
permission.

Bug: 158736025
Test: presubmit
Change-Id: I49603cee91466a791be66055a922ba1a8bd08d4e
parent c43d935c
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -2291,6 +2291,7 @@ package android.content.pm {
    field public static final int PROTECTION_FLAG_OEM = 16384; // 0x4000
    field public static final int PROTECTION_FLAG_RECENTS = 33554432; // 0x2000000
    field public static final int PROTECTION_FLAG_RETAIL_DEMO = 16777216; // 0x1000000
    field public static final int PROTECTION_FLAG_ROLE = 67108864; // 0x4000000
    field public static final int PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER = 65536; // 0x10000
    field public static final int PROTECTION_FLAG_WELLBEING = 131072; // 0x20000
    field @Nullable public final String backgroundPermission;
+13 −0
Original line number Diff line number Diff line
@@ -261,6 +261,15 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable {
    @SystemApi
    public static final int PROTECTION_FLAG_RECENTS = 0x2000000;

    /**
     * Additional flag for {@link #protectionLevel}, corresponding to the <code>role</code> value of
     * {@link android.R.attr#protectionLevel}.
     *
     * @hide
     */
    @SystemApi
    public static final int PROTECTION_FLAG_ROLE = 0x4000000;

    /** @hide */
    @IntDef(flag = true, prefix = { "PROTECTION_FLAG_" }, value = {
            PROTECTION_FLAG_PRIVILEGED,
@@ -285,6 +294,7 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable {
            PROTECTION_FLAG_COMPANION,
            PROTECTION_FLAG_RETAIL_DEMO,
            PROTECTION_FLAG_RECENTS,
            PROTECTION_FLAG_ROLE,
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface ProtectionFlags {}
@@ -546,6 +556,9 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable {
        if ((level & PermissionInfo.PROTECTION_FLAG_RECENTS) != 0) {
            protLevel.append("|recents");
        }
        if ((level & PermissionInfo.PROTECTION_FLAG_ROLE) != 0) {
            protLevel.append("|role");
        }
        return protLevel.toString();
    }

+2 −0
Original line number Diff line number Diff line
@@ -306,6 +306,8 @@
        <!-- Additional flag from base permission type: this permission will be granted to the
             recents app. -->
        <flag name="recents" value="0x2000000" />
        <!-- Additional flag from base permission type: this permission is managed by role. -->
        <flag name="role" value="0x4000000" />
    </attr>

    <!-- Flags indicating more context for a permission group. -->
+4 −0
Original line number Diff line number Diff line
@@ -335,6 +335,10 @@ public final class Permission {
        return (mPermissionInfo.protectionLevel & PermissionInfo.PROTECTION_FLAG_RECENTS) != 0;
    }

    public boolean isRole() {
        return (mPermissionInfo.protectionLevel & PermissionInfo.PROTECTION_FLAG_ROLE) != 0;
    }

    public void transfer(@NonNull String oldPackageName, @NonNull String newPackageName) {
        if (!oldPackageName.equals(mPermissionInfo.packageName)) {
            return;
+56 −17
Original line number Diff line number Diff line
@@ -160,6 +160,7 @@ import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
@@ -1550,18 +1551,24 @@ public class PermissionManagerService extends IPermissionManager.Stub {
            throw new IllegalArgumentException("Unknown package: " + packageName);
        }

        final boolean isRolePermission;
        final boolean isSoftRestrictedPermission;
        synchronized (mLock) {
            final Permission permission = mRegistry.getPermission(permName);
            isSoftRestrictedPermission = permission != null && permission.isSoftRestricted();
            if (permission == null) {
                throw new IllegalArgumentException("Unknown permission: " + permName);
            }
            isRolePermission = permission.isRole();
            isSoftRestrictedPermission = permission.isSoftRestricted();
        }
        final boolean mayGrantRolePermission = isRolePermission
                && mayManageRolePermission(callingUid);
        final boolean mayGrantSoftRestrictedPermission = isSoftRestrictedPermission
                && SoftRestrictedPermissionPolicy.forPermission(mContext,
                        pkg.toAppInfoWithoutState(), pkg, UserHandle.of(userId), permName)
                        .mayGrantPermission();

        final boolean isRuntimePermission;
        final boolean isDevelopmentPermission;
        final boolean permissionHasGids;
        synchronized (mLock) {
            final Permission bp = mRegistry.getPermission(permName);
@@ -1570,9 +1577,14 @@ public class PermissionManagerService extends IPermissionManager.Stub {
            }

            isRuntimePermission = bp.isRuntime();
            isDevelopmentPermission = bp.isDevelopment();
            permissionHasGids = bp.hasGids();
            if (!(isRuntimePermission || isDevelopmentPermission)) {
            if (isRuntimePermission || bp.isDevelopment()) {
                // Good.
            } else if (bp.isRole()) {
                if (!mayGrantRolePermission) {
                    throw new SecurityException("Permission " + permName + " is managed by role");
                }
            } else {
                throw new SecurityException("Permission " + permName + " requested by "
                        + pkg.getPackageName() + " is not a changeable permission type");
            }
@@ -1623,7 +1635,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
                return;
            }

            if (bp.isDevelopment()) {
            if (bp.isDevelopment() || bp.isRole()) {
                // Development permissions must be handled specially, since they are not
                // normal runtime permissions.  For now they apply to all users.
                // TODO(zhanghai): We are breaking the behavior above by making all permission state
@@ -1654,10 +1666,10 @@ public class PermissionManagerService extends IPermissionManager.Stub {

        final int uid = UserHandle.getUid(userId, pkg.getUid());
        if (callback != null) {
            if (isDevelopmentPermission) {
                callback.onInstallPermissionGranted();
            } else {
            if (isRuntimePermission) {
                callback.onPermissionGranted(uid, userId);
            } else {
                callback.onInstallPermissionGranted();
            }
            if (permissionHasGids) {
                callback.onGidsChanged(UserHandle.getAppId(pkg.getUid()), userId);
@@ -1715,8 +1727,18 @@ public class PermissionManagerService extends IPermissionManager.Stub {
            throw new IllegalArgumentException("Unknown package: " + packageName);
        }

        final boolean isRolePermission;
        synchronized (mLock) {
            final Permission permission = mRegistry.getPermission(permName);
            if (permission == null) {
                throw new IllegalArgumentException("Unknown permission: " + permName);
            }
            isRolePermission = permission.isRole();
        }
        final boolean mayRevokeRolePermission = isRolePermission
                && mayManageRolePermission(callingUid);

        final boolean isRuntimePermission;
        final boolean isDevelopmentPermission;
        synchronized (mLock) {
            final Permission bp = mRegistry.getPermission(permName);
            if (bp == null) {
@@ -1724,8 +1746,13 @@ public class PermissionManagerService extends IPermissionManager.Stub {
            }

            isRuntimePermission = bp.isRuntime();
            isDevelopmentPermission = bp.isDevelopment();
            if (!(isRuntimePermission || isDevelopmentPermission)) {
            if (isRuntimePermission || bp.isDevelopment()) {
                // Good.
            } else if (bp.isRole()) {
                if (!mayRevokeRolePermission) {
                    throw new SecurityException("Permission " + permName + " is managed by role");
                }
            } else {
                throw new SecurityException("Permission " + permName + " requested by "
                        + pkg.getPackageName() + " is not a changeable permission type");
            }
@@ -1777,11 +1804,11 @@ public class PermissionManagerService extends IPermissionManager.Stub {
        }

        if (callback != null) {
            if (isDevelopmentPermission) {
                mDefaultPermissionCallback.onInstallPermissionRevoked();
            } else {
            if (isRuntimePermission) {
                callback.onPermissionRevoked(UserHandle.getUid(userId, pkg.getUid()), userId,
                        reason);
            } else {
                mDefaultPermissionCallback.onInstallPermissionRevoked();
            }
        }

@@ -1790,6 +1817,17 @@ public class PermissionManagerService extends IPermissionManager.Stub {
        }
    }

    private boolean mayManageRolePermission(int uid) {
        final PackageManager packageManager = mContext.getPackageManager();
        final String[] packageNames = packageManager.getPackagesForUid(uid);
        if (packageNames == null) {
            return false;
        }
        final String permissionControllerPackageName =
                packageManager.getPermissionControllerPackageName();
        return Arrays.asList(packageNames).contains(permissionControllerPackageName);
    }

    @Override
    public void resetRuntimePermissions() {
        mContext.enforceCallingOrSelfPermission(
@@ -2906,7 +2944,8 @@ public class PermissionManagerService extends IPermissionManager.Stub {

                    if ((bp.isNormal() && shouldGrantNormalPermission) || (bp.isSignature()
                            && (shouldGrantSignaturePermission.contains(permName)
                            || (bp.isDevelopment() && origState.isPermissionGranted(permName))))) {
                            || ((bp.isDevelopment() || bp.isRole())
                            && origState.isPermissionGranted(permName))))) {
                        // Grant an install permission.
                        if (uidState.grantPermission(bp)) {
                            changedInstallPermission = true;
@@ -3472,12 +3511,12 @@ public class PermissionManagerService extends IPermissionManager.Stub {
        //                  need a separate flag anymore. Hence we need to check which
        //                  permissions are needed by the permission controller
        if (!allowed && bp.isInstaller()
                && ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames(
                && (ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames(
                        PackageManagerInternal.PACKAGE_INSTALLER, UserHandle.USER_SYSTEM),
                pkg.getPackageName()) || ArrayUtils.contains(
                        mPackageManagerInt.getKnownPackageNames(
                                PackageManagerInternal.PACKAGE_PERMISSION_CONTROLLER,
                UserHandle.USER_SYSTEM), pkg.getPackageName())) {
                UserHandle.USER_SYSTEM), pkg.getPackageName()))) {
            // If this permission is to be granted to the system installer and
            // this app is an installer, then it gets the permission.
            allowed = true;