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

Commit fc397ac0 authored by Rhed Jao's avatar Rhed Jao Committed by Automerger Merge Worker
Browse files

Merge "Create a verify flag to support verification for entering repair mode"...

Merge "Create a verify flag to support verification for entering repair mode" into udc-qpr-dev am: 92437274

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/23308665



Change-Id: I601a0af174a42b6bdaf6b5dbe70f060cd512a5b1
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents 107612b2 92437274
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -116,6 +116,17 @@ public class KeyguardManager {
    public static final String ACTION_CONFIRM_REMOTE_DEVICE_CREDENTIAL =
            "android.app.action.CONFIRM_REMOTE_DEVICE_CREDENTIAL";

    /**
     * Intent used to prompt user for device credential for entering repair
     * mode. If the credential is verified successfully, then the information
     * needed to verify the credential again will be written to a location that
     * is available to repair mode. This makes it possible for repair mode to
     * require that the same credential be provided to exit repair mode.
     * @hide
     */
    public static final String ACTION_PREPARE_REPAIR_MODE_DEVICE_CREDENTIAL =
            "android.app.action.PREPARE_REPAIR_MODE_DEVICE_CREDENTIAL";

    /**
     * A CharSequence dialog title to show to the user when used with a
     * {@link #ACTION_CONFIRM_DEVICE_CREDENTIAL}.
+43 −1
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@ import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.StorageManager;
@@ -160,9 +161,17 @@ public class LockPatternUtils {
     */
    public static final int VERIFY_FLAG_REQUEST_GK_PW_HANDLE = 1 << 0;

    /**
     * Flag provided to {@link #verifyCredential(LockscreenCredential, int, int)} . If set, the
     * method writes the password data to the repair mode file after the credential is verified
     * successfully.
     */
    public static final int VERIFY_FLAG_WRITE_REPAIR_MODE_PW = 1 << 1;

    @Retention(RetentionPolicy.SOURCE)
    @IntDef(flag = true, value = {
            VERIFY_FLAG_REQUEST_GK_PW_HANDLE
            VERIFY_FLAG_REQUEST_GK_PW_HANDLE,
            VERIFY_FLAG_WRITE_REPAIR_MODE_PW
    })
    public @interface VerifyFlag {}

@@ -201,6 +210,8 @@ public class LockPatternUtils {
    public static final String CURRENT_LSKF_BASED_PROTECTOR_ID_KEY = "sp-handle";
    public static final String PASSWORD_HISTORY_DELIMITER = ",";

    private static final String GSI_RUNNING_PROP = "ro.gsid.image_running";

    /**
     * drives the pin auto confirmation feature availability in code logic.
     */
@@ -1846,6 +1857,37 @@ public class LockPatternUtils {
                com.android.internal.R.bool.config_enableCredentialFactoryResetProtection);
    }

    /**
     * Return {@code true} if repair mode is supported by the device.
     */
    public static boolean isRepairModeSupported(Context context) {
        return context.getResources().getBoolean(
                com.android.internal.R.bool.config_repairModeSupported);
    }

    /**
     * Return {@code true} if repair mode is active on the device.
     */
    public static boolean isRepairModeActive(Context context) {
        return Settings.Global.getInt(context.getContentResolver(),
                Settings.Global.REPAIR_MODE_ACTIVE, /* def= */ 0) > 0;
    }

    /**
     * Return {@code true} if repair mode is supported by the device and the user has been granted
     * admin privileges.
     */
    public static boolean canUserEnterRepairMode(Context context, UserInfo info) {
        return info != null && info.isAdmin() && isRepairModeSupported(context);
    }

    /**
     * Return {@code true} if GSI is running on the device.
     */
    public static boolean isGsiRunning() {
        return SystemProperties.getInt(GSI_RUNNING_PROP, 0) > 0;
    }

    /**
     * Attempt to rederive the unified work challenge for the specified profile user and unlock the
     * user. If successful, this would allow the user to leave quiet mode automatically without
+19 −3
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STR
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE;
import static com.android.internal.widget.LockPatternUtils.USER_FRP;
import static com.android.internal.widget.LockPatternUtils.VERIFY_FLAG_REQUEST_GK_PW_HANDLE;
import static com.android.internal.widget.LockPatternUtils.VERIFY_FLAG_WRITE_REPAIR_MODE_PW;
import static com.android.internal.widget.LockPatternUtils.frpCredentialEnabled;
import static com.android.internal.widget.LockPatternUtils.userOwnsFrpCredential;
import static com.android.server.locksettings.SyntheticPasswordManager.TOKEN_TYPE_STRONG;
@@ -278,8 +279,6 @@ public class LockSettingsService extends ILockSettings.Stub {
    protected IGateKeeperService mGateKeeperService;
    protected IAuthSecret mAuthSecretService;

    private static final String GSI_RUNNING_PROP = "ro.gsid.image_running";

    /**
     * The UIDs that are used for system credential storage in keystore.
     */
@@ -311,6 +310,7 @@ public class LockSettingsService extends ILockSettings.Stub {
            if (phase == PHASE_ACTIVITY_MANAGER_READY) {
                mLockSettingsService.migrateOldDataAfterSystemReady();
                mLockSettingsService.loadEscrowData();
                mLockSettingsService.deleteRepairModePersistentDataIfNeeded();
            }
        }

@@ -541,7 +541,7 @@ public class LockSettingsService extends ILockSettings.Stub {
        }

        public boolean isGsiRunning() {
            return SystemProperties.getInt(GSI_RUNNING_PROP, 0) > 0;
            return LockPatternUtils.isGsiRunning();
        }

        public FingerprintManager getFingerprintManager() {
@@ -949,6 +949,16 @@ public class LockSettingsService extends ILockSettings.Stub {
        return success;
    }

    @VisibleForTesting
    void deleteRepairModePersistentDataIfNeeded() {
        if (!LockPatternUtils.isRepairModeSupported(mContext)
                || LockPatternUtils.isRepairModeActive(mContext)
                || mInjector.isGsiRunning()) {
            return;
        }
        mStorage.deleteRepairModePersistentData();
    }

    // This is called when Weaver is guaranteed to be available (if the device supports Weaver).
    // It does any synthetic password related work that was delayed from earlier in the boot.
    private void onThirdPartyAppsStarted() {
@@ -2202,6 +2212,12 @@ public class LockSettingsService extends ILockSettings.Stub {
            response = authResult.gkResponse;

            if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
                if ((flags & VERIFY_FLAG_WRITE_REPAIR_MODE_PW) != 0) {
                    if (!mSpManager.writeRepairModeCredentialLocked(protectorId, userId)) {
                        Slog.e(TAG, "Failed to write repair mode credential");
                        return VerifyCredentialResponse.ERROR;
                    }
                }
                // credential has matched
                mBiometricDeferredQueue.addPendingLockoutResetForUser(userId,
                        authResult.syntheticPassword.deriveGkPassword());
+50 −0
Original line number Diff line number Diff line
@@ -90,6 +90,9 @@ class LockSettingsStorage {

    private static final String SYNTHETIC_PASSWORD_DIRECTORY = "spblob/";

    private static final String REPAIR_MODE_DIRECTORY = "repair-mode/";
    private static final String REPAIR_MODE_PERSISTENT_FILE = "pst";

    private static final Object DEFAULT = new Object();

    private static final String[] SETTINGS_TO_BACKUP = new String[] {
@@ -390,6 +393,29 @@ class LockSettingsStorage {
        }
    }

    @VisibleForTesting
    File getRepairModePersistentDataFile() {
        final File directory = new File(Environment.getMetadataDirectory(), REPAIR_MODE_DIRECTORY);
        return new File(directory, REPAIR_MODE_PERSISTENT_FILE);
    }

    public PersistentData readRepairModePersistentData() {
        final byte[] data = readFile(getRepairModePersistentDataFile());
        if (data == null) {
            return PersistentData.NONE;
        }
        return PersistentData.fromBytes(data);
    }

    public void writeRepairModePersistentData(int persistentType, int userId, byte[] payload) {
        writeFile(getRepairModePersistentDataFile(),
                PersistentData.toBytes(persistentType, userId, /* qualityForUi= */0, payload));
    }

    public void deleteRepairModePersistentData() {
        deleteFile(getRepairModePersistentDataFile());
    }

    /**
     * Writes the synthetic password state file for the given user ID, protector ID, and state name.
     * If the file already exists, then it is atomically replaced.
@@ -583,6 +609,17 @@ class LockSettingsStorage {
        }
    }

    /**
     * Provides a concrete data structure to represent the minimal information from
     * a user's LSKF-based SP protector that is needed to verify the user's LSKF,
     * in combination with the corresponding Gatekeeper enrollment or Weaver slot.
     * It can be stored in {@link com.android.server.PersistentDataBlockService} for
     * FRP to live across factory resets not initiated via the Settings UI.
     * Written to {@link #REPAIR_MODE_PERSISTENT_FILE} to support verification for
     * exiting repair mode, since the device runs with an empty data partition in
     * repair mode and the same credential be provided to exit repair mode is
     * required.
     */
    public static class PersistentData {
        static final byte VERSION_1 = 1;
        static final int VERSION_1_HEADER_SIZE = 1 + 1 + 4 + 4;
@@ -685,6 +722,19 @@ class LockSettingsStorage {
            }
            pw.decreaseIndent();
        }
        // Dump repair mode file states
        final File repairModeFile = getRepairModePersistentDataFile();
        if (repairModeFile.exists()) {
            pw.println(TextUtils.formatSimple("Repair Mode [%s]:", repairModeFile.getParent()));
            pw.increaseIndent();
            pw.println(TextUtils.formatSimple("%6d %s %s", repairModeFile.length(),
                    LockSettingsService.timestampToString(repairModeFile.lastModified()),
                    repairModeFile.getName()));
            final PersistentData data = readRepairModePersistentData();
            pw.println(TextUtils.formatSimple("type: %d, user id: %d, payload size: %d",
                    data.type, data.userId, data.payload != null ? data.payload.length : 0));
            pw.decreaseIndent();
        }
    }

    static class DatabaseHelper extends SQLiteOpenHelper {
+51 −0
Original line number Diff line number Diff line
@@ -1114,6 +1114,57 @@ class SyntheticPasswordManager {
        }
    }

    /**
     * Writes the user's synthetic password data to the repair mode file.
     *
     * @param protectorId current LSKF based protectorId
     * @param userId user id of the user
     */
    public boolean writeRepairModeCredentialLocked(long protectorId, int userId) {
        if (!shouldWriteRepairModeCredential(userId)) {
            return false;
        }
        final byte[] data = loadState(PASSWORD_DATA_NAME, protectorId, userId);
        if (data == null) {
            Slogf.w(TAG, "Password data not found for user %d", userId);
            return false;
        }
        final PasswordData pwd = PasswordData.fromBytes(data);
        if (isNoneCredential(pwd)) {
            Slogf.w(TAG, "User %d has NONE credential", userId);
            return false;
        }
        Slogf.d(TAG, "Writing repair mode credential tied to user %d", userId);
        final int weaverSlot = loadWeaverSlot(protectorId, userId);
        if (weaverSlot != INVALID_WEAVER_SLOT) {
            // write weaver password
            mStorage.writeRepairModePersistentData(
                    PersistentData.TYPE_SP_WEAVER, weaverSlot, pwd.toBytes());
        } else {
            // write gatekeeper password
            mStorage.writeRepairModePersistentData(
                    PersistentData.TYPE_SP_GATEKEEPER, userId, pwd.toBytes());
        }
        return true;
    }

    private boolean shouldWriteRepairModeCredential(int userId) {
        final UserInfo userInfo = mUserManager.getUserInfo(userId);
        if (!LockPatternUtils.canUserEnterRepairMode(mContext, userInfo)) {
            Slogf.w(TAG, "User %d can't enter repair mode", userId);
            return false;
        }
        if (LockPatternUtils.isRepairModeActive(mContext)) {
            Slog.w(TAG, "Can't write repair mode credential while repair mode is already active");
            return false;
        }
        if (LockPatternUtils.isGsiRunning()) {
            Slog.w(TAG, "Can't write repair mode credential while GSI is running");
            return false;
        }
        return true;
    }

    private ArrayMap<Integer, ArrayMap<Long, TokenData>> tokenMap = new ArrayMap<>();

    /**
Loading