Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f6552842 authored by Eric Biggers's avatar Eric Biggers Committed by Android (Google) Code Review
Browse files

Merge changes Ic06c4535,I70c26232

* changes:
  Reconnect if weaver service connection dies
  Replace isWeaverAvailable() with getWeaverService()
parents ddb8b7df 5b21e30b
Loading
Loading
Loading
Loading
+62 −29
Original line number Diff line number Diff line
@@ -36,6 +36,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;
@@ -505,7 +506,7 @@ class SyntheticPasswordManager {

    private final Context mContext;
    private LockSettingsStorage mStorage;
    private IWeaver mWeaver;
    private volatile IWeaver mWeaver;
    private WeaverConfig mWeaverConfig;
    private PasswordSlotManager mPasswordSlotManager;

@@ -536,13 +537,33 @@ class SyntheticPasswordManager {
        }
    }

    private IWeaver getWeaverService() {
    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 getWeaverServiceInternal() {
        // Try to get the AIDL service first
        try {
            IWeaver aidlWeaver = IWeaver.Stub.asInterface(
                    ServiceManager.waitForDeclaredService(IWeaver.DESCRIPTOR + "/default"));
            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;
            }
        } catch (SecurityException e) {
@@ -568,15 +589,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;
@@ -584,19 +610,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;
    }

    /**
@@ -606,7 +631,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");
        }
@@ -619,7 +644,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;
@@ -648,7 +673,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");
        }
@@ -659,7 +684,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;
@@ -870,14 +895,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);
@@ -955,13 +981,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);
@@ -1048,7 +1075,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 persistent data credential");
                return VerifyCredentialResponse.ERROR;
            }
@@ -1056,7 +1084,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);
@@ -1209,7 +1238,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);
@@ -1252,10 +1281,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;
            }
@@ -1344,12 +1374,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;
            }
@@ -1517,12 +1549,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,