From b3f22b48bbd4e4816212e596e3cb612457d48fe5 Mon Sep 17 00:00:00 2001 From: Svet Ganov Date: Tue, 12 May 2015 11:01:24 -0700 Subject: [PATCH] Runtime permissions for system components not revokable - framework Change-Id: I5b1d7bb1618ffa8d1231618ece47d0905c82f7bf --- api/system-current.txt | 3 +- .../android/content/pm/PackageManager.java | 13 +++++- .../server/pm/PackageManagerService.java | 46 ++++++++++++++----- .../android/server/pm/PermissionsState.java | 12 ++--- 4 files changed, 53 insertions(+), 21 deletions(-) diff --git a/api/system-current.txt b/api/system-current.txt index bc47229fba1b7..4bc8f827a6155 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -9631,6 +9631,7 @@ package android.content.pm { field public static final java.lang.String FEATURE_WIFI_DIRECT = "android.hardware.wifi.direct"; field public static final int FLAG_PERMISSION_POLICY_FIXED = 4; // 0x4 field public static final int FLAG_PERMISSION_REVOKE_ON_UPGRADE = 8; // 0x8 + field public static final int FLAG_PERMISSION_SYSTEM_FIXED = 16; // 0x10 field public static final int FLAG_PERMISSION_USER_FIXED = 2; // 0x2 field public static final int FLAG_PERMISSION_USER_SET = 1; // 0x1 field public static final int GET_ACTIVITIES = 1; // 0x1 @@ -9685,7 +9686,7 @@ package android.content.pm { field public static final int INSTALL_PARSE_FAILED_NO_CERTIFICATES = -103; // 0xffffff99 field public static final int INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION = -102; // 0xffffff9a field public static final int INSTALL_SUCCEEDED = 1; // 0x1 - field public static final int MASK_PERMISSION_FLAGS = 15; // 0xf + field public static final int MASK_PERMISSION_FLAGS = 255; // 0xff field public static final int MATCH_ALL = 131072; // 0x20000 field public static final int MATCH_DEFAULT_ONLY = 65536; // 0x10000 field public static final long MAXIMUM_VERIFICATION_TIMEOUT = 3600000L; // 0x36ee80L diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 6401fe63a73f8..f046af07ff1df 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -1930,6 +1930,14 @@ public abstract class PackageManager { @SystemApi public static final int FLAG_PERMISSION_REVOKE_ON_UPGRADE = 1 << 3; + /** + * Permission flag: The permission is set in its current state + * because the app is a component that is a part of the system. + * + * @hide + */ + @SystemApi + public static final int FLAG_PERMISSION_SYSTEM_FIXED = 1 << 4; /** * Mask for all permission flags. @@ -1937,7 +1945,7 @@ public abstract class PackageManager { * @hide */ @SystemApi - public static final int MASK_PERMISSION_FLAGS = 0xF; + public static final int MASK_PERMISSION_FLAGS = 0xFF; /** * Retrieve overall information about an application package that is @@ -2435,7 +2443,8 @@ public abstract class PackageManager { @IntDef({FLAG_PERMISSION_USER_SET, FLAG_PERMISSION_USER_FIXED, FLAG_PERMISSION_POLICY_FIXED, - FLAG_PERMISSION_REVOKE_ON_UPGRADE}) + FLAG_PERMISSION_REVOKE_ON_UPGRADE, + FLAG_PERMISSION_SYSTEM_FIXED}) @Retention(RetentionPolicy.SOURCE) public @interface PermissionFlags {} diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 477af7262c552..6f4820946257f 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -55,6 +55,7 @@ import static android.content.pm.PackageManager.MOVE_FAILED_INTERNAL_ERROR; import static android.content.pm.PackageManager.MOVE_FAILED_OPERATION_PENDING; import static android.content.pm.PackageManager.MOVE_FAILED_SYSTEM_PACKAGE; import static android.content.pm.PackageParser.isApkFile; +import static android.os.Process.FIRST_APPLICATION_UID; import static android.os.Process.PACKAGE_INFO_GID; import static android.os.Process.SYSTEM_UID; import static android.system.OsConstants.O_CREAT; @@ -3142,14 +3143,6 @@ public class PackageManagerService extends IPackageManager.Stub { } } - private static void enforceOnlySystemUpdatesPermissionPolicyFlags(int flagMask, int flagValues) { - if (((flagMask & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0 - || (flagValues & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0) - && getCallingUid() != Process.SYSTEM_UID) { - throw new SecurityException("Only the system can modify policy flags"); - } - } - @Override public void grantRuntimePermission(String packageName, String name, int userId) { if (!sUserManager.exists(userId)) { @@ -3302,7 +3295,15 @@ public class PackageManagerService extends IPackageManager.Stub { enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false, "updatePermissionFlags"); - enforceOnlySystemUpdatesPermissionPolicyFlags(flagMask, flagValues); + // Only the system can change policy flags. + if (getCallingUid() != Process.SYSTEM_UID) { + flagMask &= ~PackageManager.FLAG_PERMISSION_POLICY_FIXED; + flagValues &= ~PackageManager.FLAG_PERMISSION_POLICY_FIXED; + } + + // Only the package manager can change system flags. + flagMask &= ~PackageManager.FLAG_PERMISSION_SYSTEM_FIXED; + flagValues &= ~PackageManager.FLAG_PERMISSION_SYSTEM_FIXED; synchronized (mPackages) { final PackageParser.Package pkg = mPackages.get(packageName); @@ -3322,6 +3323,12 @@ public class PackageManagerService extends IPackageManager.Stub { PermissionsState permissionsState = sb.getPermissionsState(); + // Only the package manager can change flags for system component permissions. + final int flags = permissionsState.getPermissionFlags(bp.name, userId); + if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0) { + return; + } + if (permissionsState.updatePermissionFlags(bp, userId, flagMask, flagValues)) { // Install and runtime permissions are stored in different places, // so figure out what permission changed and persist the change. @@ -7757,9 +7764,14 @@ public class PackageManagerService extends IPackageManager.Stub { changedRuntimePermissionUserIds = ArrayUtils.appendInt( changedRuntimePermissionUserIds, userId); } else { + // System components not only get the permissions but + // they are also fixed, so nothing can change that. + final int newFlags = !isSystemComponentOrPersistentPrivApp(pkg) + ? flags + : flags | PackageManager.FLAG_PERMISSION_SYSTEM_FIXED; // Propagate the permission flags. permissionsState.updatePermissionFlags(bp, userId, - flags, flags); + newFlags, newFlags); } } } @@ -7782,9 +7794,14 @@ public class PackageManagerService extends IPackageManager.Stub { for (int userId : upgradeUserIds) { if (permissionsState.grantRuntimePermission(bp, userId) != PermissionsState.PERMISSION_OPERATION_FAILURE) { + // System components not only get the permissions but + // they are also fixed so nothing can change that. + final int newFlags = !isSystemComponentOrPersistentPrivApp(pkg) + ? flags + : flags | PackageManager.FLAG_PERMISSION_SYSTEM_FIXED; // Transfer the permission flags. permissionsState.updatePermissionFlags(bp, userId, - flags, flags); + newFlags, newFlags); // If we granted the permission, we have to write. changedRuntimePermissionUserIds = ArrayUtils.appendInt( changedRuntimePermissionUserIds, userId); @@ -11666,6 +11683,13 @@ public class PackageManagerService extends IPackageManager.Stub { } } + private boolean isSystemComponentOrPersistentPrivApp(PackageParser.Package pkg) { + return UserHandle.getAppId(pkg.applicationInfo.uid) < FIRST_APPLICATION_UID + || ((pkg.applicationInfo.privateFlags + & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0 + && (pkg.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0); + } + private static boolean isMultiArch(PackageSetting ps) { return (ps.pkgFlags & ApplicationInfo.FLAG_MULTIARCH) != 0; } diff --git a/services/core/java/com/android/server/pm/PermissionsState.java b/services/core/java/com/android/server/pm/PermissionsState.java index 171a50db9e508..8942325c799f5 100644 --- a/services/core/java/com/android/server/pm/PermissionsState.java +++ b/services/core/java/com/android/server/pm/PermissionsState.java @@ -49,14 +49,14 @@ import java.util.Set; */ public final class PermissionsState { + /** The permission operation failed. */ + public static final int PERMISSION_OPERATION_FAILURE = -1; + /** The permission operation succeeded and no gids changed. */ - public static final int PERMISSION_OPERATION_SUCCESS = 1; + public static final int PERMISSION_OPERATION_SUCCESS = 0; /** The permission operation succeeded and gids changed. */ - public static final int PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED = 2; - - /** The permission operation failed. */ - public static final int PERMISSION_OPERATION_FAILURE = 3; + public static final int PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED = 1; private static final int[] NO_GIDS = {}; @@ -167,8 +167,6 @@ public final class PermissionsState { * @return The operation result which is either {@link #PERMISSION_OPERATION_SUCCESS}, * or {@link #PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED}, or {@link * #PERMISSION_OPERATION_FAILURE}. - * - * @see android.content.pm.PackageManager.PermissionFlags */ public int revokeRuntimePermission(BasePermission permission, int userId) { enforceValidUserId(userId);