Skip to content

Bugfix: Fix TPM auth retry, counter error handling, and NV error surfacing#2099

Merged
tlaurion merged 5 commits into
linuxboot:masterfrom
tlaurion:bugfix-tpm_increment_on_seal
May 6, 2026
Merged

Bugfix: Fix TPM auth retry, counter error handling, and NV error surfacing#2099
tlaurion merged 5 commits into
linuxboot:masterfrom
tlaurion:bugfix-tpm_increment_on_seal

Conversation

@tlaurion
Copy link
Copy Markdown
Collaborator

@tlaurion tlaurion commented May 5, 2026

This PR fixes regressions introduced by PR #2068, merged to origin/master on 2026-04-07.

Regressions fixed (present in origin/master post-PR #2068):

  • PCR-5 extension causes DUK unseal failure: Unconditional enable_usb and detect_usb_security_dongle_branding in gui-init.sh loaded USB modules (ehci-hcd, xhci-hcd, etc.) during early boot, extending PCR-5. kexec-seal-key.sh predicts PCR-5 = 0 for DUK seal, causing "Error PCR mismatch from TPM_Unseal" (exit code 24 = 0x18 = TPM_RC_PCR_MISMATCH).
  • No "out of resources" (0x15) TPM counter error detection
  • TPM2 counter increment had no auth retry on wrong passphrase
  • TPM1 counter increment had no error handling
  • tpm1_seal silenced NV define/write errors
  • Duplicate TPM1/TPM2 retry loops (~100 lines of redundant code)
  • counter_present dead code (now fixed with counter_read check)
  • Comment mismatch (stdout vs console) now fixed
  • set -e issue in check_tpm_counter (wrapped in subshell)

Fixes implemented:

PCR-5 / DUK unseal fix (commits 3-4):

  • Gate USB initialization: Move enable_usb and detect_usb_security_dongle_branding inside if [ -x /bin/hotp_verification ] in gui-init.sh so non-HOTP boards don't load USB modules during early boot
    • Non-HOTP boards: PCR-5 stays at 0, DUK unseal works correctly
    • HOTP boards: USB still initialized early (required for dongle interaction), but only once (gated by _USB_ENABLED flag)
  • Export _USB_ENABLED: Child processes (seal-hotpkey.sh, kexec-seal-key.sh, etc.) now inherit the flag and don't reload USB modules
  • Add DEBUG logging to enable_usb() per doc/logging.md conventions
  • Add enable_usb to wait_for_gpg_card() to ensure USB is ready before GPG card access

TPM auth retry / counter error handling (commits 1-2):

  • Add shared _tpm_auth_retry helper for TPM1/TPM2
  • check_tpm_counter only triggers tpm_reset_required on 0x15 errors
  • tpm1_seal surfaces NV errors with retry loop
  • Simplify reset_tpm to verify tpmr.sh reset exit code
  • Fix tpmr.sh counter_create to detect "out of resources" (0x15) and surface proper error

Docs: unify script name references (commit 2):

  • Update all initrd/bin/* and initrd/etc/* references in doc/* to use .sh extension

Testing: (reseal TOTP+HOTP+DUK, TPM Reset + DUK sealing, OEM Factory Reset/Re-Ownership)

  • QEMU TPM1 with HOTP: firmware "upgrade" (reseal TOTP+HOTP+DUK) + reownership
  • QEMU TPM1 without HOTP: firmware "upgrade" (reseal TOTP+DUK)
  • QEMU TPM2 with HOTP: firmware "upgrade" (reseal TOTP+HOTP+DUK)
  • QEMU TPM2 without HOTP: firmware "upgrade" (reseal TOTP+DUK) + reownerhip
  • v540tu (tpm2 real hw)
  • x230 (tpm1 real hw) : hotp/non-hotp

Copilot AI review requested due to automatic review settings May 5, 2026 18:31
@tlaurion tlaurion changed the title Bugfix: Fix TPM auth retry, counter error handling, and NV error surf… Bugfix: Fix TPM auth retry, counter error handling, and NV error surfacing May 5, 2026
@tlaurion tlaurion linked an issue May 5, 2026 that may be closed by this pull request
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses TPM regressions introduced in PR #2068 by reworking TPM counter creation/increment error handling and auth retry behavior, and updating GUI flows/docs to surface TPM reset-required states more clearly.

Changes:

  • Add shared TPM auth-retry helper logic and refactor TPM1/TPM2 counter operations in tpmr.sh.
  • Improve rollback counter creation/increment handling and propagate TPM “out of resources (0x15)” into a tpm_reset_required marker + targeted UX.
  • Update GUI flows and documentation to support “Reset the TPM” gate-bypass patterns and clearer recovery guidance.

Reviewed changes

Copilot reviewed 4 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
initrd/etc/gui_functions.sh Exit integrity investigation loop when update_checksums triggers tpm_reset_required.
initrd/etc/functions.sh Detect TPM 0x15 on counter_create and adjust TPM counter increment plumbing.
initrd/bin/tpmr.sh Introduce _tpm_auth_retry, refactor TPM counter ops, and surface TPM1 stdout quirks.
initrd/bin/gui-init.sh Improve UX around checksum update failure and gate bypass for TPM reset; verify TPM reset result.
doc/ux-patterns.md Document the reset gate-bypass UX pattern.
doc/tpm.md Document 0x15 recovery behavior and TPM1 stdout behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread doc/tpm.md Outdated
Comment thread initrd/etc/functions.sh
@tlaurion tlaurion marked this pull request as draft May 5, 2026 19:08
@tlaurion tlaurion force-pushed the bugfix-tpm_increment_on_seal branch from 35fa6b0 to d76d01c Compare May 5, 2026 21:25
@tlaurion tlaurion requested a review from Copilot May 5, 2026 21:25
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 13 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

initrd/etc/functions.sh:1901

  • The comment above the counter_increment pipeline says stdout is captured “while still letting stdout appear on the console”, but the current pipeline ends with tee /tmp/counter-... >/dev/null, which discards stdout from the console entirely. Either update the comment to match the behavior, or adjust the pipeline if the intent really is to keep stdout visible to the user.
	# Try to increment the counter.  We normally hide the verbose
	# output of tpmr.sh commands to avoid overwhelming the console, but we
	# must *not* swallow any interactive prompts.  The previous implementation
	# redirected the entire `tpmr.sh counter_create` invocation to a file and
	# /dev/null, which meant that when the counter was missing the password
	# prompt could not be seen by the user even though tpmr.sh printed it to the
	# controlling terminal.  Instead, capture just the stdout in a temporary
	# file while still letting stdout appear on the console (and logging
	# stderr to debug log).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@tlaurion tlaurion force-pushed the bugfix-tpm_increment_on_seal branch from d76d01c to 9241c16 Compare May 5, 2026 21:50
@tlaurion tlaurion requested a review from Copilot May 5, 2026 22:00
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 13 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (1)

initrd/etc/functions.sh:1901

  • The comment above the counter increment pipeline says stdout is captured “while still letting stdout appear on the console”, but the actual pipeline sends stdout into tee ... >/dev/null, which suppresses console output. Either adjust the redirection to match the comment (if console output is desired) or update the comment to reflect that stdout is intentionally hidden and only logged/stored.
	# Try to increment the counter.  We normally hide the verbose
	# output of tpmr.sh commands to avoid overwhelming the console, but we
	# must *not* swallow any interactive prompts.  The previous implementation
	# redirected the entire `tpmr.sh counter_create` invocation to a file and
	# /dev/null, which meant that when the counter was missing the password
	# prompt could not be seen by the user even though tpmr.sh printed it to the
	# controlling terminal.  Instead, capture just the stdout in a temporary
	# file while still letting stdout appear on the console (and logging
	# stderr to debug log).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread doc/tpm.md Outdated
Comment thread doc/tpm.md Outdated
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 13 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread doc/tpm.md Outdated
Comment thread doc/tpm.md
Comment thread initrd/etc/functions.sh Outdated
@tlaurion tlaurion force-pushed the bugfix-tpm_increment_on_seal branch from a88ee0e to 73b1916 Compare May 5, 2026 23:27
@tlaurion tlaurion requested a review from Copilot May 5, 2026 23:27
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 4 changed files in this pull request and generated no new comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@tlaurion tlaurion marked this pull request as ready for review May 5, 2026 23:34
@tlaurion

This comment was marked as outdated.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 7 changed files in this pull request and generated 3 comments.

Comments suppressed due to low confidence (1)

initrd/etc/functions.sh:1906

  • This comment says the implementation will “still let stdout appear on the console”, but both TPM1/TPM2 branches pipe DO_WITH_DEBUG output into tee /tmp/counter-... >/dev/null, which suppresses stdout from reaching the console. Update the comment to match the actual behavior (stdout captured to file; interactive prompts remain visible via tty).
	# Try to increment the counter.  We normally hide the verbose
	# output of tpmr.sh commands to avoid overwhelming the console, but we
	# must *not* swallow any interactive prompts.  The previous implementation
	# redirected the entire `tpmr.sh counter_create` invocation to a file and
	# /dev/null, which meant that when the counter was missing the password
	# prompt could not be seen by the user even though tpmr.sh printed it to the
	# controlling terminal.  Instead, capture just the stdout in a temporary
	# file while still letting stdout appear on the console (and logging
	# stderr to debug log).

Comment thread doc/config.md Outdated
Comment thread doc/architecture.md Outdated
Comment thread doc/tpm.md Outdated
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 7 changed files in this pull request and generated no new comments.

@tlaurion tlaurion force-pushed the bugfix-tpm_increment_on_seal branch from fc56a2b to 3db201c Compare May 6, 2026 13:53
tlaurion added 2 commits May 6, 2026 09:57
…acing

This commit fixes regressions introduced by PR linuxboot#2068, merged to origin/master on 2026-04-07.

Regressions fixed (present in origin/master post-PR linuxboot#2068):
- No "out of resources" (0x15) TPM counter error detection
- TPM2 counter increment had no auth retry on wrong passphrase
- TPM1 counter increment had no error handling
- tpm1_seal silenced NV define/write errors
- Duplicate TPM1/TPM2 retry loops (~100 lines of redundant code)
- counter_present dead code (now fixed with counter_read check)
- Comment mismatch (stdout vs console) now fixed
- set -e issue in check_tpm_counter (wrapped in subshell)

Fixes implemented:
- Add shared _tpm_auth_retry helper for TPM1/TPM2
- check_tpm_counter only triggers tpm_reset_required on 0x15 errors
- tpm1_seal surfaces NV errors with retry loop
- Simplify reset_tpm to verify tpmr.sh reset exit code

Copilot review fixes:
- Fix counter_present dead code: add counter_read check
- Fix comment at line 1901: stdout goes to /dev/null via tee
- Wrap tpmr.sh counter_create in subshell for set -e compatibility

Signed-off-by: Thierry Laurion <insurgo@riseup.net>
…d/etc/*.sh

Scripts were renamed from * to *.sh in a previous PR, but doc/* references
didn't follow. Update all initrd/bin/* and initrd/etc/* references in
doc/* to use the correct .sh extension for consistency.

Fixes Copilot review comments:
- doc/tpm.md:158 - functions, usb-init, kexec-insert-key -> .sh
- doc/tpm.md:390 - TPM1 vs TPM2 table uses tpmr.sh
- doc/tpm.md:364 - initrd/bin/* and initrd/etc/* -> .sh
- doc/config.md:45 - fix corrupted path boards/<name>/initrd/bin/.sh<file>
- doc/architecture.md:61 - seal-hotpkey -> seal-hotpkey.sh
- doc/tpm.md:14 - tpmr -> tpmr.sh for consistency
- doc/tpm.md:162,367 - remaining tpmr -> tpmr.sh references

Signed-off-by: Thierry Laurion <insurgo@riseup.net>
@tlaurion tlaurion force-pushed the bugfix-tpm_increment_on_seal branch 2 times, most recently from fcc647b to 214fb31 Compare May 6, 2026 14:28
@tlaurion tlaurion marked this pull request as draft May 6, 2026 14:32
…oards

The unconditional enable_usb and detect_usb_security_dongle_branding
calls in gui-init.sh (introduced by eb84f1b) caused USB modules
to be loaded early during boot, extending PCR-5. This resulted in
'Error PCR mismatch from TPM_Unseal' on non-HOTP boards because
kexec-seal-key.sh predicts PCR-5 = 0 (no modules loaded) for
the DUK seal.

Fix:
- Gate enable_usb and detect_usb_security_dongle_branding with
  'if [ -x /bin/hotp_verification ]' so non-HOTP boards don't
  load USB modules during early boot
- Non-HOTP boards: PCR-5 stays at 0, DUK unseal works correctly
- HOTP boards: USB still initialized early (required for dongle
  interaction), but only once (gated by _USB_ENABLED flag)
- Add enable_usb to wait_for_gpg_card() to ensure USB is ready
  before GPG card access

Fixes regression introduced in commit eb84f1b.

Signed-off-by: Thierry Laurion <insurgo@riseup.net>
@tlaurion tlaurion requested a review from Copilot May 6, 2026 15:53
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 9 changed files in this pull request and generated no new comments.

tlaurion added 2 commits May 6, 2026 15:33
…gle_branding

detect_usb_security_dongle_branding() already calls enable_usb() internally,
so calling enable_usb() before it is redundant. Remove all redundant calls
and export _USB_ENABLED so child processes inherit the state.

Also add DEBUG statements per doc/logging.md at key decision points.

Signed-off-by: Thierry Laurion <insurgo@riseup.net>
…essage

Signed-off-by: Thierry Laurion <insurgo@riseup.net>
@tlaurion tlaurion force-pushed the bugfix-tpm_increment_on_seal branch from bf15b0c to 5f81daa Compare May 6, 2026 19:50
@tlaurion tlaurion marked this pull request as ready for review May 6, 2026 19:55
@tlaurion
Copy link
Copy Markdown
Collaborator Author

tlaurion commented May 6, 2026

Confirmed working by @notgivenby

@tlaurion tlaurion merged commit c2fb345 into linuxboot:master May 6, 2026
3 of 5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TPM1 sometimes fail to seal secrets

2 participants