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

Commit b9fe5370 authored by Jeff Sharkey's avatar Jeff Sharkey
Browse files

Attempt to unlock users with null token.

When starting a locked user, try unlocking their storace will a null
token, which will typically succeed if there is an insecure
lockscreen (no PIN or pattern).

For users with a secure lockscreen, pass through a stub token for
now to indicate that it came from a user challenge.  Eventually we'll
hook that up to gatekeeperd.

Without this, we were only unlocking users with secure lockscreens.

Bug: 25943941
Change-Id: Ia0324d50f43f55dfe0b8366793ddc5d25d885922
parent bedbaa9e
Loading
Loading
Loading
Loading
+14 −2
Original line number Diff line number Diff line
@@ -624,7 +624,13 @@ public class LockSettingsService extends ILockSettings.Stub {
            byte[] hash = credentialUtil.toHash(credential, userId);
            if (Arrays.equals(hash, storedHash.hash)) {
                unlockKeystore(credentialUtil.adjustForKeystore(credential), userId);
                unlockUser(userId, null);

                // TODO: pass through a meaningful token from gatekeeper to
                // unlock credential keys; for now pass through a stub value to
                // indicate that we came from a user challenge.
                final byte[] token = String.valueOf(userId).getBytes();
                unlockUser(userId, token);

                // migrate credential to GateKeeper
                credentialUtil.setCredential(credential, null, userId);
                if (!hasChallenge) {
@@ -677,7 +683,13 @@ public class LockSettingsService extends ILockSettings.Stub {
        if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
            // credential has matched
            unlockKeystore(credential, userId);
            unlockUser(userId, null);

            // TODO: pass through a meaningful token from gatekeeper to
            // unlock credential keys; for now pass through a stub value to
            // indicate that we came from a user challenge.
            final byte[] token = String.valueOf(userId).getBytes();
            unlockUser(userId, token);

            UserInfo info = UserManager.get(mContext).getUserInfo(userId);
            if (LockPatternUtils.isSeparateWorkChallengeEnabled() && info.isManagedProfile()) {
                TrustManager trustManager =
+9 −0
Original line number Diff line number Diff line
@@ -100,6 +100,7 @@ import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.HexDump;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.NativeDaemonConnector.Command;
import com.android.server.NativeDaemonConnector.SensitiveArg;
import com.android.server.pm.PackageManagerService;
@@ -435,6 +436,7 @@ class MountService extends IMountService.Stub
    private PackageManagerService mPms;

    private final Callbacks mCallbacks;
    private final LockPatternUtils mLockPatternUtils;

    // Two connectors - mConnector & mCryptConnector
    private final CountDownLatch mConnectedSignal = new CountDownLatch(2);
@@ -1429,6 +1431,7 @@ class MountService extends IMountService.Stub

        mContext = context;
        mCallbacks = new Callbacks(FgThread.get().getLooper());
        mLockPatternUtils = new LockPatternUtils(mContext);

        // XXX: This will go away soon in favor of IMountServiceObserver
        mPms = (PackageManagerService) ServiceManager.getService("package");
@@ -2721,6 +2724,12 @@ class MountService extends IMountService.Stub
        enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
        waitForReady();

        // When a user has secure lock screen, require a challenge token to
        // actually unlock. This check is mostly in place for emulation mode.
        if (mLockPatternUtils.isSecure(userId) && ArrayUtils.isEmpty(token)) {
            throw new IllegalStateException("Token required to unlock secure user " + userId);
        }

        final String encodedToken;
        if (ArrayUtils.isEmpty(token)) {
            encodedToken = "!";
+28 −15
Original line number Diff line number Diff line
@@ -82,8 +82,6 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;

import libcore.util.EmptyArray;

/**
 * Helper class for {@link ActivityManagerService} responsible for multi-user functionality.
 */
@@ -223,7 +221,7 @@ final class UserController {
                        AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID, userId);
            }

            maybeFinishUserUnlock(uss);
            maybeUnlockUser(userId);
        }
    }

@@ -232,7 +230,7 @@ final class UserController {
     * {@link UserState#STATE_RUNNING}, which only occurs if the user storage is
     * actually unlocked.
     */
    void maybeFinishUserUnlock(UserState uss) {
    void finishUserUnlock(UserState uss) {
        final int userId = uss.mHandle.getIdentifier();
        synchronized (mService) {
            // Bail if we ended up with a stale user
@@ -530,9 +528,12 @@ final class UserController {
        return userManager;
    }

    private IMountService getMountService() {
        return IMountService.Stub.asInterface(ServiceManager.getService("mount"));
    }

    private boolean isUserKeyUnlocked(int userId) {
        final IMountService mountService = IMountService.Stub
                .asInterface(ServiceManager.getService("mount"));
        final IMountService mountService = getMountService();
        if (mountService != null) {
            try {
                return mountService.isUserKeyUnlocked(userId);
@@ -743,6 +744,17 @@ final class UserController {
        }
    }

    /**
     * Attempt to unlock user without a credential token. This typically
     * succeeds when the device doesn't have credential-encrypted storage, or
     * when the the credential-encrypted storage isn't tied to a user-provided
     * PIN or pattern.
     */
    boolean maybeUnlockUser(final int userId) {
        // Try unlocking storage using empty token
        return unlockUserCleared(userId, null);
    }

    boolean unlockUserCleared(final int userId, byte[] token) {
        synchronized (mService) {
            // Bail if already running unlocked
@@ -750,19 +762,20 @@ final class UserController {
            if (uss.state == UserState.STATE_RUNNING) return true;
        }

        if (!isUserKeyUnlocked(userId)) {
            final UserInfo userInfo = getUserInfo(userId);
        final IMountService mountService = IMountService.Stub
                .asInterface(ServiceManager.getService("mount"));
            final IMountService mountService = getMountService();
            try {
                mountService.unlockUserKey(userId, userInfo.serialNumber, token);
        } catch (RemoteException e) {
            } catch (RemoteException | RuntimeException e) {
                Slog.w(TAG, "Failed to unlock: " + e.getMessage());
                return false;
            }
        }

        synchronized (mService) {
            final UserState uss = mStartedUsers.get(userId);
            maybeFinishUserUnlock(uss);
            finishUserUnlock(uss);
        }

        return true;