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:
@@ -889,22 +889,31 @@ public class LockSettingsService extends ILockSettings.Stub {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void migrateOldDataAfterSystemReady() {
|
@VisibleForTesting
|
||||||
// Migrate the FRP credential to the persistent data block
|
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)
|
if (LockPatternUtils.frpCredentialEnabled(mContext)
|
||||||
&& !getBoolean("migrated_frp", false, 0)) {
|
&& !getBoolean("migrated_frp2", false, 0)) {
|
||||||
migrateFrpCredential();
|
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:
|
* Write the FRP persistent data block if the following are satisfied:
|
||||||
* - the user has a secure credential
|
* - the user who owns the FRP credential has a nonempty credential
|
||||||
* - the FRP credential is not set up
|
* - the FRP persistent data block doesn't exist or uses the "bad" format from Android 14 Beta 2
|
||||||
*/
|
*/
|
||||||
private void migrateFrpCredential() {
|
private void migrateFrpCredential() {
|
||||||
if (mStorage.readPersistentDataBlock() != PersistentData.NONE) {
|
PersistentData data = mStorage.readPersistentDataBlock();
|
||||||
|
if (data != PersistentData.NONE && !data.isBadFormatFromAndroid14Beta()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (UserInfo userInfo : mUserManager.getUsers()) {
|
for (UserInfo userInfo : mUserManager.getUsers()) {
|
||||||
|
|||||||
@@ -606,6 +606,11 @@ class LockSettingsStorage {
|
|||||||
this.payload = payload;
|
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) {
|
public static PersistentData fromBytes(byte[] frpData) {
|
||||||
if (frpData == null || frpData.length == 0) {
|
if (frpData == null || frpData.length == 0) {
|
||||||
return NONE;
|
return NONE;
|
||||||
|
|||||||
@@ -370,6 +370,15 @@ class SyntheticPasswordManager {
|
|||||||
return result;
|
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) {
|
public static PasswordData fromBytes(byte[] data) {
|
||||||
PasswordData result = new PasswordData();
|
PasswordData result = new PasswordData();
|
||||||
ByteBuffer buffer = ByteBuffer.allocate(data.length);
|
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 com.android.internal.widget.LockPatternUtils.USER_FRP;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
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.PropertyInvalidatedCache;
|
||||||
import android.app.admin.DevicePolicyManager;
|
import android.app.admin.DevicePolicyManager;
|
||||||
@@ -38,8 +40,9 @@ import org.junit.Before;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
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
|
@SmallTest
|
||||||
@Presubmit
|
@Presubmit
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
@@ -148,4 +151,68 @@ public class LockscreenFrpTest extends BaseLockSettingsServiceTests {
|
|||||||
mService.verifyCredential(newPin("1234"), USER_FRP, 0 /* flags */)
|
mService.verifyCredential(newPin("1234"), USER_FRP, 0 /* flags */)
|
||||||
.getResponseCode());
|
.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 */
|
2, 3, -2, -3, 44, 1, /* passwordHandle */
|
||||||
0, 0, 0, 6, /* pinLength */
|
0, 0, 0, 6, /* pinLength */
|
||||||
};
|
};
|
||||||
|
assertFalse(PasswordData.isBadFormatFromAndroid14Beta(serialized));
|
||||||
PasswordData deserialized = PasswordData.fromBytes(serialized);
|
PasswordData deserialized = PasswordData.fromBytes(serialized);
|
||||||
|
|
||||||
assertEquals(11, deserialized.scryptLogN);
|
assertEquals(11, deserialized.scryptLogN);
|
||||||
@@ -690,6 +691,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
|
|||||||
2, 3, -2, -3, 44, 1, /* passwordHandle */
|
2, 3, -2, -3, 44, 1, /* passwordHandle */
|
||||||
0, 0, 0, 6, /* pinLength */
|
0, 0, 0, 6, /* pinLength */
|
||||||
};
|
};
|
||||||
|
assertTrue(PasswordData.isBadFormatFromAndroid14Beta(serialized));
|
||||||
PasswordData deserialized = PasswordData.fromBytes(serialized);
|
PasswordData deserialized = PasswordData.fromBytes(serialized);
|
||||||
|
|
||||||
assertEquals(11, deserialized.scryptLogN);
|
assertEquals(11, deserialized.scryptLogN);
|
||||||
|
|||||||
Reference in New Issue
Block a user