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

Commit 0acc4bf5 authored by Pavel Grafov's avatar Pavel Grafov
Browse files

Unlock managed profile keystore when user is unlocked.

With file based encryption when the user unlock the phone,
managed profile is already running (in a locked state). But
on full disk encryption devices, LSS attempts to unlock child
profile straight after unlocking user 0, which fails because
the profile is not yet running.

With this change once the profile gets unlocked (happens after
ActivityManagerService processes START_PROFILES_MSG message)
LSS will attempt to unlock its keystore.

Bug: 64722589
Test: manual, tried FDE and FBE devices with unified challenge.
Change-Id: Ic614cc3c6732a3db6aaf56fef1822e358d742510
parent f5074904
Loading
Loading
Loading
Loading
+36 −6
Original line number Diff line number Diff line
@@ -74,6 +74,7 @@ import android.security.KeyStore;
import android.security.keystore.AndroidKeyStoreProvider;
import android.security.keystore.KeyProperties;
import android.security.keystore.KeyProtection;
import android.security.keystore.UserNotAuthenticatedException;
import android.service.gatekeeper.GateKeeperResponse;
import android.service.gatekeeper.IGateKeeperService;
import android.text.TextUtils;
@@ -503,12 +504,34 @@ public class LockSettingsService extends ILockSettings.Stub {
        maybeShowEncryptionNotificationForUser(userId);
    }

    /**
     * Check if profile got unlocked but the keystore is still locked. This happens on full disk
     * encryption devices since the profile may not yet be running when we consider unlocking it
     * during the normal flow. In this case unlock the keystore for the profile.
     */
    private void ensureProfileKeystoreUnlocked(int userId) {
        final KeyStore ks = KeyStore.getInstance();
        if (ks.state(userId) == KeyStore.State.LOCKED
                && tiedManagedProfileReadyToUnlock(mUserManager.getUserInfo(userId))) {
            Slog.i(TAG, "Managed profile got unlocked, will unlock its keystore");
            try {
                // If boot took too long and the password in vold got expired, parent keystore will
                // be still locked, we ignore this case since the user will be prompted to unlock
                // the device after boot.
                unlockChildProfile(userId, true /* ignoreUserNotAuthenticated */);
            } catch (RemoteException e) {
                Slog.e(TAG, "Failed to unlock child profile");
            }
        }
    }

    public void onUnlockUser(final int userId) {
        // Perform tasks which require locks in LSS on a handler, as we are callbacks from
        // ActivityManager.unlockUser()
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                ensureProfileKeystoreUnlocked(userId);
                // Hide notification first, as tie managed profile lock takes time
                hideEncryptionNotification(new UserHandle(userId));

@@ -1027,7 +1050,8 @@ public class LockSettingsService extends ILockSettings.Stub {
        return new String(decryptionResult, StandardCharsets.UTF_8);
    }

    private void unlockChildProfile(int profileHandle) throws RemoteException {
    private void unlockChildProfile(int profileHandle, boolean ignoreUserNotAuthenticated)
            throws RemoteException {
        try {
            doVerifyCredential(getDecryptedPasswordForTiedProfile(profileHandle),
                    LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
@@ -1038,6 +1062,8 @@ public class LockSettingsService extends ILockSettings.Stub {
                | BadPaddingException | CertificateException | IOException e) {
            if (e instanceof FileNotFoundException) {
                Slog.i(TAG, "Child profile key not found");
            } else if (ignoreUserNotAuthenticated && e instanceof UserNotAuthenticatedException) {
                Slog.i(TAG, "Parent keystore seems locked, ignoring");
            } else {
                Slog.e(TAG, "Failed to decrypt child profile key", e);
            }
@@ -1081,11 +1107,8 @@ public class LockSettingsService extends ILockSettings.Stub {
                final List<UserInfo> profiles = mUserManager.getProfiles(userId);
                for (UserInfo pi : profiles) {
                    // Unlock managed profile with unified lock
                    if (pi.isManagedProfile()
                            && !mLockPatternUtils.isSeparateProfileChallengeEnabled(pi.id)
                            && mStorage.hasChildProfileLock(pi.id)
                            && mUserManager.isUserRunning(pi.id)) {
                        unlockChildProfile(pi.id);
                    if (tiedManagedProfileReadyToUnlock(pi)) {
                        unlockChildProfile(pi.id, false /* ignoreUserNotAuthenticated */);
                    }
                }
            }
@@ -1094,6 +1117,13 @@ public class LockSettingsService extends ILockSettings.Stub {
        }
    }

    private boolean tiedManagedProfileReadyToUnlock(UserInfo userInfo) {
        return userInfo.isManagedProfile()
                && !mLockPatternUtils.isSeparateProfileChallengeEnabled(userInfo.id)
                && mStorage.hasChildProfileLock(userInfo.id)
                && mUserManager.isUserRunning(userInfo.id);
    }

    private Map<Integer, String> getDecryptedPasswordsForAllTiedProfiles(int userId) {
        if (mUserManager.getUserInfo(userId).isManagedProfile()) {
            return null;