OSDN Git Service

Attempt to unlock users with null token.
authorJeff Sharkey <jsharkey@android.com>
Thu, 3 Dec 2015 22:23:08 +0000 (15:23 -0700)
committerJeff Sharkey <jsharkey@android.com>
Thu, 3 Dec 2015 22:34:27 +0000 (15:34 -0700)
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

services/core/java/com/android/server/LockSettingsService.java
services/core/java/com/android/server/MountService.java
services/core/java/com/android/server/am/UserController.java

index 6aa5263..033a4b8 100644 (file)
@@ -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 =
index bd43a71..807c0d6 100644 (file)
@@ -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 = "!";
index 195465c..f6f82da 100644 (file)
@@ -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;
         }
 
-        final UserInfo userInfo = getUserInfo(userId);
-        final IMountService mountService = IMountService.Stub
-                .asInterface(ServiceManager.getService("mount"));
-        try {
-            mountService.unlockUserKey(userId, userInfo.serialNumber, token);
-        } catch (RemoteException e) {
-            Slog.w(TAG, "Failed to unlock: " + e.getMessage());
-            return false;
+        if (!isUserKeyUnlocked(userId)) {
+            final UserInfo userInfo = getUserInfo(userId);
+            final IMountService mountService = getMountService();
+            try {
+                mountService.unlockUserKey(userId, userInfo.serialNumber, token);
+            } 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;