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)
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index ab1eb8c..6dd2dac 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.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 @@
@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<Pair<Long, Integer>> 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 @@
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 @@
// - 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 @@
// 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 @@
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 @@
initKeystoreSuperKeys(userId, sp, /* allowExisting= */ true);
}
+ private void destroyMigratedProtectors() {
+ if (!mProtectorsToDestroyOnBootCompleted.isEmpty()) {
+ synchronized (mSpManager) {
+ for (Pair<Long, Integer> 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.
*