From a8c58f06d06e1a69b0f3555678f51f679da8ea30 Mon Sep 17 00:00:00 2001 From: Rubin Xu Date: Wed, 3 Jun 2020 23:00:43 +0100 Subject: [PATCH] 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 --- .../ManagedProfilePasswordCache.java | 14 +++++++++-- .../android/server/pm/UserManagerService.java | 24 +++++++++++++++++-- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java b/services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java index d38ee678c7aab..7950fcf7234ca 100644 --- a/services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java +++ b/services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java @@ -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; } } diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 40fa798309c1b..2a6997cba4bba 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -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; } - mLockPatternUtils.tryUnlockWithCachedUnifiedChallenge(userId); + 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) {