OSDN Git Service

DO NOT MERGE: Reduce shell power over user management.
authorSudheer Shanka <sudheersai@google.com>
Thu, 9 Jun 2016 00:13:24 +0000 (17:13 -0700)
committerSudheer Shanka <sudheersai@google.com>
Tue, 12 Jul 2016 01:59:08 +0000 (01:59 +0000)
Remove MANAGE_USERS permission from shell and whitelist it for
some specific functionality.

Bug: 29189712
Change-Id: Ifb37448c091af91991964511e3efb1bb4dea1ff3

core/res/AndroidManifest.xml
packages/Shell/AndroidManifest.xml
services/core/java/com/android/server/pm/UserManagerService.java

index baa4e24..4af1d31 100644 (file)
         android:label="@string/permlab_manageUsers"
         android:description="@string/permdesc_manageUsers" />
 
+    <!-- @hide Allows an application to create, remove users and get the list of
+         users on the device. Applications holding this permission can only create restricted,
+         guest, and managed users. For creating other kind of users,
+         {@link android.Manifest.permission#MANAGE_USERS} is needed.
+         This permission is not available to third party applications. -->
+    <permission android:name="android.permission.CREATE_USERS"
+        android:protectionLevel="signature" />
+
     <!-- Allows an application to get full detailed information about
          recently running tasks, with full fidelity to the real state.
          @hide -->
index 3c44245..3eb06da 100644 (file)
@@ -84,7 +84,7 @@
     <uses-permission android:name="android.permission.WRITE_MEDIA_STORAGE" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
-    <uses-permission android:name="android.permission.MANAGE_USERS" />
+    <uses-permission android:name="android.permission.CREATE_USERS" />
     <uses-permission android:name="android.permission.MANAGE_DEVICE_ADMINS" />
     <uses-permission android:name="android.permission.BLUETOOTH_STACK" />
     <uses-permission android:name="android.permission.GET_ACCOUNTS" />
index d484b8f..454723c 100644 (file)
@@ -117,6 +117,11 @@ public class UserManagerService extends IUserManager.Stub {
     private static final String RESTRICTIONS_FILE_PREFIX = "res_";
     private static final String XML_SUFFIX = ".xml";
 
+    private static final int ALLOWED_FLAGS_FOR_CREATE_USERS_PERMISSION =
+            UserInfo.FLAG_MANAGED_PROFILE
+            | UserInfo.FLAG_RESTRICTED
+            | UserInfo.FLAG_GUEST;
+
     private static final int MIN_USER_ID = 10;
 
     private static final int USER_VERSION = 5;
@@ -260,7 +265,7 @@ public class UserManagerService extends IUserManager.Stub {
 
     @Override
     public List<UserInfo> getUsers(boolean excludeDying) {
-        checkManageUsersPermission("query users");
+        checkManageOrCreateUsersPermission("query users");
         synchronized (mPackagesLock) {
             ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUsers.size());
             for (int i = 0; i < mUsers.size(); i++) {
@@ -352,7 +357,7 @@ public class UserManagerService extends IUserManager.Stub {
 
     @Override
     public UserInfo getUserInfo(int userId) {
-        checkManageUsersPermission("query user");
+        checkManageOrCreateUsersPermission("query user");
         synchronized (mPackagesLock) {
             return getUserInfoLocked(userId);
         }
@@ -568,6 +573,71 @@ public class UserManagerService extends IUserManager.Stub {
         }
     }
 
+    /**
+     * Enforces that only the system UID or root's UID or apps that have the
+     * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS} or
+     * {@link android.Manifest.permission#CREATE_USERS CREATE_USERS}
+     * can make certain calls to the UserManager.
+     *
+     * @param message used as message if SecurityException is thrown
+     * @throws SecurityException if the caller is not system or root
+     * @see #hasManageOrCreateUsersPermission()
+     */
+    private static final void checkManageOrCreateUsersPermission(String message) {
+        if (!hasManageOrCreateUsersPermission()) {
+            throw new SecurityException(
+                    "You either need MANAGE_USERS or CREATE_USERS permission to: " + message);
+        }
+    }
+
+    /**
+     * Similar to {@link #checkManageOrCreateUsersPermission(String)} but when the caller is tries
+     * to create user/profiles other than what is allowed for
+     * {@link android.Manifest.permission#CREATE_USERS CREATE_USERS} permission, then it will only
+     * allow callers with {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS} permission.
+     */
+    private static final void checkManageOrCreateUsersPermission(int creationFlags) {
+        if ((creationFlags & ~ALLOWED_FLAGS_FOR_CREATE_USERS_PERMISSION) == 0) {
+            if (!hasManageOrCreateUsersPermission()) {
+                throw new SecurityException("You either need MANAGE_USERS or CREATE_USERS "
+                        + "permission to create an user with flags: " + creationFlags);
+            }
+        } else if (!hasManageUsersPermission()) {
+            throw new SecurityException("You need MANAGE_USERS permission to create an user "
+                    + " with flags: " + creationFlags);
+        }
+    }
+
+    /**
+     * @return whether the calling UID is system UID or root's UID or the calling app has the
+     * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS}.
+     */
+    private static final boolean hasManageUsersPermission() {
+        final int callingUid = Binder.getCallingUid();
+        return UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
+                || callingUid == Process.ROOT_UID
+                || ActivityManager.checkComponentPermission(
+                        android.Manifest.permission.MANAGE_USERS,
+                        callingUid, -1, true) == PackageManager.PERMISSION_GRANTED;
+    }
+
+    /**
+     * @return whether the calling UID is system UID or root's UID or the calling app has the
+     * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS} or
+     * {@link android.Manifest.permission#CREATE_USERS CREATE_USERS}.
+     */
+    private static final boolean hasManageOrCreateUsersPermission() {
+        final int callingUid = Binder.getCallingUid();
+        return UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
+                || callingUid == Process.ROOT_UID
+                || ActivityManager.checkComponentPermission(
+                        android.Manifest.permission.MANAGE_USERS,
+                        callingUid, -1, true) == PackageManager.PERMISSION_GRANTED
+                || ActivityManager.checkComponentPermission(
+                        android.Manifest.permission.CREATE_USERS,
+                        callingUid, -1, true) == PackageManager.PERMISSION_GRANTED;
+    }
+
     private void writeBitmapLocked(UserInfo info, Bitmap bitmap) {
         try {
             File dir = new File(mUsersDir, Integer.toString(info.id));
@@ -1132,7 +1202,7 @@ public class UserManagerService extends IUserManager.Stub {
 
     @Override
     public UserInfo createProfileForUser(String name, int flags, int userId) {
-        checkManageUsersPermission("Only the system can create users");
+        checkManageOrCreateUsersPermission(flags);
         if (userId != UserHandle.USER_OWNER) {
             Slog.w(LOG_TAG, "Only user owner can have profiles");
             return null;
@@ -1142,7 +1212,7 @@ public class UserManagerService extends IUserManager.Stub {
 
     @Override
     public UserInfo createUser(String name, int flags) {
-        checkManageUsersPermission("Only the system can create users");
+        checkManageOrCreateUsersPermission(flags);
         return createUserInternal(name, flags, UserHandle.USER_NULL);
     }
 
@@ -1294,7 +1364,7 @@ public class UserManagerService extends IUserManager.Stub {
      * @param userHandle the user's id
      */
     public boolean removeUser(int userHandle) {
-        checkManageUsersPermission("Only the system can remove users");
+        checkManageOrCreateUsersPermission("Only the system can remove users");
         if (getUserRestrictions(UserHandle.getCallingUserId()).getBoolean(
                 UserManager.DISALLOW_REMOVE_USER, false)) {
             Log.w(LOG_TAG, "Cannot remove user. DISALLOW_REMOVE_USER is enabled.");