Merge "Automatically fix bad FRP block written by Android 14 Beta 2" into udc-dev
This commit is contained in:
@@ -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()) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user