Merge "Automatically fix bad FRP block written by Android 14 Beta 2" into udc-dev am: 385d2a0f7b

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/23352581

Change-Id: I91867065dc10db1f270cce9ba0f41f38c3420298
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Eric Biggers
2023-05-22 21:09:32 +00:00
committed by Automerger Merge Worker
5 changed files with 101 additions and 9 deletions

View File

@@ -889,22 +889,31 @@ public class LockSettingsService extends ILockSettings.Stub {
}
private void migrateOldDataAfterSystemReady() {
// Migrate the FRP credential to the persistent data block
@VisibleForTesting
void migrateOldDataAfterSystemReady() {
// Write the FRP persistent data block if needed.
//
// The original purpose of this code was to write the FRP block for the first time, when
// upgrading from Android 8.1 or earlier which didn't use the FRP block. This code has
// since been repurposed to also fix the "bad" (non-forwards-compatible) FRP block written
// by Android 14 Beta 2. For this reason, the database key used here has been renamed from
// "migrated_frp" to "migrated_frp2" to cause migrateFrpCredential() to run again on devices
// where it had run before.
if (LockPatternUtils.frpCredentialEnabled(mContext)
&& !getBoolean("migrated_frp", false, 0)) {
&& !getBoolean("migrated_frp2", false, 0)) {
migrateFrpCredential();
setBoolean("migrated_frp", true, 0);
setBoolean("migrated_frp2", true, 0);
}
}
/**
* Migrate the credential for the FRP credential owner user if the following are satisfied:
* - the user has a secure credential
* - the FRP credential is not set up
* Write the FRP persistent data block if the following are satisfied:
* - the user who owns the FRP credential has a nonempty credential
* - the FRP persistent data block doesn't exist or uses the "bad" format from Android 14 Beta 2
*/
private void migrateFrpCredential() {
if (mStorage.readPersistentDataBlock() != PersistentData.NONE) {
PersistentData data = mStorage.readPersistentDataBlock();
if (data != PersistentData.NONE && !data.isBadFormatFromAndroid14Beta()) {
return;
}
for (UserInfo userInfo : mUserManager.getUsers()) {

View File

@@ -606,6 +606,11 @@ class LockSettingsStorage {
this.payload = payload;
}
public boolean isBadFormatFromAndroid14Beta() {
return (this.type == TYPE_SP_GATEKEEPER || this.type == TYPE_SP_WEAVER)
&& SyntheticPasswordManager.PasswordData.isBadFormatFromAndroid14Beta(this.payload);
}
public static PersistentData fromBytes(byte[] frpData) {
if (frpData == null || frpData.length == 0) {
return NONE;

View File

@@ -370,6 +370,15 @@ class SyntheticPasswordManager {
return result;
}
/**
* Returns true if the given serialized PasswordData begins with the value 2 as a short.
* This detects the "bad" (non-forwards-compatible) PasswordData format that was temporarily
* used during development of Android 14. For more details, see fromBytes() below.
*/
public static boolean isBadFormatFromAndroid14Beta(byte[] data) {
return data != null && data.length >= 2 && data[0] == 0 && data[1] == 2;
}
public static PasswordData fromBytes(byte[] data) {
PasswordData result = new PasswordData();
ByteBuffer buffer = ByteBuffer.allocate(data.length);

View File

@@ -23,6 +23,8 @@ import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PIN;
import static com.android.internal.widget.LockPatternUtils.USER_FRP;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import android.app.PropertyInvalidatedCache;
import android.app.admin.DevicePolicyManager;
@@ -38,8 +40,9 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.nio.ByteBuffer;
/** Test setting a lockscreen credential and then verify it under USER_FRP */
/** Tests that involve the Factory Reset Protection (FRP) credential. */
@SmallTest
@Presubmit
@RunWith(AndroidJUnit4.class)
@@ -148,4 +151,68 @@ public class LockscreenFrpTest extends BaseLockSettingsServiceTests {
mService.verifyCredential(newPin("1234"), USER_FRP, 0 /* flags */)
.getResponseCode());
}
// The FRP block that gets written by the current version of Android must still be accepted by
// old versions of Android. This test tries to detect non-forward-compatible changes in
// PasswordData#toBytes(), which would break that.
@Test
public void testFrpBlock_isForwardsCompatible() {
mService.setLockCredential(newPin("1234"), nonePassword(), PRIMARY_USER_ID);
PersistentData data = mStorage.readPersistentDataBlock();
ByteBuffer buffer = ByteBuffer.wrap(data.payload);
final int credentialType = buffer.getInt();
assertEquals(CREDENTIAL_TYPE_PIN, credentialType);
final byte scryptLogN = buffer.get();
assertTrue(scryptLogN >= 0);
final byte scryptLogR = buffer.get();
assertTrue(scryptLogR >= 0);
final byte scryptLogP = buffer.get();
assertTrue(scryptLogP >= 0);
final int saltLength = buffer.getInt();
assertTrue(saltLength > 0);
final byte[] salt = new byte[saltLength];
buffer.get(salt);
final int passwordHandleLength = buffer.getInt();
assertTrue(passwordHandleLength > 0);
final byte[] passwordHandle = new byte[passwordHandleLength];
buffer.get(passwordHandle);
}
@Test
public void testFrpBlock_inBadAndroid14FormatIsAutomaticallyFixed() {
mService.setLockCredential(newPin("1234"), nonePassword(), PRIMARY_USER_ID);
// Write a "bad" FRP block with PasswordData beginning with the bytes [0, 2].
byte[] badPasswordData = new byte[] {
0, 2, /* version 2 */
0, 3, /* CREDENTIAL_TYPE_PIN */
11, /* scryptLogN */
22, /* scryptLogR */
33, /* scryptLogP */
0, 0, 0, 5, /* salt.length */
1, 2, -1, -2, 55, /* salt */
0, 0, 0, 6, /* passwordHandle.length */
2, 3, -2, -3, 44, 1, /* passwordHandle */
0, 0, 0, 6, /* pinLength */
};
mStorage.writePersistentDataBlock(PersistentData.TYPE_SP_GATEKEEPER, PRIMARY_USER_ID, 0,
badPasswordData);
// Execute the code that should fix the FRP block.
assertFalse(mStorage.getBoolean("migrated_frp2", false, 0));
mService.migrateOldDataAfterSystemReady();
assertTrue(mStorage.getBoolean("migrated_frp2", false, 0));
// Verify that the FRP block has been fixed.
PersistentData data = mStorage.readPersistentDataBlock();
assertEquals(PersistentData.TYPE_SP_GATEKEEPER, data.type);
ByteBuffer buffer = ByteBuffer.wrap(data.payload);
assertEquals(CREDENTIAL_TYPE_PIN, buffer.getInt());
}
}

View File

@@ -638,6 +638,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
2, 3, -2, -3, 44, 1, /* passwordHandle */
0, 0, 0, 6, /* pinLength */
};
assertFalse(PasswordData.isBadFormatFromAndroid14Beta(serialized));
PasswordData deserialized = PasswordData.fromBytes(serialized);
assertEquals(11, deserialized.scryptLogN);
@@ -690,6 +691,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
2, 3, -2, -3, 44, 1, /* passwordHandle */
0, 0, 0, 6, /* pinLength */
};
assertTrue(PasswordData.isBadFormatFromAndroid14Beta(serialized));
PasswordData deserialized = PasswordData.fromBytes(serialized);
assertEquals(11, deserialized.scryptLogN);