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

Commit 2806374f authored by Nicolas Prevot's avatar Nicolas Prevot
Browse files

Restrict setting the profile/device owner with a signature-level permission.

Create the new permission MANAGE_PROFILE_OWNERS to restrict setting
the profile/device owner.

BUG:19838376

Change-Id: Ib55a2db85fcb6f34e3b88c398683bddb0ad66868
parent f2953dad
Loading
Loading
Loading
Loading
+18 −14
Original line number Diff line number Diff line
@@ -2651,14 +2651,12 @@ public class DevicePolicyManager {

    /**
     * @hide
     * Sets the given package as the device owner. The package must already be installed and there
     * shouldn't be an existing device owner registered, for this call to succeed. Also, this
     * method must be called before the device is provisioned.
     * Sets the given package as the device owner.
     * Same as {@link #setDeviceOwner(String, String)} but without setting a device owner name.
     * @param packageName the package name of the application to be registered as the device owner.
     * @return whether the package was successfully registered as the device owner.
     * @throws IllegalArgumentException if the package name is null or invalid
     * @throws IllegalStateException if a device owner is already registered or the device has
     *         already been provisioned.
     * @throws IllegalStateException If the preconditions mentioned are not met.
     */
    public boolean setDeviceOwner(String packageName) throws IllegalArgumentException,
            IllegalStateException {
@@ -2667,15 +2665,17 @@ public class DevicePolicyManager {

    /**
     * @hide
     * Sets the given package as the device owner. The package must already be installed and there
     * shouldn't be an existing device owner registered, for this call to succeed. Also, this
     * method must be called before the device is provisioned.
     * Sets the given package as the device owner. The package must already be installed. There
     * must not already be a device owner.
     * Only apps with the MANAGE_PROFILE_AND_DEVICE_OWNERS permission and the shell uid can call
     * this method.
     * Calling this after the setup phase of the primary user has completed is allowed only if
     * the caller is the shell uid, and there are no additional users and no accounts.
     * @param packageName the package name of the application to be registered as the device owner.
     * @param ownerName the human readable name of the institution that owns this device.
     * @return whether the package was successfully registered as the device owner.
     * @throws IllegalArgumentException if the package name is null or invalid
     * @throws IllegalStateException if a device owner is already registered or the device has
     *         already been provisioned.
     * @throws IllegalStateException If the preconditions mentioned are not met.
     */
    public boolean setDeviceOwner(String packageName, String ownerName)
            throws IllegalArgumentException, IllegalStateException {
@@ -2961,14 +2961,18 @@ public class DevicePolicyManager {
    /**
     * @hide
     * Sets the given component as the profile owner of the given user profile. The package must
     * already be installed and there shouldn't be an existing profile owner registered for this
     * user. Only the system can call this API if the user has already completed setup.
     * already be installed. There must not already be a profile owner for this user.
     * Only apps with the MANAGE_PROFILE_AND_DEVICE_OWNERS permission and the shell uid can call
     * this method.
     * Calling this after the setup phase of the specified user has completed is allowed only if:
     * - the caller is SYSTEM_UID.
     * - or the caller is the shell uid, and there are no accounts on the specified user.
     * @param admin the component name to be registered as profile owner.
     * @param ownerName the human readable name of the organisation associated with this DPM.
     * @param userHandle the userId to set the profile owner for.
     * @return whether the component was successfully registered as the profile owner.
     * @throws IllegalArgumentException if admin is null, the package isn't installed, or
     *         the user has already been set up.
     * @throws IllegalArgumentException if admin is null, the package isn't installed, or the
     * preconditions mentioned are not met.
     */
    public boolean setProfileOwner(ComponentName admin, String ownerName, int userHandle)
            throws IllegalArgumentException {
+8 −0
Original line number Diff line number Diff line
@@ -1309,6 +1309,14 @@
    <permission android:name="android.permission.MANAGE_USERS"
        android:protectionLevel="signature|system" />

    <!-- @hide Allows an application to set the profile owners and the device owner.
         This permission is not available to third party applications.-->
    <permission android:name="android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS"
        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
        android:protectionLevel="signature"
        android:label="@string/permlab_manageProfileAndDeviceOwners"
        android:description="@string/permdesc_manageProfileAndDeviceOwners" />

    <!-- Allows an application to get full detailed information about
         recently running tasks, with full fidelity to the real state.
         @hide -->
+6 −0
Original line number Diff line number Diff line
@@ -698,6 +698,12 @@
       about currently and recently running tasks.  This may allow the app to
       discover information about which applications are used on the device.</string>

    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
    <string name="permlab_manageProfileAndDeviceOwners">Manage profile and device owners</string>
    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to set the profile/device owners.
     [CHAR LIMIT=NONE] -->
    <string name="permdesc_manageProfileAndDeviceOwners">Allows apps to set the profile owners and the device owner.</string>

    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
    <string name="permlab_reorderTasks">reorder running apps</string>
    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+74 −43
Original line number Diff line number Diff line
@@ -3983,15 +3983,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
                    + " for device owner");
        }
        synchronized (this) {
            if (!allowedToSetDeviceOwnerOnDevice()) {
                throw new IllegalStateException(
                        "Trying to set device owner but device is already provisioned.");
            }

            if (mDeviceOwner != null && mDeviceOwner.hasDeviceOwner()) {
                throw new IllegalStateException(
                        "Trying to set device owner but device owner is already set.");
            }
            enforceCanSetDeviceOwner();

            // Shutting down backup manager service permanently.
            long ident = Binder.clearCallingIdentity();
@@ -4009,7 +4001,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
                // Device owner is not set and does not exist, set it.
                mDeviceOwner = DeviceOwner.createWithDeviceOwner(packageName, ownerName);
            } else {
                // Device owner is not set but a profile owner exists, update Device owner state.
                // Device owner state already exists, update it.
                mDeviceOwner.setDeviceOwner(packageName, ownerName);
            }
            mDeviceOwner.writeOwnerFile();
@@ -4225,45 +4217,25 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
        if (!mHasFeature) {
            return false;
        }
        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);

        UserInfo info = mUserManager.getUserInfo(userHandle);
        if (info == null) {
            // User doesn't exist.
            throw new IllegalArgumentException(
                    "Attempted to set profile owner for invalid userId: " + userHandle);
        }
        if (info.isGuest()) {
            throw new IllegalStateException("Cannot set a profile owner on a guest");
        }

        if (who == null
                || !DeviceOwner.isInstalledForUser(who.getPackageName(), userHandle)) {
            throw new IllegalArgumentException("Component " + who
                    + " not installed for userId:" + userHandle);
        }
        synchronized (this) {
            // Only SYSTEM_UID can override the userSetupComplete
            if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID
                    && hasUserSetupCompleted(userHandle)) {
                throw new IllegalStateException(
                        "Trying to set profile owner but user is already set-up.");
            }

            enforceCanSetProfileOwner(userHandle);
            if (mDeviceOwner == null) {
                // Device owner state does not exist, create it.
                mDeviceOwner = DeviceOwner.createWithProfileOwner(who, ownerName,
                        userHandle);
                mDeviceOwner.writeOwnerFile();
                return true;
            } else {
                // Device owner already exists, update it.
                // Device owner state already exists, update it.
                mDeviceOwner.setProfileOwner(who, ownerName, userHandle);
            }
            mDeviceOwner.writeOwnerFile();
            return true;
        }
    }
    }

    @Override
    public void clearProfileOwner(ComponentName who) {
@@ -4451,18 +4423,77 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    }

    /**
     * Device owner can only be set on an unprovisioned device. However, if initiated via "adb",
     * we also allow it if no accounts or additional users are present on the device.
     * The profile owner can only be set by adb or an app with the MANAGE_PROFILE_AND_DEVICE_OWNERS
     * permission.
     * The profile owner can only be set before the user setup phase has completed,
     * except for:
     * - SYSTEM_UID
     * - adb if there are not accounts.
     */
    private boolean allowedToSetDeviceOwnerOnDevice() {
        if (!hasUserSetupCompleted(UserHandle.USER_OWNER)) {
            return true;
    private void enforceCanSetProfileOwner(int userHandle) {
        UserInfo info = mUserManager.getUserInfo(userHandle);
        if (info == null) {
            // User doesn't exist.
            throw new IllegalArgumentException(
                    "Attempted to set profile owner for invalid userId: " + userHandle);
        }
        if (info.isGuest()) {
            throw new IllegalStateException("Cannot set a profile owner on a guest");
        }
        if (getProfileOwner(userHandle) != null) {
            throw new IllegalStateException("Trying to set the profile owner, but profile owner "
                    + "is already set.");
        }
        int callingUid = Binder.getCallingUid();
        if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) {
            if (hasUserSetupCompleted(userHandle) &&
                    AccountManager.get(mContext).getAccountsAsUser(userHandle).length > 0) {
                throw new IllegalStateException("Not allowed to set the profile owner because "
                        + "there are already some accounts on the profile");
            }
            return;
        }
        mContext.enforceCallingOrSelfPermission(
                android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS, null);
        if (hasUserSetupCompleted(userHandle)
                && UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
            throw new IllegalStateException("Cannot set the profile owner on a user which is "
                    + "already set-up");
        }
    }

        int callingId = Binder.getCallingUid();
        return (callingId == Process.SHELL_UID || callingId == Process.ROOT_UID)
                && mUserManager.getUserCount() == 1
                && AccountManager.get(mContext).getAccounts().length == 0;
    /**
     * The Device owner can only be set by adb or an app with the MANAGE_PROFILE_AND_DEVICE_OWNERS
     * permission.
     * The device owner can only be set before the setup phase of the primary user has completed,
     * except for adb if no accounts or additional users are present on the device.
     */
    private void enforceCanSetDeviceOwner() {
        if (mDeviceOwner != null && mDeviceOwner.hasDeviceOwner()) {
            throw new IllegalStateException("Trying to set the device owner, but device owner "
                    + "is already set.");
        }
        int callingUid = Binder.getCallingUid();
        if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) {
            if (!hasUserSetupCompleted(UserHandle.USER_OWNER)) {
                return;
            }
            if (mUserManager.getUserCount() > 1) {
                throw new IllegalStateException("Not allowed to set the device owner because there "
                        + "are already several users on the device");
            }
            if (AccountManager.get(mContext).getAccounts().length > 0) {
                throw new IllegalStateException("Not allowed to set the device owner because there "
                        + "are already some accounts on the device");
            }
            return;
        }
        mContext.enforceCallingOrSelfPermission(
                android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS, null);
        if (hasUserSetupCompleted(UserHandle.USER_OWNER)) {
            throw new IllegalStateException("Cannot set the device owner if the device is "
                    + "already set-up");
        }
    }

    private void enforceCrossUserPermission(int userHandle) {