From 7504b7b0feec9d5bc81fbd14587cc5bb3878b2bc Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 30 Sep 2024 19:14:44 +0000 Subject: Polishing for migration to disable Weaver - Prevent device from ending up in bad state if it rolls back to old build after the migration but before the boot has completed. - Place a (generous) maximum number of retries on unwrapping the SP. - Improve a comment. Bug: 356324437 Test: atest FrameworksServicesTests:com.android.server.locksettings Flag: EXEMPT uses config option instead Change-Id: If05d11a0a884294896223aedd79d7f689380dc58 Merged-In: If05d11a0a884294896223aedd79d7f689380dc58 (cherry picked from commit 06f58c061f0cc6dd082c0001d259f00ee7588794) --- .../server/locksettings/LockSettingsService.java | 34 +++++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index ab1eb8c2cdcb..6dd2dac22127 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -127,6 +127,7 @@ import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; import android.util.LongSparseArray; +import android.util.Pair; import android.util.Slog; import android.util.SparseArray; import android.util.SparseIntArray; @@ -312,6 +313,10 @@ public class LockSettingsService extends ILockSettings.Stub { @GuardedBy("mUserCreationAndRemovalLock") private boolean mThirdPartyAppsStarted; + // This list contains the (protectorId, userId) of any protectors that were by replaced by a + // migration and should be destroyed once rollback to the old build is no longer possible. + private ArrayList> mProtectorsToDestroyOnBootCompleted = new ArrayList<>(); + // Current password metrics for all secured users on the device. Updated when user unlocks the // device or changes password. Removed if user is stopped with its CE key evicted. @GuardedBy("this") @@ -366,6 +371,10 @@ public class LockSettingsService extends ILockSettings.Stub { mLockSettingsService.migrateOldDataAfterSystemReady(); mLockSettingsService.deleteRepairModePersistentDataIfNeeded(); } else if (phase == PHASE_BOOT_COMPLETED) { + // In the case of an upgrade, PHASE_BOOT_COMPLETED means that a rollback to the old + // build can no longer occur. This is the time to destroy any migrated protectors. + mLockSettingsService.destroyMigratedProtectors(); + mLockSettingsService.loadEscrowData(); } } @@ -1123,7 +1132,8 @@ public class LockSettingsService extends ILockSettings.Stub { // - Upgrading from Android 14, where unsecured users didn't have Keystore super keys. // // - Upgrading from a build with config_disableWeaverOnUnsecuredUsers=false to one with - // config_disableWeaverOnUnsecuredUsers=true. + // config_disableWeaverOnUnsecuredUsers=true. (We don't bother to proactively add + // Weaver for the reverse update to false, as it's too late to help in that case.) // // The end result is that all users, regardless of whether they are secured or not, have // a synthetic password with all keys initialized and protected by it, and honoring @@ -1176,13 +1186,17 @@ public class LockSettingsService extends ILockSettings.Stub { // protected by Weaver. Note that the problematic HAL can also deadlock if called with // the ActivityManagerService lock held, but that should not be a problem here since // that lock isn't held here, unlike unlockUserKeyIfUnsecured() where it is. - while (sp == null) { + for (int i = 0; i < 12 && sp == null; i++) { Slog.e(TAG, "Failed to unwrap synthetic password. Waiting 5 seconds to retry."); SystemClock.sleep(5000); result = mSpManager.unlockLskfBasedProtector(getGateKeeperService(), protectorId, LockscreenCredential.createNone(), userId, null); sp = result.syntheticPassword; } + if (sp == null) { + throw new IllegalStateException( + "Failed to unwrap synthetic password for unsecured user"); + } // If the SP is protected by Weaver, then remove the Weaver protection in order to make // config_disableWeaverOnUnsecuredUsers=true take effect. if (result.usedWeaver) { @@ -1199,9 +1213,10 @@ public class LockSettingsService extends ILockSettings.Stub { throw new IllegalStateException("New SP protector does not work"); } - // Replace the protector. + // Replace the protector. Wait until PHASE_BOOT_COMPLETED to destroy the old + // protector, since the Weaver slot erasure and freeing cannot be rolled back. setCurrentLskfBasedProtectorId(newProtectorId, userId); - mSpManager.destroyLskfBasedProtector(protectorId, userId); + mProtectorsToDestroyOnBootCompleted.add(new Pair(protectorId, userId)); } else { Slog.i(TAG, "Synthetic password is already not protected by Weaver"); } @@ -1225,6 +1240,17 @@ public class LockSettingsService extends ILockSettings.Stub { initKeystoreSuperKeys(userId, sp, /* allowExisting= */ true); } + private void destroyMigratedProtectors() { + if (!mProtectorsToDestroyOnBootCompleted.isEmpty()) { + synchronized (mSpManager) { + for (Pair pair : mProtectorsToDestroyOnBootCompleted) { + mSpManager.destroyLskfBasedProtector(pair.first, pair.second); + } + } + } + mProtectorsToDestroyOnBootCompleted = null; // The list is no longer needed. + } + /** * Returns the lowest password quality that still presents the same UI for entering it. * -- cgit v1.2.3-59-g8ed1b