OSDN Git Service

DO NOT MERGE (N) Revoke permision when group changed
authorPhilip P. Moltmann <moltmann@google.com>
Thu, 12 Apr 2018 20:48:13 +0000 (13:48 -0700)
committerJP Sugarbroad <jpsugar@google.com>
Tue, 8 May 2018 21:04:01 +0000 (14:04 -0700)
If a run time permission of a group is already granted we grant the
other permission of the group automatically when requested.

Hence if an already granted permission changed its group during an
update suddenly permission of a potentially not approved group will
get auto-granted.

This is undesirable, hence we revoke the permission during the update
process.

Test: atest android.permission.cts.PermissionGroupChange
Bug: 72710897
Change-Id: Ib2165d1ae53b80455ebe02e07775853e37a2e339
(cherry picked from commit 5aee5696276650e992c813a778e4e7b6e723f331)

services/core/java/com/android/server/pm/PackageManagerService.java

index b6a9940..7095a76 100644 (file)
@@ -165,6 +165,7 @@ import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.hardware.display.DisplayManager;
 import android.net.Uri;
+import android.os.AsyncTask;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
@@ -4212,6 +4213,81 @@ public class PackageManagerService extends IPackageManager.Stub {
         killUid(appId, userId, KILL_APP_REASON_PERMISSIONS_REVOKED);
     }
 
+    /**
+     * We might auto-grant permissions if any permission of the group is already granted. Hence if
+     * the group of a granted permission changes we need to revoke it to avoid having permissions of
+     * the new group auto-granted.
+     *
+     * @param newPackage The new package that was installed
+     * @param oldPackage The old package that was updated
+     * @param allPackageNames All package names
+     */
+    private void revokeRuntimePermissionsIfGroupChanged(
+            PackageParser.Package newPackage,
+            PackageParser.Package oldPackage,
+            ArrayList<String> allPackageNames) {
+        final int numOldPackagePermissions = oldPackage.permissions.size();
+        final ArrayMap<String, String> oldPermissionNameToGroupName
+                = new ArrayMap<>(numOldPackagePermissions);
+
+        for (int i = 0; i < numOldPackagePermissions; i++) {
+            final PackageParser.Permission permission = oldPackage.permissions.get(i);
+
+            if (permission.group != null) {
+                oldPermissionNameToGroupName.put(permission.info.name,
+                        permission.group.info.name);
+            }
+        }
+
+        final int numNewPackagePermissions = newPackage.permissions.size();
+        for (int newPermissionNum = 0; newPermissionNum < numNewPackagePermissions;
+                newPermissionNum++) {
+            final PackageParser.Permission newPermission =
+                    newPackage.permissions.get(newPermissionNum);
+            final int newProtection = newPermission.info.protectionLevel;
+
+            if ((newProtection & PermissionInfo.PROTECTION_DANGEROUS) != 0) {
+                final String permissionName = newPermission.info.name;
+                final String newPermissionGroupName =
+                        newPermission.group == null ? null : newPermission.group.info.name;
+                final String oldPermissionGroupName = oldPermissionNameToGroupName.get(
+                        permissionName);
+
+                if (newPermissionGroupName != null
+                        && !newPermissionGroupName.equals(oldPermissionGroupName)) {
+                    final List<UserInfo> users = mContext.getSystemService(UserManager.class)
+                            .getUsers();
+
+                    final int numUsers = users.size();
+                    for (int userNum = 0; userNum < numUsers; userNum++) {
+                        final int userId = users.get(userNum).id;
+                        final int numPackages = allPackageNames.size();
+                        for (int packageNum = 0; packageNum < numPackages; packageNum++) {
+                            final String packageName = allPackageNames.get(packageNum);
+
+                            if (checkPermission(permissionName, packageName, userId)
+                                    == PackageManager.PERMISSION_GRANTED) {
+                                EventLog.writeEvent(0x534e4554, "72710897",
+                                        newPackage.applicationInfo.uid,
+                                        "Revoking permission", permissionName, "from package",
+                                        packageName, "as the group changed from",
+                                        oldPermissionGroupName, "to", newPermissionGroupName);
+
+                                try {
+                                    revokeRuntimePermission(packageName, permissionName, userId);
+                                } catch (IllegalArgumentException e) {
+                                    Slog.e(TAG, "Could not revoke " + permissionName + " from "
+                                            + packageName, e);
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+
     @Override
     public void resetRuntimePermissions() {
         mContext.enforceCallingOrSelfPermission(
@@ -8113,6 +8189,8 @@ public class PackageManagerService extends IPackageManager.Stub {
                 Log.d(TAG, "Scanning package " + pkg.packageName);
         }
 
+        final PackageParser.Package oldPkg;
+
         synchronized (mPackages) {
             if (mPackages.containsKey(pkg.packageName)
                     || mSharedLibraries.containsKey(pkg.packageName)) {
@@ -8121,6 +8199,13 @@ public class PackageManagerService extends IPackageManager.Stub {
                                 + " already installed.  Skipping duplicate.");
             }
 
+            final PackageSetting oldPkgSetting = mSettings.peekPackageLPr(pkg.packageName);
+            if (oldPkgSetting == null) {
+               oldPkg = null;
+            } else {
+               oldPkg = oldPkgSetting.pkg;
+            }
+
             // If we're only installing presumed-existing packages, require that the
             // scanned APK is both already known and at the path previously established
             // for it.  Previously unknown packages we pick up normally, but if we have an
@@ -8993,6 +9078,24 @@ public class PackageManagerService extends IPackageManager.Stub {
                 // This is a regular package, with one or more known overlay packages.
                 createIdmapsForPackageLI(pkg);
             }
+
+            if (oldPkg != null) {
+                // We need to call revokeRuntimePermissionsIfGroupChanged async as permission
+                // revokation from this method might need to kill apps which need the
+                // mPackages lock on a different thread. This would dead lock.
+                //
+                // Hence create a copy of all package names and pass it into
+                // revokeRuntimePermissionsIfGroupChanged. Only for those permissions might get
+                // revoked. If a new package is added before the async code runs the permission
+                // won't be granted yet, hence new packages are no problem.
+                final ArrayList<String> allPackageNames = new ArrayList<>(mPackages.keySet());
+
+                AsyncTask.execute(new Runnable() {
+                    public void run() {
+                        revokeRuntimePermissionsIfGroupChanged(pkg, oldPkg, allPackageNames);
+                    }
+                });
+            }
         }
 
         Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);