Return copy of pending token list

Make SyntheticPasswordManager.getPendingTokensForUser() return
a copy of the token list, as the underlying list might change
if a pending token is activated or removed. This fixes the NPE
in LockSettingsService.activateEscrowTokens() where it tries
to iterate through the list and activate tokens.

Bug: 178560581
Test: atest com.android.server.locksettings

Merged-In: I59d159d792a3d9e2a79ea521d6f01a5cb7c65695
Change-Id: I59d159d792a3d9e2a79ea521d6f01a5cb7c65695
This commit is contained in:
Rubin Xu
2021-03-04 15:42:09 +00:00
parent 84da0714a2
commit 8171508fe0
2 changed files with 40 additions and 5 deletions

View File

@@ -35,6 +35,7 @@ import android.security.Scrypt;
import android.service.gatekeeper.GateKeeperResponse;
import android.service.gatekeeper.IGateKeeperService;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
@@ -904,7 +905,7 @@ public class SyntheticPasswordManager {
if (!tokenMap.containsKey(userId)) {
return Collections.emptySet();
}
return tokenMap.get(userId).keySet();
return new ArraySet<>(tokenMap.get(userId).keySet());
}
public boolean removePendingToken(long handle, int userId) {

View File

@@ -246,7 +246,8 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
assertTrue(mService.hasPendingEscrowToken(PRIMARY_USER_ID));
mService.verifyCredential(password, 0, PRIMARY_USER_ID).getResponseCode();
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
password, 0, PRIMARY_USER_ID).getResponseCode());
assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
assertFalse(mService.hasPendingEscrowToken(PRIMARY_USER_ID));
@@ -275,7 +276,8 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null);
assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
mService.verifyCredential(password, 0, PRIMARY_USER_ID).getResponseCode();
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
password, 0, PRIMARY_USER_ID).getResponseCode());
assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
mLocalService.setLockCredentialWithToken(nonePassword(), handle, token, PRIMARY_USER_ID);
@@ -301,7 +303,8 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null);
assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
mService.verifyCredential(password, 0, PRIMARY_USER_ID).getResponseCode();
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
password, 0, PRIMARY_USER_ID).getResponseCode());
assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
mService.setLockCredential(pattern, password, PRIMARY_USER_ID);
@@ -376,6 +379,36 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
} catch (SecurityException expected) { }
}
@Test
public void testActivateMultipleEscrowTokens() throws Exception {
byte[] token0 = "some-high-entropy-secure-token-0".getBytes();
byte[] token1 = "some-high-entropy-secure-token-1".getBytes();
byte[] token2 = "some-high-entropy-secure-token-2".getBytes();
LockscreenCredential password = newPassword("password");
LockscreenCredential pattern = newPattern("123654");
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
long handle0 = mLocalService.addEscrowToken(token0, PRIMARY_USER_ID, null);
long handle1 = mLocalService.addEscrowToken(token1, PRIMARY_USER_ID, null);
long handle2 = mLocalService.addEscrowToken(token2, PRIMARY_USER_ID, null);
// Activate token
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
password, 0, PRIMARY_USER_ID).getResponseCode());
// Verify tokens work
assertTrue(mLocalService.isEscrowTokenActive(handle0, PRIMARY_USER_ID));
assertTrue(mLocalService.setLockCredentialWithToken(
pattern, handle0, token0, PRIMARY_USER_ID));
assertTrue(mLocalService.isEscrowTokenActive(handle1, PRIMARY_USER_ID));
assertTrue(mLocalService.setLockCredentialWithToken(
pattern, handle1, token1, PRIMARY_USER_ID));
assertTrue(mLocalService.isEscrowTokenActive(handle2, PRIMARY_USER_ID));
assertTrue(mLocalService.setLockCredentialWithToken(
pattern, handle2, token2, PRIMARY_USER_ID));
}
@Test
public void testSetLockCredentialWithTokenFailsWithoutLockScreen() throws Exception {
LockscreenCredential password = newPassword("password");
@@ -503,7 +536,8 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
reset(mDevicePolicyManager);
long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null);
mService.verifyCredential(password, 0, PRIMARY_USER_ID).getResponseCode();
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
password, 0, PRIMARY_USER_ID).getResponseCode());
assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
mService.onCleanupUser(PRIMARY_USER_ID);