CVE-2023-21267 AI-generated analysis
platform/frameworks/base, SystemUI keyguard (KeyguardViewMediator) and core LockPatternUtils
Makes SystemUI's KeyguardViewMediator show (and refuse to hide) the keyguard when the current user is in lockdown, even if an app has externally disabled the keyguard. It also fixes LockPatternUtils.isUserInLockdown so that it still detects lockdown when other strong-auth flags are set.
Root cause
In packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java, doKeyguardLocked() returned early ("not showing because externally disabled") whenever mExternallyEnabled was false. setKeyguardEnabled(false) also hid an already showing keyguard. Neither path checked whether the user had triggered lockdown. The mediator also did not react to strong-auth state changes. The commit's manual test (app pinning with "Ask for PIN before unpinning" disabled, then Lockdown from the power menu) expects the keyguard to appear and require primary authentication. Separately, core/java/com/android/internal/widget/LockPatternUtils.java isUserInLockdown() compared getStrongAuthForUser(userId) for equality with STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN. It therefore returned false whenever another strong-auth flag (e.g. STRONG_AUTH_REQUIRED_AFTER_LOCKOUT) was also set, which defeated the new lockdown checks in those states.
How the fix works
- Commit cecddcd865f7 (android-security-14.0.0_r3) reverts the earlier attempt c851ef6d27bf ('On device lockdown, always show the keyguard') because of regression b/300463732. It removes the onStrongAuthStateChanged override in KeyguardViewMediator.java, restores doKeyguardLocked() to 'if (!mExternallyEnabled)', and deletes the test onLockdown_showKeyguard_evenIfKeyguardIsNotEnabledExternally and its captor from KeyguardViewMediatorTest.java.
- Commit cb7e9c7549a2 (android-security-14.0.0_r3), KeyguardViewMediator.java, KeyguardUpdateMonitorCallback.onStrongAuthStateChanged(int userId): a new override calls doKeyguardLocked(null) when mLockPatternUtils.isUserInLockdown(KeyguardUpdateMonitor.getCurrentUser()) is true.
- Same commit, KeyguardViewMediator.java, setKeyguardEnabled(boolean enabled): in the '!enabled && mShowing' branch, if the current user is in lockdown, it logs 'keyguardEnabled(false) overridden by user lockdown' and returns before hiding the keyguard. mExternallyEnabled has already been set to false at that point.
- Same commit, KeyguardViewMediator.java, doKeyguardLocked(Bundle options): the early return for an externally disabled keyguard now requires '!mExternallyEnabled && !mLockPatternUtils.isUserInLockdown(KeyguardUpdateMonitor.getCurrentUser())'.
- Commit e205cd30e91d (android-security-14.0.0_r7), core/java/com/android/internal/widget/LockPatternUtils.java, isUserInLockdown(int userId): changes '== STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN' to '(flags & STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN) != 0'. It adds LockPatternUtilsTest.isUserInLockDown, which covers NOT_REQUIRED, LOCKDOWN alone, and LOCKDOWN | LOCKOUT.
Completeness
- Covers three sites in KeyguardViewMediator: the show decision in doKeyguardLocked, the hide in setKeyguardEnabled(false) while showing, and a new trigger on strong-auth change (onStrongAuthStateChanged).
- cb7e9c7549a2 relies on LockPatternUtils.isUserInLockdown, which used an equality compare. Lockdown combined with another strong-auth flag (e.g. lockout) would therefore not have been detected by these checks until e205cd30e91d (14.0.0_r7).
- onStrongAuthStateChanged ignores its userId parameter and checks lockdown for KeyguardUpdateMonitor.getCurrentUser() on every strong-auth change.
- The diffstat of cb7e9c7549a2 shows only KeyguardViewMediator.java changed. The regression test removed by the revert is not re-added in that commit, even though the commit message cites atest KeyguardViewMediatorTest. At android-security-14.0.0_r29 the test file declares mKeyguardUpdateMonitorCallbackCaptor again, but the commit that restored it is not in the material.
- The material does not show whether other keyguard-suppression paths exist beyond the three sites changed.
Behavior changes
- While the current user is in lockdown, the keyguard is shown even if an app has disabled it (e.g. app pinning without PIN-before-unpinning). Per the commit's test steps, the pinned state persists after a correct credential and the keyguard stays after an incorrect one.
- setKeyguardEnabled(false) called while the keyguard is showing and the user is in lockdown no longer hides it. A 'keyguardEnabled(false) overridden by user lockdown' log is emitted.
- A strong-auth state change now triggers doKeyguardLocked(null) when the current user is in lockdown.
- LockPatternUtils.isUserInLockdown now returns true for any strong-auth value containing STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN. This affects every caller of that method, not only KeyguardViewMediator.
Per major
- Android 14: Same fix: revert cecddcd865f7 plus updated fix cb7e9c7549a2 in android-security-14.0.0_r3, then the LockPatternUtils bitmask fix e205cd30e91d in android-security-14.0.0_r7. At android-security-14.0.0_r29, 6/8 lines of the patched region are present. The r29 context shows onStrongAuthStateChanged calling mUpdateMonitor.isUserInLockdown(...) instead of mLockPatternUtils.isUserInLockdown(...), and LockPatternUtils.isUserInLockdown in the bitmask form. The material does not identify exactly which lines differ.
- Android 15: Not affected per the bulletin. Patched region present 8/8 at android-security-15.0.0_r17.
- Android 16: Not affected per the bulletin. Patched region present 8/8 at android-security-16.0.0_r8.
- Android 17: Not affected per the bulletin. Patched region present 8/8 at android-security-17.0.0_r1.
Unknowns
- The original commit c851ef6d27bf and the nature of regression b/300463732 are not in the material. Only the revert diff shows what c851ef6d27bf contained.
- The exact disclosure scenario beyond the commit's manual test and the bulletin's ID rating is not stated.
- Whether a KeyguardViewMediatorTest regression test was re-added, and in which commit.
- The implementation of KeyguardUpdateMonitor.isUserInLockdown used at android-security-14.0.0_r29 is not shown.
- Which lines of the patched region account for the 6/8 match at android-security-14.0.0_r29.
- What power-menu Lockdown sets in the strong-auth state, and whether setKeyguardEnabled's skipped block sets mNeedToReshowWhenReenabled.