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

Commit aaec88c7 authored by Eric Biggers's avatar Eric Biggers
Browse files

Rename methods for unlocking, locking, and protecting CE storage

Users have many cryptographic keys, such as:

- Storage (file-based encryption) keys, both CE and DE
- Keystore super keys, both AfterFirstUnlock and UnlockedDeviceRequired
- Keystore client keys
- Synthetic password and the Keystore key that encrypts it

Unfortunately, many StorageManager, vold, and LockSettingsService
methods refer simply to "UserKey".  It isn't clear or consistent which
key(s) they mean.  For example, unlockUserKey unlocks CE storage,
createUserKey creates both the CE and DE keys, and
unlockUserKeyIfUnsecured unlocks CE storage but also does other things.
With the planned fixes to handle Keystore super keys more similarly to
the CE storage key (b/296464083), this confusion will increase further.

This CL is the first part of fixing this.  It renames the following
StorageManager methods to make it clear that they deal with CE storage:

   unlockUserKey => unlockCeStorage
   lockUserKey => lockCeStorage
   setUserKeyProtection => setCeStorageProtection

In addition, it starts the renaming of:

   isUserKeyUnlocked => isCeStorageUnlocked

However, isUserKeyUnlocked is used more widely and is also a @TestApi,
so for now it still exists alongside the new name.  Later CLs will
convert the remaining callers of isUserKeyUnlocked to use the new name.

No change in behavior except for some changed log messages.

Bug: 306204742
Flag: exempt, mechanical refactoring
Test: presubmit
Change-Id: I202ebbfd2b4f79fedb3ed120a8ad81500c126894
parent 47be3bb6
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -138,16 +138,16 @@ interface IStorageManager {
    @EnforcePermission("STORAGE_INTERNAL")
    void destroyUserKey(int userId) = 62;
    @EnforcePermission("STORAGE_INTERNAL")
    void unlockUserKey(int userId, int serialNumber, in byte[] secret) = 63;
    void unlockCeStorage(int userId, int serialNumber, in byte[] secret) = 63;
    @EnforcePermission("STORAGE_INTERNAL")
    void lockUserKey(int userId) = 64;
    boolean isUserKeyUnlocked(int userId) = 65;
    void lockCeStorage(int userId) = 64;
    boolean isCeStorageUnlocked(int userId) = 65;
    @EnforcePermission("STORAGE_INTERNAL")
    void prepareUserStorage(in String volumeUuid, int userId, int serialNumber, int flags) = 66;
    @EnforcePermission("STORAGE_INTERNAL")
    void destroyUserStorage(in String volumeUuid, int userId, int flags) = 67;
    @EnforcePermission("STORAGE_INTERNAL")
    void setUserKeyProtection(int userId, in byte[] secret) = 70;
    void setCeStorageProtection(int userId, in byte[] secret) = 70;
    @EnforcePermission("MOUNT_FORMAT_FILESYSTEMS")
    void fstrim(int flags, IVoldTaskListener listener) = 72;
    AppFuseMount mountProxyFileDescriptorBridge() = 73;
+18 −5
Original line number Diff line number Diff line
@@ -1598,10 +1598,14 @@ public class StorageManager {
        }
    }

    /** {@hide} */
    public void lockUserKey(int userId) {
    /**
     * Locks the user's credential-encrypted (CE) storage.
     *
     * @hide
     */
    public void lockCeStorage(int userId) {
        try {
            mStorageManager.lockUserKey(userId);
            mStorageManager.lockCeStorage(userId);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
@@ -1628,17 +1632,26 @@ public class StorageManager {
    /** {@hide} */
    @TestApi
    public static boolean isUserKeyUnlocked(int userId) {
        return isCeStorageUnlocked(userId);
    }

    /**
     * Returns true if the user's credential-encrypted (CE) storage is unlocked.
     *
     * @hide
     */
    public static boolean isCeStorageUnlocked(int userId) {
        if (sStorageManager == null) {
            sStorageManager = IStorageManager.Stub
                    .asInterface(ServiceManager.getService("mount"));
        }
        if (sStorageManager == null) {
            Slog.w(TAG, "Early during boot, assuming locked");
            Slog.w(TAG, "Early during boot, assuming CE storage is locked");
            return false;
        }
        final long token = Binder.clearCallingIdentity();
        try {
            return sStorageManager.isUserKeyUnlocked(userId);
            return sStorageManager.isCeStorageUnlocked(userId);
        } catch (RemoteException e) {
            throw e.rethrowAsRuntimeException();
        } finally {
+20 −20
Original line number Diff line number Diff line
@@ -2984,7 +2984,7 @@ class StorageManagerService extends IStorageManager.Stub
            // We need all the users unlocked to move their primary storage
            users = mContext.getSystemService(UserManager.class).getUsers();
            for (UserInfo user : users) {
                if (StorageManager.isFileEncrypted() && !isUserKeyUnlocked(user.id)) {
                if (StorageManager.isFileEncrypted() && !isCeStorageUnlocked(user.id)) {
                    Slog.w(TAG, "Failing move due to locked user " + user.id);
                    onMoveStatusLocked(PackageManager.MOVE_FAILED_LOCKED_USER);
                    return;
@@ -3243,21 +3243,22 @@ class StorageManagerService extends IStorageManager.Stub
    /* Only for use by LockSettingsService */
    @android.annotation.EnforcePermission(android.Manifest.permission.STORAGE_INTERNAL)
    @Override
    public void setUserKeyProtection(@UserIdInt int userId, byte[] secret) throws RemoteException {
        super.setUserKeyProtection_enforcePermission();
    public void setCeStorageProtection(@UserIdInt int userId, byte[] secret)
            throws RemoteException {
        super.setCeStorageProtection_enforcePermission();

        mVold.setUserKeyProtection(userId, HexDump.toHexString(secret));
        mVold.setCeStorageProtection(userId, HexDump.toHexString(secret));
    }

    /* Only for use by LockSettingsService */
    @android.annotation.EnforcePermission(android.Manifest.permission.STORAGE_INTERNAL)
    @Override
    public void unlockUserKey(@UserIdInt int userId, int serialNumber, byte[] secret)
    public void unlockCeStorage(@UserIdInt int userId, int serialNumber, byte[] secret)
            throws RemoteException {
        super.unlockUserKey_enforcePermission();
        super.unlockCeStorage_enforcePermission();

        if (StorageManager.isFileEncrypted()) {
            mVold.unlockUserKey(userId, serialNumber, HexDump.toHexString(secret));
            mVold.unlockCeStorage(userId, serialNumber, HexDump.toHexString(secret));
        }
        synchronized (mLock) {
            mCeUnlockedUsers.append(userId);
@@ -3266,23 +3267,22 @@ class StorageManagerService extends IStorageManager.Stub

    @android.annotation.EnforcePermission(android.Manifest.permission.STORAGE_INTERNAL)
    @Override
    public void lockUserKey(int userId) {
        //  Do not lock user 0 data for headless system user
        super.lockUserKey_enforcePermission();
    public void lockCeStorage(int userId) {
        super.lockCeStorage_enforcePermission();

        // Never lock the CE storage of a headless system user.
        if (userId == UserHandle.USER_SYSTEM
                && UserManager.isHeadlessSystemUserMode()) {
            throw new IllegalArgumentException("Headless system user data cannot be locked..");
        }


        if (!isUserKeyUnlocked(userId)) {
        if (!isCeStorageUnlocked(userId)) {
            Slog.d(TAG, "User " + userId + "'s CE storage is already locked");
            return;
        }

        try {
            mVold.lockUserKey(userId);
            mVold.lockCeStorage(userId);
        } catch (Exception e) {
            Slog.wtf(TAG, e);
            return;
@@ -3294,7 +3294,7 @@ class StorageManagerService extends IStorageManager.Stub
    }

    @Override
    public boolean isUserKeyUnlocked(int userId) {
    public boolean isCeStorageUnlocked(int userId) {
        synchronized (mLock) {
            return mCeUnlockedUsers.contains(userId);
        }
@@ -3681,8 +3681,8 @@ class StorageManagerService extends IStorageManager.Stub
        final int userId = UserHandle.getUserId(callingUid);
        final String propertyName = "sys.user." + userId + ".ce_available";

        // Ignore requests to create directories while storage is locked
        if (!isUserKeyUnlocked(userId)) {
        // Ignore requests to create directories while CE storage is locked
        if (!isCeStorageUnlocked(userId)) {
            throw new IllegalStateException("Failed to prepare " + appPath);
        }

@@ -3808,15 +3808,15 @@ class StorageManagerService extends IStorageManager.Stub
        final boolean systemUserUnlocked = isSystemUnlocked(UserHandle.USER_SYSTEM);

        final boolean userIsDemo;
        final boolean userKeyUnlocked;
        final boolean storagePermission;
        final boolean ceStorageUnlocked;
        final long token = Binder.clearCallingIdentity();
        try {
            userIsDemo = LocalServices.getService(UserManagerInternal.class)
                    .getUserInfo(userId).isDemo();
            storagePermission = mStorageManagerInternal.hasExternalStorage(callingUid,
                    callingPackage);
            userKeyUnlocked = isUserKeyUnlocked(userId);
            ceStorageUnlocked = isCeStorageUnlocked(userId);
        } finally {
            Binder.restoreCallingIdentity(token);
        }
@@ -3876,7 +3876,7 @@ class StorageManagerService extends IStorageManager.Stub
                } else if (!systemUserUnlocked) {
                    reportUnmounted = true;
                    Slog.w(TAG, "Reporting " + volId + " unmounted due to system locked");
                } else if ((vol.getType() == VolumeInfo.TYPE_EMULATED) && !userKeyUnlocked) {
                } else if ((vol.getType() == VolumeInfo.TYPE_EMULATED) && !ceStorageUnlocked) {
                    reportUnmounted = true;
                    Slog.w(TAG, "Reporting " + volId + "unmounted due to " + userId + " locked");
                } else if (!storagePermission && !realState) {
+2 −2
Original line number Diff line number Diff line
@@ -2249,7 +2249,7 @@ public class ActivityManagerService extends IActivityManager.Stub
            return;
        }
        // TODO(b/148767783): should we check all profiles under user0?
        UserspaceRebootLogger.logEventAsync(StorageManager.isUserKeyUnlocked(userId),
        UserspaceRebootLogger.logEventAsync(StorageManager.isCeStorageUnlocked(userId),
                BackgroundThread.getExecutor());
    }
@@ -4564,7 +4564,7 @@ public class ActivityManagerService extends IActivityManager.Stub
            // We carefully use the same state that PackageManager uses for
            // filtering, since we use this flag to decide if we need to install
            // providers when user is unlocked later
            app.setUnlocked(StorageManager.isUserKeyUnlocked(app.userId));
            app.setUnlocked(StorageManager.isCeStorageUnlocked(app.userId));
        }
        boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);
+15 −15
Original line number Diff line number Diff line
@@ -639,8 +639,8 @@ class UserController implements Handler.Callback {
        mInjector.getUserJourneyLogger()
                .logUserLifecycleEvent(userId, USER_LIFECYCLE_EVENT_UNLOCKING_USER,
                EVENT_STATE_BEGIN);
        // If the user key hasn't been unlocked yet, we cannot proceed.
        if (!StorageManager.isUserKeyUnlocked(userId)) return false;
        // If the user's CE storage hasn't been unlocked yet, we cannot proceed.
        if (!StorageManager.isCeStorageUnlocked(userId)) return false;
        synchronized (mLock) {
            // Do not proceed if unexpected state or a stale user
            if (mStartedUsers.get(userId) != uss || uss.state != STATE_RUNNING_LOCKED) {
@@ -655,8 +655,8 @@ class UserController implements Handler.Callback {

        // Call onBeforeUnlockUser on a worker thread that allows disk I/O
        FgThread.getHandler().post(() -> {
            if (!StorageManager.isUserKeyUnlocked(userId)) {
                Slogf.w(TAG, "User key got locked unexpectedly, leaving user locked.");
            if (!StorageManager.isCeStorageUnlocked(userId)) {
                Slogf.w(TAG, "User's CE storage got locked unexpectedly, leaving user locked.");
                return;
            }

@@ -690,8 +690,8 @@ class UserController implements Handler.Callback {
    private void finishUserUnlocked(final UserState uss) {
        final int userId = uss.mHandle.getIdentifier();
        EventLog.writeEvent(EventLogTags.UC_FINISH_USER_UNLOCKED, userId);
        // Only keep marching forward if user is actually unlocked
        if (!StorageManager.isUserKeyUnlocked(userId)) return;
        // Only keep marching forward if the user's CE storage is unlocked.
        if (!StorageManager.isCeStorageUnlocked(userId)) return;
        synchronized (mLock) {
            // Bail if we ended up with a stale user
            if (mStartedUsers.get(uss.mHandle.getIdentifier()) != uss) return;
@@ -777,8 +777,8 @@ class UserController implements Handler.Callback {
        if (userInfo == null) {
            return;
        }
        // Only keep marching forward if user is actually unlocked
        if (!StorageManager.isUserKeyUnlocked(userId)) return;
        // Only keep marching forward if the user's CE storage is unlocked.
        if (!StorageManager.isCeStorageUnlocked(userId)) return;

        // Remember that we logged in
        mInjector.getUserManager().onUserLoggedIn(userId);
@@ -1256,7 +1256,7 @@ class UserController implements Handler.Callback {
            }
            try {
                Slogf.i(TAG, "Locking CE storage for user #" + userId);
                mInjector.getStorageManager().lockUserKey(userId);
                mInjector.getStorageManager().lockCeStorage(userId);
            } catch (RemoteException re) {
                throw re.rethrowAsRuntimeException();
            }
@@ -1874,8 +1874,8 @@ class UserController implements Handler.Callback {
        }

        UserState uss;
        if (!StorageManager.isUserKeyUnlocked(userId)) {
            // We always want to try to unlock the user key, even if the user is not started yet.
        if (!StorageManager.isCeStorageUnlocked(userId)) {
            // We always want to try to unlock CE storage, even if the user is not started yet.
            mLockPatternUtils.unlockUserKeyIfUnsecured(userId);
        }
        synchronized (mLock) {
@@ -2662,10 +2662,10 @@ class UserController implements Handler.Callback {
                case UserState.STATE_RUNNING_UNLOCKING:
                case UserState.STATE_RUNNING_UNLOCKED:
                    return true;
                // In the stopping/shutdown state return unlock state of the user key
                // In the stopping/shutdown state, return unlock state of the user's CE storage.
                case UserState.STATE_STOPPING:
                case UserState.STATE_SHUTDOWN:
                    return StorageManager.isUserKeyUnlocked(userId);
                    return StorageManager.isCeStorageUnlocked(userId);
                default:
                    return false;
            }
@@ -2674,10 +2674,10 @@ class UserController implements Handler.Callback {
            switch (state.state) {
                case UserState.STATE_RUNNING_UNLOCKED:
                    return true;
                // In the stopping/shutdown state return unlock state of the user key
                // In the stopping/shutdown state, return unlock state of the user's CE storage.
                case UserState.STATE_STOPPING:
                case UserState.STATE_SHUTDOWN:
                    return StorageManager.isUserKeyUnlocked(userId);
                    return StorageManager.isCeStorageUnlocked(userId);
                default:
                    return false;
            }
Loading