A corrupt lock file can crash at boot, and a lockout that cannot be signed vanishes #64
Labels
No Label
P0
P1
P2
release-blocker
No Milestone
No project
No Assignees
1 Participants
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: null/Privacy-Period-Tracker#64
Loading…
Reference in New Issue
No description provided.
Delete Branch "%!s(<nil>)"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What is true now.
core/security/.../AppLockRepository.kt:81exposeshasPinasstore.data.map { ... }with NO.catch, unlikeUserPreferencesRepository.preferences(core/datastore/.../UserPreferencesRepository.kt:36) which swallowsIOExceptionand emits defaults. It is collected in two places with no handler:AppLockViewModel.kt:85-94(combine(...).stateIn(viewModelScope, ...)—stateInlaunches without theCoroutineExceptionHandlerdeclared at:103) andMainActivity.kt:83(appLock.hasPin.collect(::applySecureFlag)inlifecycleScope). An unreadable or corruptapp_lockfile therefore propagates out of both — on the startup path, before any UI.Separately,
writeLockout(:182-189) doesrunCatching { macOf(blob) }.getOrNull() ?: return— when the counter cannot be signed, the failed attempt is silently not recorded, so wrong PINs stop costing time.What to do. Give the lock flows the same
.catch { if (it is IOException) emit(empty) else throw it }treatment, add aReplaceFileCorruptionHandlerto theapp_lockDataStore, and routeMainActivity/AppLockViewModelthrough flows that cannot throw. Decide and document the safe reading of a corrupt lock file: it should read as NO LOCK (the app opens) rather than as a lock nobody can open — the same policyVerifierRecord.decodealready applies to a corrupt record (:73-82), on the reasoning that whoever can corrupt that file can read the database anyway, and the alternative bricks the app with the erase hatch also broken. For the lockout write, fail closed for the process rather than silently forgetting the attempt.Traps. Without the corruption handler, a corrupt file makes every later
editfail too — the lock can never be set again and the 'Forgot your PIN?' erase itself fails. Do not log anything on these paths:appandcore/securityare both inmodulesSeeingHealthDataandcheckNoHealthLoggingforbids every logging call.Verify:
an unreadable lock file reads as off rather than crashinganda corrupt lock file is replaced so a lock can be set againinAppLockRepositoryTest, plusa failed attempt still costs time in this process when its counter cannot be signed.