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

Commit a8c58f06 authored by Rubin Xu's avatar Rubin Xu
Browse files

Allow automatic unlocking of work profile by Digital Wellbeing

At the moment, keystore key protecting the cached work profile challenge
is only avaliable when keyguard is unlocked. This is to ensure an
attacker cannot turn on profile automatically from Keyguard's
QuickSettings tile without knowledge of the keyguard password. This
has the inadvertent side-effect of blocking digital wellbeing app
from scheduling turning on profile in the background when the device
is most likely to be locked. Fix by allowing DWB to bypass the
keyguard unlocked requirement when
QUIET_MODE_DISABLE_ONLY_IF_CREDENTIAL_NOT_REQUIRED is passed in.

Implementation wise, this is done by not setting the
setUnlockedDeviceRequired bit on the keystore key, but enforcing the
requirement in UserManagerService via a logical check which has the
DWB bypass condition. Existing keys are retired by the framework
assuming a new name for the encryption key.

Bug: 158069733
Test: atest QuietModeHostsideTest
Test: manual
Merged-In: I4d241a4d7f11817f5171c5b064c379ff17aeaa43
Change-Id: I4d241a4d7f11817f5171c5b064c379ff17aeaa43
parent 2ea259c0
Loading
Loading
Loading
Loading
+12 −2
Original line number Diff line number Diff line
@@ -104,8 +104,6 @@ public class ManagedProfilePasswordCache {
                        // Generate auth-bound key to user 0 (since we the caller is user 0)
                        .setUserAuthenticationRequired(true)
                        .setUserAuthenticationValidityDurationSeconds(CACHE_TIMEOUT_SECONDS)
                        // Only accessible after user 0's keyguard is unlocked
                        .setUnlockedDeviceRequired(true)
                        .build());
                key = generator.generateKey();
            } catch (GeneralSecurityException e) {
@@ -171,10 +169,14 @@ public class ManagedProfilePasswordCache {
    public void removePassword(int userId) {
        synchronized (mEncryptedPasswords) {
            String keyName = getEncryptionKeyName(userId);
            String legacyKeyName = getLegacyEncryptionKeyName(userId);
            try {
                if (mKeyStore.containsAlias(keyName)) {
                    mKeyStore.deleteEntry(keyName);
                }
                if (mKeyStore.containsAlias(legacyKeyName)) {
                    mKeyStore.deleteEntry(legacyKeyName);
                }
            } catch (KeyStoreException e) {
                Slog.d(TAG, "Cannot delete key", e);
            }
@@ -186,6 +188,14 @@ public class ManagedProfilePasswordCache {
    }

    private static String getEncryptionKeyName(int userId) {
        return "com.android.server.locksettings.unified_profile_cache_v2_" + userId;
    }

    /**
     * Returns the legacy keystore key name when setUnlockedDeviceRequired() was set explicitly.
     * Only existed during Android 11 internal testing period.
     */
    private static String getLegacyEncryptionKeyName(int userId) {
        return "com.android.server.locksettings.unified_profile_cache_" + userId;
    }
}
+22 −2
Original line number Diff line number Diff line
@@ -989,6 +989,15 @@ public class UserManagerService extends IUserManager.Stub {

        ensureCanModifyQuietMode(
                callingPackage, Binder.getCallingUid(), userId, target != null, dontAskCredential);

        if (onlyIfCredentialNotRequired && callingPackage.equals(
                getPackageManagerInternal().getSystemUiServiceComponent().getPackageName())) {
            // This is to prevent SysUI from accidentally allowing the profile to turned on
            // without password when keyguard is still locked.
            throw new SecurityException("SystemUI is not allowed to set "
                    + "QUIET_MODE_DISABLE_ONLY_IF_CREDENTIAL_NOT_REQUIRED");
        }

        final long identity = Binder.clearCallingIdentity();
        try {
            if (enableQuietMode) {
@@ -996,7 +1005,17 @@ public class UserManagerService extends IUserManager.Stub {
                        userId, true /* enableQuietMode */, target, callingPackage);
                return true;
            }
            if (mLockPatternUtils.isManagedProfileWithUnifiedChallenge(userId)) {
                KeyguardManager km = mContext.getSystemService(KeyguardManager.class);
                // Normally only attempt to auto-unlock unified challenge if keyguard is not showing
                // (to stop turning profile on automatically via the QS tile), except when we
                // are called with QUIET_MODE_DISABLE_ONLY_IF_CREDENTIAL_NOT_REQUIRED, in which
                // case always attempt to auto-unlock.
                if (!km.isDeviceLocked(mLocalService.getProfileParentId(userId))
                        || onlyIfCredentialNotRequired) {
                    mLockPatternUtils.tryUnlockWithCachedUnifiedChallenge(userId);
                }
            }
            final boolean needToShowConfirmCredential = !dontAskCredential
                    && mLockPatternUtils.isSecure(userId)
                    && !StorageManager.isUserKeyUnlocked(userId);
@@ -1029,6 +1048,8 @@ public class UserManagerService extends IUserManager.Stub {
     */
    private void ensureCanModifyQuietMode(String callingPackage, int callingUid,
            @UserIdInt int targetUserId, boolean startIntent, boolean dontAskCredential) {
        verifyCallingPackage(callingPackage, callingUid);

        if (hasManageUsersPermission()) {
            return;
        }
@@ -1050,7 +1071,6 @@ public class UserManagerService extends IUserManager.Stub {
            return;
        }

        verifyCallingPackage(callingPackage, callingUid);
        final ShortcutServiceInternal shortcutInternal =
                LocalServices.getService(ShortcutServiceInternal.class);
        if (shortcutInternal != null) {