init/luks: dispatch PIN-bearing tokens serially in token-ID order#353
Merged
Conversation
Two PIN-bearing tokens (e.g. TPM2-PIN and FIDO2-PIN) enrolled to the same volume are already serialized by inputMutex (and fido2Mu), so prompts queue rather than overlap. The remaining issue is ordering — parallel goroutines race to grab the mutex, so the user sees prompts in non-deterministic order each boot. With more than one PIN method this is confusing: a user who enrolled TPM2 first as their preferred unlock can't tell which boot will actually prompt for it first. Classify tokens up front: PIN-bearing tokens (TPM2 with tpm2-pin or FIDO2 with fido2-clientPin-required) collect into a pinTokens slice; everything else fans out as today. A single goroutine then walks pinTokens in slice order — already sorted by ID via the sort.Slice in luksOpen — calling recoverTokenPassword serially. A skipped token advances to the next; a successful unlock closes done and stops the loop. Non-PIN tokens are unaffected and still run in parallel. The done check before each PIN iteration also lets a parallel non-PIN unlock cancel the loop without waiting on the next prompt to time out.
Cover tokenNeedsPin's JSON classification (TPM2 with/without tpm2-pin, FIDO2 with/without fido2-clientPin-required, malformed payloads, unrelated token types) and the PIN-token serial loop semantics: - ordering: PIN tokens run in slice order, fully completing each before starting the next - short-circuit: a successful PIN unlock stops trailing PIN tokens - parallelism: non-PIN tokens fan out independently of the PIN loop - cancellation: a non-PIN success closes done and the PIN loop exits without dispatching the next prompt - skip-advances-loop: returns(false) (the errTPM2Skipped / errFido2FallbackToKeyboard path) lets the next PIN token run - sort determinism: shuffled input sorted by ID dispatches in ascending ID order The production loop is mirrored by runPinTokens so it can be exercised without real LUKS devices, swtpm, or hardware tokens. init and generator tests pass.
Owner
|
Thank you! |
pilotstew
added a commit
to pilotstew/booster
that referenced
this pull request
May 14, 2026
Adds a new NOTES subsection covering the concurrent-unlock model that landed across PRs anatol#350, anatol#353, anatol#355, anatol#356, anatol#357, anatol#358, and anatol#362: PIN-token serialization in ascending LUKS2 token-ID order, cancel-on-win semantics for keyboard/FIDO2-PIN/TPM2-PIN prompts on both the console and the Plymouth splash (with the MR !393 caveat for older Plymouth builds), and the per-token 3-attempt PIN cap with empty-PIN skip. Trims two paragraphs from the existing 'Password entry' subsection (auto-dismiss and PIN attempts) now that the new section covers them in fuller context. 'Password entry' keeps the Ctrl+W / Ctrl+U / Tab edit-key reference.
anatol
pushed a commit
that referenced
this pull request
May 14, 2026
Adds a new NOTES subsection covering the concurrent-unlock model that landed across PRs #350, #353, #355, #356, #357, #358, and #362: PIN-token serialization in ascending LUKS2 token-ID order, cancel-on-win semantics for keyboard/FIDO2-PIN/TPM2-PIN prompts on both the console and the Plymouth splash (with the MR !393 caveat for older Plymouth builds), and the per-token 3-attempt PIN cap with empty-PIN skip. Trims two paragraphs from the existing 'Password entry' subsection (auto-dismiss and PIN attempts) now that the new section covers them in fuller context. 'Password entry' keeps the Ctrl+W / Ctrl+U / Tab edit-key reference.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two PIN-bearing tokens (e.g. TPM2-PIN and FIDO2-PIN) enrolled to the same volume are already serialized by
inputMutex(andfido2Mu), so prompts queue rather than overlap. The remaining issue is ordering — parallel goroutines race to grab the mutex, so the user sees prompts in non-deterministic order each boot. With more than one PIN method this is confusing: a user who enrolled TPM2 first as their preferred unlock can't tell which boot will actually prompt for it first.Change
Classify tokens up front in
luksOpen:tpm2-pin, FIDO2 withfido2-clientPin-required) collect into apinTokensslice.A single goroutine then walks
pinTokensin slice order — already sorted by ID via thesort.SliceinluksOpen— callingrecoverTokenPasswordserially. A skipped/failed token advances to the next; a successful unlock closesdoneand stops the loop.The
donecheck before each PIN iteration also lets a parallel non-PIN unlock cancel the loop without waiting on the next prompt to time out.New predicate
tokenNeedsPin(t luks.Token) boolparses the token payload JSON to determine dispatch group. Returns false for malformed payloads, missing fields, and unrelated token types so behaviour falls through to today's parallel path on any classification doubt.Tests
init/token_orchestration_test.go:TestTokenNeedsPin— table-driven JSON classification across both typesrunPinTokensdoes NOT sort — sorting isluksOpen's responsibilityThe production loop is mirrored by
runPinTokensso it can be exercised without real LUKS devices, swtpm, or hardware tokens.