From 4a5f4a2bc7a379a5b4174f78fefeefe745e6cd37 Mon Sep 17 00:00:00 2001 From: Svetoslav Date: Tue, 7 Jul 2015 18:18:15 -0700 Subject: [PATCH] Fix reset permissions on clear data and package uninstall. If the user clears data for an app we reset the permission but only the changes made by the user. We do not modify syste or policy flags and also ensure the permission that were granted by default are granted after the data wipe. This is the same as starting with a clean slate. If the package whose data is cleared is a part of a shared user we resent to initial state only the permissions that the cleared package contributed. Hence, if another package also declared the permission as used we do not clear the permission state as it is still in use. When a package is deleted for a user but still present for another user we reset its permissions to their inital state follwoing above described strategy. Lastly when a preinstalled package wtih an upgrade is diabled (triggers upgrade uninstall) and this package is a part of a shared user, we do not drop permission state (grants and flags) for permissions used by the shadowed system package. This ensures that we do not drop runtime permission state (such state is default grants and user changes).i bug:22248525 Change-Id: I3a3007476d2cb9f4ff824e1e137a6e1a4d04408b --- .../android/content/pm/PackageManager.java | 12 +- .../server/pm/PackageManagerService.java | 169 ++++++++++++------ .../java/com/android/server/pm/Settings.java | 55 +++--- 3 files changed, 156 insertions(+), 80 deletions(-) diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 49386f9e04803..62c2e8cd33aae 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -4627,12 +4627,12 @@ public abstract class PackageManager { /** {@hide} */ public static String permissionFlagToString(int flag) { switch (flag) { - case FLAG_PERMISSION_GRANTED_BY_DEFAULT: return "FLAG_PERMISSION_GRANTED_BY_DEFAULT"; - case FLAG_PERMISSION_POLICY_FIXED: return "FLAG_PERMISSION_POLICY_FIXED"; - case FLAG_PERMISSION_SYSTEM_FIXED: return "FLAG_PERMISSION_SYSTEM_FIXED"; - case FLAG_PERMISSION_USER_SET: return "FLAG_PERMISSION_USER_SET"; - case FLAG_PERMISSION_REVOKE_ON_UPGRADE: return "FLAG_PERMISSION_REVOKE_ON_UPGRADE"; - case FLAG_PERMISSION_USER_FIXED: return "FLAG_PERMISSION_USER_FIXED"; + case FLAG_PERMISSION_GRANTED_BY_DEFAULT: return "GRANTED_BY_DEFAULT"; + case FLAG_PERMISSION_POLICY_FIXED: return "POLICY_FIXED"; + case FLAG_PERMISSION_SYSTEM_FIXED: return "SYSTEM_FIXED"; + case FLAG_PERMISSION_USER_SET: return "USER_SET"; + case FLAG_PERMISSION_REVOKE_ON_UPGRADE: return "REVOKE_ON_UPGRADE"; + case FLAG_PERMISSION_USER_FIXED: return "USER_FIXED"; default: return Integer.toString(flag); } } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 124214c84b5f2..ed20345085759 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -25,6 +25,12 @@ import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED; +import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT; +import static android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED; +import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE; +import static android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED; +import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED; +import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET; import static android.content.pm.PackageManager.INSTALL_EXTERNAL; import static android.content.pm.PackageManager.INSTALL_FAILED_ALREADY_EXISTS; import static android.content.pm.PackageManager.INSTALL_FAILED_CONFLICTING_PROVIDER; @@ -72,6 +78,9 @@ import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet; import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets; import static com.android.server.pm.InstructionSets.getPreferredInstructionSet; import static com.android.server.pm.InstructionSets.getPrimaryInstructionSet; +import static com.android.server.pm.PermissionsState.PERMISSION_OPERATION_FAILURE; +import static com.android.server.pm.PermissionsState.PERMISSION_OPERATION_SUCCESS; +import static com.android.server.pm.PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED; import android.Manifest; import android.app.ActivityManager; @@ -12665,7 +12674,7 @@ public class PackageManagerService extends IPackageManager.Stub { KILL_APP_REASON_GIDS_CHANGED); } }); - break; + break; } } } @@ -12781,8 +12790,14 @@ public class PackageManagerService extends IPackageManager.Stub { // writer synchronized (mPackages) { PackageSetting ps = mSettings.mPackages.get(newPkg.packageName); + + // Propagate the permissions state as we do want to drop on the floor + // runtime permissions. The update permissions method below will take + // care of removing obsolete permissions and grant install permissions. + ps.getPermissionsState().copyFrom(disabledPs.getPermissionsState()); updatePermissionsLPw(newPkg.packageName, newPkg, UPDATE_PERMISSIONS_ALL | UPDATE_PERMISSIONS_REPLACE_PKG); + if (applyUserRestrictions) { if (DEBUG_REMOVE) { Slog.d(TAG, "Propagating install state across reinstall"); @@ -12943,8 +12958,7 @@ public class PackageManagerService extends IPackageManager.Stub { if (clearPackagePreferredActivitiesLPw(packageName, removeUser)) { scheduleWritePackageRestrictionsLocked(removeUser); } - revokeRuntimePermissionsAndClearAllFlagsLocked(ps.getPermissionsState(), - removeUser); + resetUserChangesToRuntimePermissionsAndFlagsLocked(ps, removeUser); } return true; } @@ -13105,8 +13119,7 @@ public class PackageManagerService extends IPackageManager.Stub { } PackageSetting ps = (PackageSetting) pkg.mExtras; - PermissionsState permissionsState = ps.getPermissionsState(); - revokeRuntimePermissionsAndClearUserSetFlagsLocked(permissionsState, userId); + resetUserChangesToRuntimePermissionsAndFlagsLocked(ps, userId); } // Always delete data directories for package, even if we found no other @@ -13137,66 +13150,118 @@ public class PackageManagerService extends IPackageManager.Stub { return true; } - /** - * Revokes granted runtime permissions and clears resettable flags - * which are flags that can be set by a user interaction. + * Reverts user permission state changes (permissions and flags). * - * @param permissionsState The permission state to reset. + * @param ps The package for which to reset. * @param userId The device user for which to do a reset. */ - private void revokeRuntimePermissionsAndClearUserSetFlagsLocked( - PermissionsState permissionsState, int userId) { - final int userSetFlags = PackageManager.FLAG_PERMISSION_USER_SET - | PackageManager.FLAG_PERMISSION_USER_FIXED - | PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE; + private void resetUserChangesToRuntimePermissionsAndFlagsLocked( + final PackageSetting ps, final int userId) { + if (ps.pkg == null) { + return; + } - revokeRuntimePermissionsAndClearFlagsLocked(permissionsState, userId, userSetFlags); - } + final int userSettableFlags = FLAG_PERMISSION_USER_SET + | FLAG_PERMISSION_USER_FIXED + | FLAG_PERMISSION_REVOKE_ON_UPGRADE; - /** - * Revokes granted runtime permissions and clears all flags. - * - * @param permissionsState The permission state to reset. - * @param userId The device user for which to do a reset. - */ - private void revokeRuntimePermissionsAndClearAllFlagsLocked( - PermissionsState permissionsState, int userId) { - revokeRuntimePermissionsAndClearFlagsLocked(permissionsState, userId, - PackageManager.MASK_PERMISSION_FLAGS); - } + final int policyOrSystemFlags = FLAG_PERMISSION_SYSTEM_FIXED + | FLAG_PERMISSION_POLICY_FIXED; - /** - * Revokes granted runtime permissions and clears certain flags. - * - * @param permissionsState The permission state to reset. - * @param userId The device user for which to do a reset. - * @param flags The flags that is going to be reset. - */ - private void revokeRuntimePermissionsAndClearFlagsLocked( - PermissionsState permissionsState, final int userId, int flags) { - boolean needsWrite = false; + boolean writeInstallPermissions = false; + boolean writeRuntimePermissions = false; - for (PermissionState state : permissionsState.getRuntimePermissionStates(userId)) { - BasePermission bp = mSettings.mPermissions.get(state.getName()); - if (bp != null) { - permissionsState.revokeRuntimePermission(bp, userId); - permissionsState.updatePermissionFlags(bp, userId, flags, 0); - needsWrite = true; + final int permissionCount = ps.pkg.requestedPermissions.size(); + for (int i = 0; i < permissionCount; i++) { + String permission = ps.pkg.requestedPermissions.get(i); + + BasePermission bp = mSettings.mPermissions.get(permission); + if (bp == null) { + continue; + } + + // If shared user we just reset the state to which only this app contributed. + if (ps.sharedUser != null) { + boolean used = false; + final int packageCount = ps.sharedUser.packages.size(); + for (int j = 0; j < packageCount; j++) { + PackageSetting pkg = ps.sharedUser.packages.valueAt(j); + if (pkg.pkg != null && !pkg.pkg.packageName.equals(ps.pkg.packageName) + && pkg.pkg.requestedPermissions.contains(permission)) { + used = true; + break; + } + } + if (used) { + continue; + } + } + + PermissionsState permissionsState = ps.getPermissionsState(); + + final int oldFlags = permissionsState.getPermissionFlags(bp.name, userId); + + // Always clear the user settable flags. + final boolean hasInstallState = permissionsState.getInstallPermissionState( + bp.name) != null; + if (permissionsState.updatePermissionFlags(bp, userId, userSettableFlags, 0)) { + if (hasInstallState) { + writeInstallPermissions = true; + } else { + writeRuntimePermissions = true; + } + } + + // Below is only runtime permission handling. + if (!bp.isRuntime()) { + continue; + } + + // Never clobber system or policy. + if ((oldFlags & policyOrSystemFlags) != 0) { + continue; + } + + // If this permission was granted by default, make sure it is. + if ((oldFlags & FLAG_PERMISSION_GRANTED_BY_DEFAULT) != 0) { + if (permissionsState.grantRuntimePermission(bp, userId) + != PERMISSION_OPERATION_FAILURE) { + writeRuntimePermissions = true; + } + } else { + // Otherwise, reset the permission. + final int revokeResult = permissionsState.revokeRuntimePermission(bp, userId); + switch (revokeResult) { + case PERMISSION_OPERATION_SUCCESS: { + writeRuntimePermissions = true; + } break; + + case PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED: { + writeRuntimePermissions = true; + // If gids changed for this user, kill all affected packages. + mHandler.post(new Runnable() { + @Override + public void run() { + // This has to happen with no lock held. + killSettingPackagesForUser(ps, userId, + KILL_APP_REASON_GIDS_CHANGED); + } + }); + } break; + } } } - // Ensure default permissions are never cleared. - mHandler.post(new Runnable() { - @Override - public void run() { - mDefaultPermissionPolicy.grantDefaultPermissions(userId); - } - }); - - if (needsWrite) { + // Synchronously write as we are taking permissions away. + if (writeRuntimePermissions) { mSettings.writeRuntimePermissionsForUserLPr(userId, true); } + + // Synchronously write as we are taking permissions away. + if (writeInstallPermissions) { + mSettings.writeLPr(); + } } /** diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 4e85e39258632..bdcd714647210 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -824,14 +824,8 @@ final class Settings { continue; } - // If no user has the permission, nothing to remove. - if (!sus.getPermissionsState().hasPermission(bp.name, userId)) { - continue; - } - - boolean used = false; - // Check if another package in the shared user needs the permission. + boolean used = false; for (PackageSetting pkg : sus.packages) { if (pkg.pkg != null && !pkg.pkg.packageName.equals(deletedPs.pkg.packageName) @@ -840,26 +834,43 @@ final class Settings { break; } } + if (used) { + continue; + } - if (!used) { - PermissionsState permissionsState = sus.getPermissionsState(); + PermissionsState permissionsState = sus.getPermissionsState(); + PackageSetting disabledPs = getDisabledSystemPkgLPr(deletedPs.pkg.packageName); - // Try to revoke as an install permission which is for all users. - // The package is gone - no need to keep flags for applying policy. - permissionsState.updatePermissionFlags(bp, userId, - PackageManager.MASK_PERMISSION_FLAGS, 0); - - if (permissionsState.revokeInstallPermission(bp) == - PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED) { - return UserHandle.USER_ALL; + // If the package is shadowing is a disabled system package, + // do not drop permissions that the shadowed package requests. + if (disabledPs != null) { + boolean reqByDisabledSysPkg = false; + for (String permission : disabledPs.pkg.requestedPermissions) { + if (permission.equals(eachPerm)) { + reqByDisabledSysPkg = true; + break; + } } - - // Try to revoke as an install permission which is per user. - if (permissionsState.revokeRuntimePermission(bp, userId) == - PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED) { - return userId; + if (reqByDisabledSysPkg) { + continue; } } + + // Try to revoke as an install permission which is for all users. + // The package is gone - no need to keep flags for applying policy. + permissionsState.updatePermissionFlags(bp, userId, + PackageManager.MASK_PERMISSION_FLAGS, 0); + + if (permissionsState.revokeInstallPermission(bp) == + PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED) { + return UserHandle.USER_ALL; + } + + // Try to revoke as an install permission which is per user. + if (permissionsState.revokeRuntimePermission(bp, userId) == + PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED) { + return userId; + } } return UserHandle.USER_NULL;