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

Commit d9522409 authored by Rubin Xu's avatar Rubin Xu
Browse files

Kill off untrusted password reset

Time has come that we can finally ditch untrusted password reset i.e.
changing lockscreen password without providing the existing password or
an activiated password reset token. In this change, we are:

1. Preventing any DPC / legacy device admin from invoking
DPM.resetPassword(), the primary route to invoke untrusted password
reset. Depending on their target SDK level, resetPassword() will either
throw SecurityException, or fail silently.
2. Still allowing privilleged app holding RESET_PASSWORD permission to
call this API, but it's limited to setting a new passowrd on an
unsecured device.
3. Removing synthetic password caching mechanism in LockSettingsService,
whose sole purpose was to support untrusted password reset.

Bug: 137939224
Test: atest com.android.server.locksettings
Test: atest com.android.server.devicepolicy.DevicePolicyManagerTest
Change-Id: Ie3e5e277984b6fc2f1d378880363028752bad775
parent 43429e77
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -6828,7 +6828,7 @@ package android.app.admin {
    method public boolean removeOverrideApn(@NonNull android.content.ComponentName, int);
    method public boolean removeUser(@NonNull android.content.ComponentName, @NonNull android.os.UserHandle);
    method public boolean requestBugreport(@NonNull android.content.ComponentName);
    method public boolean resetPassword(String, int);
    method @Deprecated public boolean resetPassword(String, int);
    method public boolean resetPasswordWithToken(@NonNull android.content.ComponentName, String, byte[], int);
    method @Nullable public java.util.List<android.app.admin.NetworkEvent> retrieveNetworkLogs(@Nullable android.content.ComponentName, long);
    method @Nullable public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrievePreRebootSecurityLogs(@NonNull android.content.ComponentName);
+33 −18
Original line number Diff line number Diff line
@@ -3742,17 +3742,35 @@ public class DevicePolicyManager {
    /**
     * Force a new password for device unlock (the password needed to access the entire device) or
     * the work profile challenge on the current user. This takes effect immediately.
     * <p>
     * <em>For device owner and profile owners targeting SDK level
     * {@link android.os.Build.VERSION_CODES#O} or above, this API is no longer available and will
     * throw {@link SecurityException}. Please use the new API {@link #resetPasswordWithToken}
     * instead. </em>
     * <p>
     * <em>Note: This API has been limited as of {@link android.os.Build.VERSION_CODES#N} for
     * device admins that are not device owner and not profile owner.
     * The password can now only be changed if there is currently no password set.  Device owner
     * and profile owner can still do this when user is unlocked and does not have a managed
     * profile.</em>
     *
     * <p> Before {@link android.os.Build.VERSION_CODES#N}, this API is available to device admin,
     * profile owner and device owner. Starting from {@link android.os.Build.VERSION_CODES#N},
     * legacy device admin (who is not also profile owner or device owner) can only call this
     * API to set a new password if there is currently no password set. Profile owner and device
     * owner can continue to force change an existing password as long as the target user is
     * unlocked, although device owner will not be able to call this API at all if there is also a
     * managed profile on the device.
     *
     * <p> Between {@link android.os.Build.VERSION_CODES#O},
     * {@link android.os.Build.VERSION_CODES#P} and {@link android.os.Build.VERSION_CODES#Q},
     * profile owner and devices owner targeting SDK level {@link android.os.Build.VERSION_CODES#O}
     * or above who attempt to call this API will receive {@link SecurityException}; they are
     * encouraged to migrate to the new {@link #resetPasswordWithToken} API instead.
     * Profile owner and device owner targeting older SDK levels are not affected: they continue
     * to experience the existing behaviour described in the previous paragraph.
     *
     * <p><em>Starting from {@link android.os.Build.VERSION_CODES#R}, this API is no longer
     * supported in most cases.</em> Device owner and profile owner calling
     * this API will receive {@link SecurityException} if they target SDK level
     * {@link android.os.Build.VERSION_CODES#O} or above, or they will receive a silent failure
     * (API returning {@code false}) if they target lower SDK level.
     * For legacy device admins, this API throws {@link SecurityException} if they target SDK level
     * {@link android.os.Build.VERSION_CODES#N} or above, and returns {@code false} otherwise. Only
     * privileged apps holding RESET_PASSWORD permission which are part of
     * the system factory image can still call this API to set a new password if there is currently
     * no password set. In this case, if the device already has a password, this API will throw
     * {@link SecurityException}.
     *
     * <p>
     * The given password must be sufficient for the current password quality and length constraints
     * as returned by {@link #getPasswordQuality(ComponentName)} and
@@ -3760,12 +3778,7 @@ public class DevicePolicyManager {
     * it will be rejected and false returned. Note that the password may be a stronger quality
     * (containing alphanumeric characters when the requested quality is only numeric), in which
     * case the currently active quality will be increased to match.
     * <p>
     * Calling with a null or empty password will clear any existing PIN, pattern or password if the
     * current password constraints allow it. <em>Note: This will not work in
     * {@link android.os.Build.VERSION_CODES#N} and later for managed profiles, or for device admins
     * that are not device owner or profile owner.  Once set, the password cannot be changed to null
     * or empty except by these admins.</em>
     *
     * <p>On devices not supporting {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature, this
     * methods does nothing.
     * <p>
@@ -3777,11 +3790,13 @@ public class DevicePolicyManager {
     * @param flags May be 0 or combination of {@link #RESET_PASSWORD_REQUIRE_ENTRY} and
     *            {@link #RESET_PASSWORD_DO_NOT_ASK_CREDENTIALS_ON_BOOT}.
     * @return Returns true if the password was applied, or false if it is not acceptable for the
     *         current constraints or if the user has not been decrypted yet.
     *         current constraints.
     * @throws SecurityException if the calling application does not own an active administrator
     *             that uses {@link DeviceAdminInfo#USES_POLICY_RESET_PASSWORD}
     * @throws IllegalStateException if the calling user is locked or has a managed profile.
     * @deprecated Please use {@link #resetPasswordWithToken} instead.
     */
    @Deprecated
    @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
    public boolean resetPassword(String password, int flags) {
        throwIfParentInstance("resetPassword");
+0 −9
Original line number Diff line number Diff line
@@ -144,15 +144,6 @@ public abstract class DevicePolicyManagerInternal {
     */
    public abstract void reportSeparateProfileChallengeChanged(@UserIdInt int userId);

    /**
     * Check whether the user could have their password reset in an untrusted manor due to there
     * being an admin which can call {@link #resetPassword} to reset the password without knowledge
     * of the previous password.
     *
     * @param userId The user in question
     */
    public abstract boolean canUserHaveUntrustedCredentialReset(@UserIdInt int userId);

    /**
     * Return text of error message if printing is disabled.
     * Called by Print Service when printing is disabled by PO or DO when printing is attempted.
+1 −1
Original line number Diff line number Diff line
@@ -43,7 +43,7 @@ interface ILockSettings {
    long getLong(in String key, in long defaultValue, in int userId);
    @UnsupportedAppUsage
    String getString(in String key, in String defaultValue, in int userId);
    boolean setLockCredential(in LockscreenCredential credential, in LockscreenCredential savedCredential, int userId, boolean allowUntrustedChange);
    boolean setLockCredential(in LockscreenCredential credential, in LockscreenCredential savedCredential, int userId);
    void resetKeyStore(int userId);
    VerifyCredentialResponse checkCredential(in LockscreenCredential credential, int userId,
            in ICheckCredentialProgressCallback progressCallback);
+5 −25
Original line number Diff line number Diff line
@@ -636,35 +636,16 @@ public class LockPatternUtils {
     *
     * @param newCredential The new credential to save
     * @param savedCredential The current credential
     * @param userId the user whose lockscreen credential is to be changed
     *
     * @return whether this method saved the new password successfully or not. This flow will fail
     * and return false if the given credential is wrong.
     * @throws RuntimeException if password change encountered an unrecoverable error.
     */
    public boolean setLockCredential(@NonNull LockscreenCredential newCredential,
            @NonNull LockscreenCredential savedCredential, int userId) {
        return setLockCredential(newCredential, savedCredential, userId, false);
    }

    /**
     * Save a new lockscreen credential.
     * <p> This method will fail (returning {@code false}) if the previously saved pattern provided
     * is incorrect and allowUntrustedChange is false, or if the lockscreen verification is still
     * being throttled.
     * @param newCredential The new credential to save
     * @param savedCredential The current credential
     * @param userHandle the user whose lockscreen credential is to be changed
     * @param allowUntrustedChange whether we want to allow saving a new pattern if the existing
     * credentialt being provided is incorrect.
     *
     * @return whether this method saved the new password successfully or not. This flow will fail
     * and return false if the given credential is wrong and allowUntrustedChange is false.
     * and return false if the given credential is wrong.
     * @throws RuntimeException if password change encountered an unrecoverable error.
     * @throws UnsupportedOperationException secure lockscreen is not supported on this device.
     * @throws IllegalArgumentException if new credential is too short.
     */
    public boolean setLockCredential(@NonNull LockscreenCredential newCredential,
            @NonNull LockscreenCredential savedCredential, int userHandle,
            boolean allowUntrustedChange) {
            @NonNull LockscreenCredential savedCredential, int userHandle) {
        if (!hasSecureLockScreen()) {
            throw new UnsupportedOperationException(
                    "This operation requires the lock screen feature.");
@@ -672,8 +653,7 @@ public class LockPatternUtils {
        newCredential.checkLength();

        try {
            if (!getLockSettings().setLockCredential(
                    newCredential, savedCredential, userHandle, allowUntrustedChange)) {
            if (!getLockSettings().setLockCredential(newCredential, savedCredential, userHandle)) {
                return false;
            }
        } catch (RemoteException e) {
Loading