diff options
| author | 2023-08-25 05:04:44 +0000 | |
|---|---|---|
| committer | 2023-08-25 05:04:44 +0000 | |
| commit | 02add5fc232bf2bc759db59d87eb5fd067a643b9 (patch) | |
| tree | fbb6d812494928a459f93fb847e16df4c655db0e | |
| parent | 96843cf63ba2e58a460322d14d894851d5672f20 (diff) | |
| parent | 456cd05c7e547bf32ae0e327c1118f2b3d016653 (diff) | |
Merge changes I32306fb8,Ic06c4535,I70c26232 into udc-dev-plus-aosp
* changes:
locksettings: Don't use AIDL V1 weaver
Reconnect if weaver service connection dies
Replace isWeaverAvailable() with getWeaverService()
| -rw-r--r-- | services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java | 132 |
1 files changed, 95 insertions, 37 deletions
diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java index e8fd6f88359c..11c0f5183e21 100644 --- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java +++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java @@ -31,6 +31,7 @@ import android.hardware.weaver.IWeaver; import android.hardware.weaver.WeaverConfig; import android.hardware.weaver.WeaverReadResponse; import android.hardware.weaver.WeaverReadStatus; +import android.os.IBinder; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.ServiceManager; @@ -71,7 +72,6 @@ import java.util.NoSuchElementException; import java.util.Objects; import java.util.Set; - /** * A class that manages a user's synthetic password (SP) ({@link #SyntheticPassword}), along with a * set of SP protectors that are independent ways that the SP is protected. @@ -500,7 +500,7 @@ class SyntheticPasswordManager { private final Context mContext; private LockSettingsStorage mStorage; - private IWeaver mWeaver; + private volatile IWeaver mWeaver; private WeaverConfig mWeaverConfig; private PasswordSlotManager mPasswordSlotManager; @@ -531,17 +531,63 @@ class SyntheticPasswordManager { } } - private IWeaver getWeaverService() { - // Try to get the AIDL service first + private class WeaverDiedRecipient implements IBinder.DeathRecipient { + // Not synchronized on the outer class, since setting the pointer to null is atomic, and we + // don't want to have to worry about any sort of deadlock here. + @Override + public void binderDied() { + // Weaver died. Try to recover by setting mWeaver to null, which makes + // getWeaverService() look up the service again. This is done only as a simple + // robustness measure; it should not be relied on. If this triggers, the root cause is + // almost certainly a bug in the device's Weaver implementation, which must be fixed. + Slog.wtf(TAG, "Weaver service has died"); + mWeaver.asBinder().unlinkToDeath(this, 0); + mWeaver = null; + } + } + + private @Nullable IWeaver getWeaverAidlService() { + final IWeaver aidlWeaver; try { - IWeaver aidlWeaver = IWeaver.Stub.asInterface( - ServiceManager.waitForDeclaredService(IWeaver.DESCRIPTOR + "/default")); - if (aidlWeaver != null) { - Slog.i(TAG, "Using AIDL weaver service"); - return aidlWeaver; - } + aidlWeaver = + IWeaver.Stub.asInterface( + ServiceManager.waitForDeclaredService(IWeaver.DESCRIPTOR + "/default")); } catch (SecurityException e) { Slog.w(TAG, "Does not have permissions to get AIDL weaver service"); + return null; + } + if (aidlWeaver == null) { + return null; + } + final int aidlVersion; + try { + aidlVersion = aidlWeaver.getInterfaceVersion(); + } catch (RemoteException e) { + Slog.e(TAG, "Cannot get AIDL weaver service version", e); + return null; + } + if (aidlVersion < 2) { + Slog.w(TAG, + "Ignoring AIDL weaver service v" + + aidlVersion + + " because only v2 and later are supported"); + return null; + } + Slog.i(TAG, "Found AIDL weaver service v" + aidlVersion); + return aidlWeaver; + } + + private @Nullable IWeaver getWeaverServiceInternal() { + // Try to get the AIDL service first + IWeaver aidlWeaver = getWeaverAidlService(); + if (aidlWeaver != null) { + Slog.i(TAG, "Using AIDL weaver service"); + try { + aidlWeaver.asBinder().linkToDeath(new WeaverDiedRecipient(), 0); + } catch (RemoteException e) { + Slog.w(TAG, "Unable to register Weaver death recipient", e); + } + return aidlWeaver; } // If the AIDL service can't be found, look for the HIDL service @@ -563,15 +609,20 @@ class SyntheticPasswordManager { return LockPatternUtils.isAutoPinConfirmFeatureAvailable(); } - private synchronized boolean isWeaverAvailable() { - if (mWeaver != null) { - return true; + /** + * Returns a handle to the Weaver service, or null if Weaver is unavailable. Note that not all + * devices support Weaver. + */ + private synchronized @Nullable IWeaver getWeaverService() { + IWeaver weaver = mWeaver; + if (weaver != null) { + return weaver; } // Re-initialize weaver in case there was a transient error preventing access to it. - IWeaver weaver = getWeaverService(); + weaver = getWeaverServiceInternal(); if (weaver == null) { - return false; + return null; } final WeaverConfig weaverConfig; @@ -579,19 +630,18 @@ class SyntheticPasswordManager { weaverConfig = weaver.getConfig(); } catch (RemoteException | ServiceSpecificException e) { Slog.e(TAG, "Failed to get weaver config", e); - return false; + return null; } if (weaverConfig == null || weaverConfig.slots <= 0) { Slog.e(TAG, "Invalid weaver config"); - return false; + return null; } mWeaver = weaver; mWeaverConfig = weaverConfig; mPasswordSlotManager.refreshActiveSlots(getUsedWeaverSlots()); Slog.i(TAG, "Weaver service initialized"); - - return true; + return weaver; } /** @@ -601,7 +651,7 @@ class SyntheticPasswordManager { * * @return the value stored in the weaver slot, or null if the operation fails */ - private byte[] weaverEnroll(int slot, byte[] key, @Nullable byte[] value) { + private byte[] weaverEnroll(IWeaver weaver, int slot, byte[] key, @Nullable byte[] value) { if (slot == INVALID_WEAVER_SLOT || slot >= mWeaverConfig.slots) { throw new IllegalArgumentException("Invalid slot for weaver"); } @@ -614,7 +664,7 @@ class SyntheticPasswordManager { value = SecureRandomUtils.randomBytes(mWeaverConfig.valueSize); } try { - mWeaver.write(slot, key, value); + weaver.write(slot, key, value); } catch (RemoteException e) { Slog.e(TAG, "weaver write binder call failed, slot: " + slot, e); return null; @@ -643,7 +693,7 @@ class SyntheticPasswordManager { * the verification is successful, throttled or failed. If successful, the bound secret * is also returned. */ - private VerifyCredentialResponse weaverVerify(int slot, byte[] key) { + private VerifyCredentialResponse weaverVerify(IWeaver weaver, int slot, byte[] key) { if (slot == INVALID_WEAVER_SLOT || slot >= mWeaverConfig.slots) { throw new IllegalArgumentException("Invalid slot for weaver"); } @@ -654,7 +704,7 @@ class SyntheticPasswordManager { } final WeaverReadResponse readResponse; try { - readResponse = mWeaver.read(slot, key); + readResponse = weaver.read(slot, key); } catch (RemoteException e) { Slog.e(TAG, "weaver read failed, slot: " + slot, e); return VerifyCredentialResponse.ERROR; @@ -846,14 +896,15 @@ class SyntheticPasswordManager { int slot = loadWeaverSlot(protectorId, userId); destroyState(WEAVER_SLOT_NAME, protectorId, userId); if (slot != INVALID_WEAVER_SLOT) { - if (!isWeaverAvailable()) { + final IWeaver weaver = getWeaverService(); + if (weaver == null) { Slog.e(TAG, "Cannot erase Weaver slot because Weaver is unavailable"); return; } Set<Integer> usedSlots = getUsedWeaverSlots(); if (!usedSlots.contains(slot)) { Slogf.i(TAG, "Erasing Weaver slot %d", slot); - weaverEnroll(slot, null, null); + weaverEnroll(weaver, slot, null, null); mPasswordSlotManager.markSlotDeleted(slot); } else { Slogf.i(TAG, "Weaver slot %d was already reused; not erasing it", slot); @@ -931,13 +982,14 @@ class SyntheticPasswordManager { Slogf.i(TAG, "Creating LSKF-based protector %016x for user %d", protectorId, userId); - if (isWeaverAvailable()) { + final IWeaver weaver = getWeaverService(); + if (weaver != null) { // Weaver is available, so make the protector use it to verify the LSKF. Do this even // if the LSKF is empty, as that gives us support for securely deleting the protector. int weaverSlot = getNextAvailableWeaverSlot(); Slogf.i(TAG, "Enrolling LSKF for user %d into Weaver slot %d", userId, weaverSlot); - byte[] weaverSecret = weaverEnroll(weaverSlot, stretchedLskfToWeaverKey(stretchedLskf), - null); + byte[] weaverSecret = weaverEnroll(weaver, weaverSlot, + stretchedLskfToWeaverKey(stretchedLskf), null); if (weaverSecret == null) { throw new IllegalStateException( "Fail to enroll user password under weaver " + userId); @@ -1024,7 +1076,8 @@ class SyntheticPasswordManager { } return VerifyCredentialResponse.fromGateKeeperResponse(response); } else if (persistentData.type == PersistentData.TYPE_SP_WEAVER) { - if (!isWeaverAvailable()) { + final IWeaver weaver = getWeaverService(); + if (weaver == null) { Slog.e(TAG, "No weaver service to verify SP-based FRP credential"); return VerifyCredentialResponse.ERROR; } @@ -1032,7 +1085,8 @@ class SyntheticPasswordManager { byte[] stretchedLskf = stretchLskf(userCredential, pwd); int weaverSlot = persistentData.userId; - return weaverVerify(weaverSlot, stretchedLskfToWeaverKey(stretchedLskf)).stripPayload(); + return weaverVerify(weaver, weaverSlot, + stretchedLskfToWeaverKey(stretchedLskf)).stripPayload(); } else { Slog.e(TAG, "persistentData.type must be TYPE_SP_GATEKEEPER or TYPE_SP_WEAVER, but is " + persistentData.type); @@ -1134,7 +1188,7 @@ class SyntheticPasswordManager { TokenData tokenData = new TokenData(); tokenData.mType = type; final byte[] secdiscardable = SecureRandomUtils.randomBytes(SECDISCARDABLE_LENGTH); - if (isWeaverAvailable()) { + if (getWeaverService() != null) { tokenData.weaverSecret = SecureRandomUtils.randomBytes(mWeaverConfig.valueSize); tokenData.secdiscardableOnDisk = SyntheticPasswordCrypto.encrypt(tokenData.weaverSecret, PERSONALIZATION_WEAVER_TOKEN, secdiscardable); @@ -1177,10 +1231,11 @@ class SyntheticPasswordManager { return false; } Slogf.i(TAG, "Creating token-based protector %016x for user %d", tokenHandle, userId); - if (isWeaverAvailable()) { + final IWeaver weaver = getWeaverService(); + if (weaver != null) { int slot = getNextAvailableWeaverSlot(); Slogf.i(TAG, "Using Weaver slot %d for new token-based protector", slot); - if (weaverEnroll(slot, null, tokenData.weaverSecret) == null) { + if (weaverEnroll(weaver, slot, null, tokenData.weaverSecret) == null) { Slog.e(TAG, "Failed to enroll weaver secret when activating token"); return false; } @@ -1269,12 +1324,14 @@ class SyntheticPasswordManager { int weaverSlot = loadWeaverSlot(protectorId, userId); if (weaverSlot != INVALID_WEAVER_SLOT) { // Protector uses Weaver to verify the LSKF - if (!isWeaverAvailable()) { + final IWeaver weaver = getWeaverService(); + if (weaver == null) { Slog.e(TAG, "Protector uses Weaver, but Weaver is unavailable"); result.gkResponse = VerifyCredentialResponse.ERROR; return result; } - result.gkResponse = weaverVerify(weaverSlot, stretchedLskfToWeaverKey(stretchedLskf)); + result.gkResponse = weaverVerify(weaver, weaverSlot, + stretchedLskfToWeaverKey(stretchedLskf)); if (result.gkResponse.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) { return result; } @@ -1442,12 +1499,13 @@ class SyntheticPasswordManager { } int slotId = loadWeaverSlot(protectorId, userId); if (slotId != INVALID_WEAVER_SLOT) { - if (!isWeaverAvailable()) { + final IWeaver weaver = getWeaverService(); + if (weaver == null) { Slog.e(TAG, "Protector uses Weaver, but Weaver is unavailable"); result.gkResponse = VerifyCredentialResponse.ERROR; return result; } - VerifyCredentialResponse response = weaverVerify(slotId, null); + VerifyCredentialResponse response = weaverVerify(weaver, slotId, null); if (response.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK || response.getGatekeeperHAT() == null) { Slog.e(TAG, |