Conversation
Required to to build dasharo-ec module. Need to pin SDCC version to 4.2.0 to avoid Dasharo/dasharo-issues#1785 and be in sync with ec-sdk: Dasharo/ec-sdk#2 Using 3.8.0 in nix toolchain (as originally used in ec-sdk) was not feasible: linuxboot#2062 (comment) Signed-off-by: Maciej Pijanowski <maciej.pijanowski@3mdeb.com> Signed-off-by: Thierry Laurion <insurgo@riseup.net> Signed-off-by: Thierry Laurion <insurgo@riseup.net>
…mal changes to build Dasharo-EC Signed-off-by: Thierry Laurion <insurgo@riseup.net> Signed-off-by: Thierry Laurion <insurgo@riseup.net>
- Remove leading tabs from ifeq variable assignments (Make parse error) - Move post-build steps (cp, dd, touch) out of dasharo-ec_target into a proper Make rule; _target is now only make arguments - Set dasharo-ec_output to ec.rom (the actual artifact, not .built) - Add -$(BOARD) suffix to dasharo-ec_base_dir and dasharo-ec_dir so v540tu and v560tu maintain independent build trees and ec.rom files - Add explicit rule to copy and zero-pad ec.rom to 128 KB - Fix coreboot copy rule: use FORCE + cmp so the recipe always runs but only updates the destination (and its mtime) when content differs, preventing the mtime race between boards sharing coreboot_base_dir Signed-off-by: Filip Lewiński <filip.lewinski@3mdeb.com> Signed-off-by: Thierry Laurion <insurgo@riseup.net> Signed-off-by: Thierry Laurion <insurgo@riseup.net>
…port - config/coreboot-novacustom-v560tu.config: switch EC from SYSTEM76_EC to DASHARO_EC (CONFIG_EC_DASHARO_EC=y, _UPDATE=y, _UPDATE_FILE="ec.rom"), matching the v540tu change already in this branch - modules/dasharo-ec: strip UNTESTED_/EOL_ board name prefixes before the board model mapping so that boards not yet promoted (e.g. UNTESTED_nitropad-ns50) resolve correctly without a separate entry - modules/dasharo-ec: add board model mappings for novacustom-nv4x_adl (ns5x_adl - nv4x_adl) and nitropad-ns50 (ns5x_adl) - modules/dasharo-ec: drop redundant sh -c wrapper from cp recipe; Make already invokes recipe lines via the shell - modules/dasharo-ec: replace dd seek-based padding with truncate --size=128KiB, as suggested in review (ec.rom is always smaller than 128 KiB) - modules/dasharo-ec: indent ifeq variable assignments with a tab for readability Signed-off-by: Filip Lewiński <filip.lewinski@3mdeb.com> Signed-off-by: Thierry Laurion <insurgo@riseup.net> Signed-off-by: Thierry Laurion <insurgo@riseup.net>
…nges When the coreboot git commit changes (canary mismatch), remove and recreate the board-specific build directories to prevent stale artifacts from causing compilation failures. This eliminates the need for manual `rm -rf build/x86/BOARD` before rebuilding after coreboot canary updates in development cycles (when creating patches). One currently still has to, eg: echo "bogues repo url + commit hash" | sudo tee /home/user/heads/build/x86/coreboot-25.09/.canary Current logic then: 1. Detects canary changes and triggers repository cleanup 2. Removes both Heads board directory (build/x86/BOARD) and coreboot board directory (build/x86/coreboot-*/BOARD) that contain stale build artifacts 3. Recreates empty board directories for the subsequent build 4. Allows patches to apply cleanly without Ada compilation errors This ensures Ada builds work correctly after coreboot updates without manual intervention (resync repo, apply patches, clean artifact dirs and rebuilds only what changed). Signed-off-by: Thierry Laurion <insurgo@riseup.net> Signed-off-by: Thierry Laurion <insurgo@riseup.net>
Signed-off-by: Filip Lewiński <filip.lewinski@3mdeb.com> Signed-off-by: Thierry Laurion <insurgo@riseup.net> Signed-off-by: Thierry Laurion <insurgo@riseup.net>
Signed-off-by: Filip Lewiński <filip.lewinski@3mdeb.com> Signed-off-by: Thierry Laurion <insurgo@riseup.net> Signed-off-by: Thierry Laurion <insurgo@riseup.net>
Signed-off-by: Filip Lewiński <filip.lewinski@3mdeb.com> Signed-off-by: Thierry Laurion <insurgo@riseup.net> Signed-off-by: Thierry Laurion <insurgo@riseup.net>
…g (Improve performance by lowering the EPP value from the power-on default of 0xb3 (70%) to 0x73 (45%). Lower value = higher performance.) Test fix for Dasharo/dasharo-issues#1711 related: - linuxboot#2039 - Dasharo/dasharo-issues#1711 - linuxboot#1894 Signed-off-by: Thierry Laurion <insurgo@riseup.net> Signed-off-by: Thierry Laurion <insurgo@riseup.net>
…nreleased The coreboot module for NovaCustom MTL boards was renamed from 'dasharo' to 'dasharo_v56'. The Heads patch system resolves patch directories as <module_name>[-<patch_version>], so with module coreboot-dasharo_v56 and patch_version=unreleased the expected path is patches/coreboot-dasharo_v56-unreleased/. Signed-off-by: Filip Lewiński <filip.lewinski@3mdeb.com> Signed-off-by: Thierry Laurion <insurgo@riseup.net> Signed-off-by: Thierry Laurion <insurgo@riseup.net>
Signed-off-by: Filip Lewiński <filip.lewinski@3mdeb.com> Signed-off-by: Thierry Laurion <insurgo@riseup.net> Signed-off-by: Thierry Laurion <insurgo@riseup.net>
Signed-off-by: Filip Lewiński <filip.lewinski@3mdeb.com> Signed-off-by: Thierry Laurion <insurgo@riseup.net> Signed-off-by: Thierry Laurion <insurgo@riseup.net>
Signed-off-by: Filip Lewiński <filip.lewinski@3mdeb.com> Signed-off-by: Thierry Laurion <insurgo@riseup.net> Signed-off-by: Thierry Laurion <insurgo@riseup.net>
Signed-off-by: Filip Lewiński <filip.lewinski@3mdeb.com> Signed-off-by: Thierry Laurion <insurgo@riseup.net> Signed-off-by: Thierry Laurion <insurgo@riseup.net>
Signed-off-by: Filip Lewiński <filip.lewinski@3mdeb.com> Signed-off-by: Thierry Laurion <insurgo@riseup.net> Signed-off-by: Thierry Laurion <insurgo@riseup.net>
Signed-off-by: Thierry Laurion <insurgo@riseup.net> Signed-off-by: Thierry Laurion <insurgo@riseup.net>
Signed-off-by: Thierry Laurion <insurgo@riseup.net> Signed-off-by: Thierry Laurion <insurgo@riseup.net>
Signed-off-by: Thierry Laurion <insurgo@riseup.net> Signed-off-by: Thierry Laurion <insurgo@riseup.net>
Signed-off-by: Thierry Laurion <insurgo@riseup.net> Signed-off-by: Thierry Laurion <insurgo@riseup.net>
…nfig Add coreboot.save_in_defconfig_format_backup target that runs savedefconfig and saves the result as .config_defconfig alongside the original .config file. Signed-off-by: Thierry Laurion <insurgo@riseup.net> Signed-off-by: Thierry Laurion <insurgo@riseup.net>
…m Dasharo/mtl_release Command trail: ./docker_repro.sh make BOARD=UNTESTED_nitropad-ns50 coreboot.save_in_oldconfig_format_in_place ./docker_repro.sh make BOARD=UNTESTED_nitropad-ns50 coreboot.save_in_defconfig_format_backup git difftool -d sudo cp config/coreboot-nitropad-ns50.config_defconfig config/coreboot-nitropad-ns50.config ./docker_repro.sh make BOARD=UNTESTED_nitropad-ns50 coreboot.save_in_oldconfig_format_in_place ./docker_repro.sh make BOARD=UNTESTED_nitropad-ns50 coreboot.save_in_defconfig_format_backup Preserve smbios strings from origin/master while reducing unnecessary defconfig changes to only critical deviations: - Use RaptorLake FSP headers (MTL release) - Set CONFIG_USE_PC_CMOS_ALTCENTURY=n - Enable console loglevel/ansi prefixes - Fix debug output: HWBASE_DEBUG_NULL -> HWBASE_DEBUG_CB Signed-off-by: Thierry Laurion <insurgo@riseup.net> Signed-off-by: Thierry Laurion <insurgo@riseup.net>
Previously coreboot-purism depended on coreboot-24.02.01's toolchain to avoid duplicate toolchain builds. However, no maintained boards actually use 24.02.01 directly (only unmaintained x230-legacy boards), so this dependency was unnecessary complexity. Now coreboot-purism builds its complete toolchain independently, making it consistent with all other coreboot forks (Dasharo variants, talos_2) which also build their own toolchains. This simplifies the cache strategy: each fork's cache contains only its own coreboot directory, with no hidden dependencies. Signed-off-by: Thierry Laurion <insurgo@riseup.net> Signed-off-by: Thierry Laurion <insurgo@riseup.net>
Implements a new cache-based pipeline that dramatically improves build times through hierarchical caching with fork-specific caches. Key changes: - Add executor, commands, and job definitions for cache-based builds - Add create_hashes job to generate cache digest files - Add x86_blobs job for blob downloads with cache support - Add x86_musl_cross_make job for toolchain builds with cache save - Add x86_coreboot job per fork, each saves both modules and coreboot caches - Add ppc64_musl_cross_make and ppc64_coreboot jobs (decoupled from single job) - Add glossary documenting fan-in, workspace chain, cache layers Fixes for cache invalidation issues: - Remove .circleci/config.yml from cache key hashes (prevents cache invalidation on CI config changes - was causing full rebuilds on every pipeline) - Fix musl-cross-make module to auto-detect existing crossgcc using wildcard check - Exclude .circleci/config.yml from all_modules_and_patches.sha256sums and coreboot_musl-cross-make.sha256sums Test results (multiple pipeline runs): Pipeline 3789 (first run, cold cache): - x86-musl-cross-make: 30 min - ppc64-musl-cross-make: 16 min - Result: Cache saved Pipeline 3790 (second run, cache hit): - x86-musl-cross-make: 4.5 min (6.6x faster than first run) - ppc64-musl-cross-make: 4.5 min (3.5x faster than first run) - Result: Beats baseline (14.5 min) by 3.2x Pipeline 3791 (third run, cache hit): - x86-musl-cross-make: ~6 min (27s Make Board + spin up variance) - ppc64-musl-cross-make: 4.5 min - Result: Still beats baseline The wildcard fix for musl-cross-make module detects existing crossgcc from cache and skips rebuild entirely (Make Board takes only 27s vs 26 min cold). Add tests/circle-ci-simulation/ for local cache behavior verification: - test_cache_hash.sh, test_musl_skip.sh, simulate_cold_cache.sh, etc. Signed-off-by: Thierry Laurion <insurgo@riseup.net> Signed-off-by: Thierry Laurion <insurgo@riseup.net>
…01_rc3 REGRESSION TESTING for next Dasharo+Heads: v560tu/v540tu dasharo tag 1.0.1, have all Dasharo coreboot based boards use their own tagsSigned-off-by: Thierry Laurion <insurgo@riseup.net>
…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> 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> Signed-off-by: Thierry Laurion <insurgo@riseup.net>
…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> Signed-off-by: Thierry Laurion <insurgo@riseup.net>
…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> Signed-off-by: Thierry Laurion <insurgo@riseup.net>
…essage Signed-off-by: Thierry Laurion <insurgo@riseup.net> Signed-off-by: Thierry Laurion <insurgo@riseup.net>
…on_seal Bugfix: Fix TPM auth retry, counter error handling, and NV error surfacingSigned-off-by: Thierry Laurion <insurgo@riseup.net>
Add a HOTP remote-attestation variant of the Acer Chromebook Spin 714 (KANO) board, following the qemu-coreboot-fbwhiptail-tpm2[-hotp] unified pattern: boards/kano-hotp/kano-hotp.config is identical to the base boards/kano/kano.config except CONFIG_HOTPKEY=y and CONFIG_BOARD_NAME="Google Kano HOTP". Both boards share the same config/coreboot-kano.config and config/linux-kano.config pointers. CI: kano-hotp builds seeded by the kano coreboot-mrchromebox-26.03 seed. Signed-off-by: Thierry Laurion <insurgo@riseup.net> Signed-off-by: Thierry Laurion <insurgo@riseup.net>
…king Extend .gitignore to cover editor and tooling scratch/backup files so they cannot silently get committed again (a prior commit tracked tpmr.sh.bck, tpm-patch2, tpm.md-patch and tpm2_* scratch fixtures under the repo root). Adds: *.bak, *.bck, *.orig, *.rej, *.save, *.tmp, -patch, .md-patch (build/archives already covered by *.o, *.rom, *.img, *.cpio etc.) Signed-off-by: Thierry Laurion <insurgo@riseup.net> Signed-off-by: Thierry Laurion <insurgo@riseup.net>
Bring in upstream master (PR linuxboot#2200: tpm-gpio-reset Kondix10 attribution and module pin 3e3a695). Both commits are already present in this branch by identical patch content (modules/tpm-gpio-reset matches at both tips), so they are not duplicated here. Signed-off-by: Thierry Laurion <insurgo@riseup.net> Signed-off-by: Thierry Laurion <insurgo@riseup.net>
Signed-off-by: Chris Wiggins <chris@cwiggs.com> Signed-off-by: Thierry Laurion <insurgo@riseup.net>
Add Google kano (MrChromebox 26.03 coreboot fork) support - First full Chromebook port!Signed-off-by: Thierry Laurion <insurgo@riseup.net>
This was referenced Sep 7, 2026
tpm1_da_state queries TPM_CAP_DA_LOGIC (0x19) for TPM 1.2 chips and returns a human-readable summary plus a machine-parsable "DA: state=... current=... threshold=... timer=..." line. tpm2_da_state queries getcap properties-variable for TPM 2.0 and returns LOCKOUT_COUNTER, MAX_AUTH_FAIL, LOCKOUT_INTERVAL, and LOCKOUT_RECOVERY plus the same machine-parsable summary line. When the counter is at or above threshold, the function estimates time-to-unlock as (counter - maxAuth + 1) * interval. Both functions gracefully report "unavailable" when the TPM does not support the underlying query (e.g. STM TPM1 returning TPM_BAD_MODE 44), and emit a DEBUG line with vendor / firmware identification for diagnostic logging. tpm1_bad_auth and tpm2_bad_auth deliberately trigger an auth failure on the rollback counter so the dictionary-attack counter is bumped on demand. They distinguish auth-failure from active lockout via da_state output and are the primary tool for reproducing and verifying lockout detection end-to-end on both TPM versions without waiting for organic hits. Dispatcher entries expose the new subcommands under the existing tpmr.sh case branches so callers can invoke any of: tpmr.sh da_state tpmr.sh bad_auth [<counter_id>] This is the foundation needed by callers that need to distinguish DA lockout from other TPM read failures -- in particular the rollback-counter preflight gate, the increment-tpm-counter reseal path, the tpm1_unseal / tpm2_unseal paths, and the recovery-shell entry -- all of which land in follow-up commits. Signed-off-by: Thierry Laurion <insurgo@riseup.net>
preflight_rollback_counter_before_reseal is the gating function every Heads boot runs before showing the TOTP / HOTP prompt. When it cannot read the rollback counter NV index, the previous code silently discarded the tpm2 stderr (`tpmr.sh counter_read ... >/dev/null 2>&1`) and surfaced a generic "TPM swap attack" message regardless of the actual cause -- leaving users unable to tell apart real disk or TPM swap from TPM dictionary-attack (DA) lockout or other transient errors. This commit rewires the failure path to: 1. Capture the tpm2 stderr to /tmp/debug.log (LOG level) via DO_WITH_DEBUG so the actual response code is preserved for post-mortem reports without polluting the console. 2. Query the new tpmr.sh da_state helper (TPM1 + TPM2) and parse the machine-parsable DA: policy line. When the TPM reports DA lockout (timer > 0, or counter >= threshold), set the /tmp/secret/tpm_da_lockout marker file and surface a focused message that includes the remaining backoff time, common causes (repeated auth failures, repeated unclean shutdowns that skipped TPM2_Shutdown -- particularly observed on Intel PTT and similar firmware TPMs), and an actionable recommendation: wait the timer, or reset the TPM from the GUI if the wait is long. 3. Keep the existing reset recommendation for genuine non-lockout failures (counter reset, TPM replaced, da_state unavailable) but drop the alarmist "TPM swap attack" wording and append a pointer to /tmp/debug.log for the captured tpm2 error. Logging follows doc/logging.md: LOG for verbose dumps (tpm2 stderr, full da_state output), DEBUG for decision points (lockout_detected yes/no). User-facing whiptail stays short with 76-column wrap delegated to _whiptail_preprocess_args per doc/ux-patterns.md, and points to /tmp/debug.log for full diagnostics. Scope note: this commit is functions.sh only. The consumer in gui-init.sh (the preflight error menu at line 949) currently strips the "Reset TPM from GUI" action guidance from our message and appends a generic "TPM swap attack" warning block. A follow-up commit will fix the consumer so the calm UX actually reaches the user. Signed-off-by: Thierry Laurion <insurgo@riseup.net>
… marker file
tpm2_unseal now captures its stderr to a temp file so it can grep for
the TPM2_RC_LOCKOUT pattern ("lockout", "lock", "auth.*fail",
"0x98e", "0x149") before falling through to the generic
"unable to unseal" warning. When detected, sets
/tmp/secret/tpm_da_lockout so the GUI menu loop in gui-init.sh can
route to a lockout-specific dialog instead of the generic TOTP
failure dialog (the consumer side lands in a follow-up commit).
tpm1_unseal gets symmetric detection: tpmtotp prints errors to stdout
(not stderr), and "Defend lock running" is the canonical TPM 1.2
defend-lock signal. This path matters for chips that don't expose
DA state via TPM_CAP_DA_LOGIC (e.g. STM TPM1 returning
TPM_BAD_MODE 44) -- the unseal failure output is the only reliable
signal there. On lockout detection, the marker is set and a STATUS
line is emitted with the da_state summary so the user sees remaining
backoff time, not just the alarm.
The marker file is consumed by:
- gui-init.sh update_totp (commit 6): routes to lockout dialog
- recovery() (commit 5): displays DA state summary
This commit is tpmr.sh only. Callers (unseal-totp.sh, unseal-hotp.sh,
seal-hotpkey.sh, kexec-unseal-key.sh) need no change -- they already
treat unseal failure as exit 1, and the marker file is set BEFORE
exit so it persists for the consumer.
Signed-off-by: Thierry Laurion <insurgo@riseup.net>
…ockout before reseal
increment_tpm_counter is called from:
- gui-init.sh:819 inside the reset_tpm flow
- oem-factory-reset.sh:884 inside counter validation
- kexec-sign-config.sh:103 inside update_checksums (the path that
fires when re-signing /boot files)
Without a DA preflight, any of these paths would attempt an
increment on a locked TPM and either extend the lockout (TPM1) or
fail with a confusing generic error after a needless auth attempt.
This commit queries tpmr.sh da_state (TPM1 + TPM2) at the start of
increment_tpm_counter. When DA lockout is active (timer > 0, or
counter >= threshold on TPM2):
- Sets /tmp/secret/tpm_da_lockout so the recovery shell
(commit 5) and gui-init.sh (commit 6) can display remaining time
- Writes the timer string to /tmp/secret/tpm_da_lockout_msg for
the GUI lockout dialog
- DIE with a clear, time-aware message rather than letting the
generic increment error fire
For TPM1 chips that don't expose DA state via TPM_CAP_DA_LOGIC
(e.g. STM returning TPM_BAD_MODE 44), da_state returns unavailable
and the guard is a no-op -- the increment will still be attempted
and lockout will be detected from the increment failure output
(handled in the increment block). This matches the preflight gate's
fallback behavior.
Threshold warnings (above threshold, nearing threshold) emit WARN
without aborting so users approaching lockout still get useful
guidance without losing the increment.
Logging follows doc/logging.md: DEBUG for decision points
(lockout detected, threshold status, da_state unavailable),
WARN/DIE for user-visible signals.
Signed-off-by: Thierry Laurion <insurgo@riseup.net>
…ockout time
recovery() is the universal fallback path -- it is reached when:
- The TOTP/HOTP preflight fails (commit 2)
- The unseal fails (commit 3, with marker file set)
- The user explicitly chooses 'Exit to recovery shell' from any menu
- The boot script is missing or fails
- /init or /bin/reboot.sh decides to drop to a shell
A user who lands in recovery shell due to DA lockout (the most
common 'stuck' scenario) currently sees no signal explaining why
their TPM auth is failing. The shell is also the only place they
can run tpmr.sh manually for diagnosis, so showing the DA state
up-front gives them both the explanation and the command they can
re-run for deeper inspection.
This commit:
- Queries tpmr.sh da_state (TPM1 + TPM2) inside recovery(), just
before the shell starts
- Routes the full multi-line da_state output to LOG (debug.log
only) per doc/logging.md
- Surfaces the single-line '=>' summary (e.g. 'TPM LOCKOUT ACTIVE
(5/5 failures)' or 'TPM DEFEND LOCK ACTIVE (~5 min remaining)')
at STATUS level so it reaches console in all modes including
Quiet
- Falls back to the self-descriptive 'TPM DA state: unavailable'
line when no summary is available (STM TPM1 case)
Consumes the /tmp/secret/tpm_da_lockout marker set by commits 2, 3,
and 4 indirectly: when lockout is active, the marker is on disk,
the da_state query returns the lockout summary, and the user sees
it the moment they reach the shell.
Signed-off-by: Thierry Laurion <insurgo@riseup.net>
…nu UX, route lockout marker to dedicated dialog
Three UX changes, all gated on the /tmp/secret/tpm_da_lockout marker
file set by commits 2, 3, and 4:
1. Early STATUS line at the start of gui-init.sh (right after
TRACE_FUNC, before HOTP detection) so the user sees remaining
backoff time on screen immediately, before any auth attempt that
could extend the lockout. Non-mutating tpmr.sh da_state query;
silent on healthy boots, STATUS line only when lockout is active.
2. Fix the preflight error menu UX. The previous code stripped the
'Reset TPM from GUI...' action guidance from our preflight
message and unconditionally appended a generic block:
Possible causes: TPM was reset or replaced, /boot disk was
swapped or restored, TPM state tampering occurred.
WARNING: If none of the above were intentional, treat /boot
as UNTRUSTED. A disk or TPM swap attack cannot be ruled out.
That alarming text appears even when the cause is a recoverable
DA lockout. Now, when the marker file is set, we skip the generic
block and show a lockout-specific dialog explaining common causes
(auth failures, unclean shutdowns on Intel PTT) with the timer,
and offering reset / OEM Factory Reset / continue to main menu
without 'Show integrity report' (which makes no sense during
lockout).
3. Route the lockout marker to a dedicated dialog inside update_totp
so users hitting lockout through the TOTP-unseal path see the
same focused UX as users hitting it through the preflight path.
Without this, the marker would be set (commit 3) but the generic
'TOTP Generation Failed!' dialog with 'THIS COULD INDICATE
TAMPERING!' would still be shown -- directly contradicting the
calm UX the marker file is supposed to signal.
The marker is consumed (deleted) by whichever dialog reads it.
This makes the protocol one-shot per failure, so re-preflight
failures re-set it cleanly from scratch via the gate.
All three changes share the marker-file contract; bundling them
keeps the protocol change atomic.
Signed-off-by: Thierry Laurion <insurgo@riseup.net>
…otocol, early-status display Signed-off-by: Thierry Laurion <insurgo@riseup.net>
…TPM2
Three improvements on top of the existing bad_auth:
1. State the NV region clearly in both pre/post debug lines.
The NV index range is the primary indicator of what kind of
NV space the counter lives in -- and crucially whether it is
even writable by the user.
TPM1 classification:
0x0001xxxx : permanent (TPM-reserved)
0x0002xxxx : legacy user NV
0x0003xxxx : legacy user NV
0x4xxxxxxx : platform-reserved
0x8xxxxxxx : transport/reserved
default : user NV (Heads counter lives here)
TPM2 classification:
0x01xxxxxx : user-defined (0x01000000-0x01FFFFFF)
0x40xxxxxx : TPM-reserved (0x40000000-0x400FFFFF)
0x80xxxxxx : persistent (0x80000000-0x803FFFFF)
0x10xxxxxx : platform (0x10000000-0x10000FFF)
default : other
Note: counter_id has the 0x prefix stripped during discovery
(counter_id='${probe_index#0x}') so case patterns match without
the 0x prefix. The DEBUG output adds the prefix back for clarity.
2. Emit DA state BEFORE the bad-auth attempt for both TPM1 and
TPM2 (was missing on TPM1). The TPM1 branch only printed
state on lockout detection, leaving users blind to whether
the attempt actually fired.
3. Emit DA state AFTER the bad-auth attempt for both TPM1 and
TPM2 (was missing the NV region annotation on TPM2, missing
entirely on TPM1). The user can now see the counter visibly
increment in the after-state, confirming the bad-auth fired.
Both state prints now include the NV region and counter index
so it's unambiguous which NV slot is being exercised.
Signed-off-by: Thierry Laurion <insurgo@riseup.net>
…ntent
The preflight error menu was hardcoded to '26 80 4' height. This
predates doc/ux-patterns.md's window-sizing rule ('Use 0 for
height in all dialogs') and breaks when dialog content grows --
which is exactly what happened when the DA lockout diagnostic
was added.
On the kgpe-d16_server-whiptail boards (CONFIG_VGA_TEXT_FRAMEBUFFER=y,
serial console / VGA text mode 80x25), 26 rows overflows the
25-line terminal and the menu items fall off the visible area.
Fix: change '26 80 4' to '0 80 4' (auto-height per doc convention),
drop redundant 'Possible causes' and 'WARNING' blocks since
preflight_reason already enumerates causes.
Signed-off-by: Thierry Laurion <insurgo@riseup.net>
Documents the 80x25 VGA text mode floor and references the actual coreboot board configs that hit it (kgpe-d16_server-*). Adds guidance to always use 0 for height in whiptail dialogs. Signed-off-by: Thierry Laurion <insurgo@riseup.net>
The tpm2_bad_auth function strips the '0x' prefix from the
counter_id during discovery (counter_id=${probe_index#0x})
because the index is then reused as '0x$counter_id' for
tpm2 invocations.
But the case patterns in the NV region classifier still
started with '0x' (e.g. '0x01*'), so they never matched. For
a counter like 0x1180918 (counter_id='1180918'), the function
fell through to '*)' and reported 'other' -- wrong.
Fix: drop the '0x' prefix from case patterns so they match the
stripped counter_id.
TPM1 patterns had the same bug but accidentally still resolved
to a sensible label ('user NV') via the wildcard fallback, so
the misreport went unnoticed. Both TPMs are now consistent.
Signed-off-by: Thierry Laurion <insurgo@riseup.net>
…gress The post-discovery 'tpm2 nvread "0x$counter_id" >/dev/null 2>&1' existence check is failing silently when TPM is in lockout -- tpm2 nvread returns TPM_RC_LOCKOUT in that state, so the if branches into the WRONG 'Counter does not exist' message and returns 1 without ever attempting the bad auth. This is exactly the failure mode bad_auth is supposed to detect and exercise. Fix: drop the redundant existence check entirely. The NV enumeration in the discovery loop already probed each index with tpm2 nvread and confirmed existence. If the counter was deleted between discovery and now, tpm2 nvincrement will fail with TPM_RC_HANDLE -- still reported through the outcome block. Also add STATUS-level progress lines so the user can see in the kernel ring buffer (not just /tmp/debug.log) that bad_auth is running and what it's doing: - bad_auth (TPM2): testing NV index 0x$counter_id - bad_auth (TPM2): ABORTED -- no counter ID (if discovery failed) Signed-off-by: Thierry Laurion <insurgo@riseup.net>
…l log modes Previous fix added a single STATUS line at the start of bad_auth but the rest of the function's progress was DEBUG-only. In quiet mode (the default for production boots), DEBUG does not go to console -- so the user can see 'bad_auth starting' but not whether nvincrement actually ran, what it returned, or whether the function completed. Replace the critical progress lines with STATUS so the user can follow the entire test in console output (not just /tmp/debug.log): STATUS bad_auth (TPM2): starting -- counter=0x... region=... STATUS bad_auth (TPM2): BEFORE state captured STATUS bad_auth (TPM2): attempting nvincrement with WRONG auth on 0x... STATUS bad_auth (TPM2): nvincrement REJECTED by TPM lockout (rc=...) STATUS bad_auth (TPM2): nvincrement FAILED with wrong auth (rc=...) -- DA counter bumped STATUS bad_auth (TPM2): nvincrement SUCCEEDED with wrong auth (rc=0) -- counter has no auth, test inconclusive STATUS bad_auth (TPM2): AFTER state -- capturing... STATUS bad_auth (TPM2): DONE If 'DONE' is missing from the console output, the function crashed or hung -- which is now obviously diagnosable from the last STATUS line seen. Signed-off-by: Thierry Laurion <insurgo@riseup.net>
…M1 lockout-exit check STATUS only writes to /dev/console and /tmp/debug.log, so progress lines were invisible in /dev/kmsg capture; the TPM1 counter_read existence check also silently exited on DA lockout. Signed-off-by: Thierry Laurion <insurgo@riseup.net>
STATUS and 'echo >&2' progress lines in tpm1_bad_auth and tpm2_bad_auth reach /dev/console and /tmp/debug.log, but neither channel reaches /dev/kmsg in any output mode (see doc/logging.md). When CONFIG_DEBUG_OUTPUT=y, the kernel forwards /dev/kmsg to all registered consoles -- including serial and BMC -- so a user capturing /dev/kmsg for post-mortem analysis sees only the existing DEBUG lines, missing the structured progress markers that announce what bad_auth is doing and what it observed. Add a DEBUG "..." companion line immediately after each progress marker (start, BEFORE state captured, attempt, REJECTED/FAILED/ SUCCEEDED, AFTER state capturing, DONE, ABORTED) in both functions. The text matches the STATUS/echo text verbatim. The DEBUG channel writes to /tmp/debug.log always and to /dev/kmsg + /dev/console when CONFIG_DEBUG_OUTPUT=y, so every progress marker now lands in any /dev/kmsg capture alongside the existing diagnostic DEBUG lines. doc/tpm.md: add '### Output and visibility' subsection under the tpmr.sh bad_auth section explaining the dual-channel pattern and why both are emitted. Doc now matches code. Signed-off-by: Thierry Laurion <insurgo@riseup.net>
… reliable detection The TPM2 lockout grep used 0x22d which is not a valid TPM2_RC. TPM_RC_LOCKOUT is defined as 0x921 (TPM2_RC_WARN 0x900 + 0x021) in tpm2-tss headers. On a real locked TPM, tpm2-tools prints Esys Finish ErrorCode (0x00000921) -- the old pattern never matched and lockout was silently misclassified as an auth failure. Fix the grep to match 0x921 (the real TCG-spec constant) alongside the textual lockout/TPM_RC_LOCKOUT patterns. Fix all 0x22d references in code and doc to 0x921. Fix the sample tpm2 error output in doc to match the actual ESAPI format string. Restructure bad_auth (both TPM1 and TPM2) to do the increment attempt FIRST and capture da_state only AFTER. The BEFORE da_state capture was removed because tpm2 getcap properties-variable blocks indefinitely against a wedged PTT (Esys_GetCapability forces timeout=-1 in tpm2-tss). The increment attempt itself is the test -- it returns promptly with TPM_RC_LOCKOUT 0x921 (TPM2) or TPM_DEFEND_LOCK_RUNNING 0x803 (TPM1) when the TPM is already locked out. The AFTER da_state query runs unconditionally and captures the timer for recovery guidance. Also: capture stderr from lockout-detection TPM queries instead of redirecting to /dev/null. The 4 getcapability sites (tpm1_da_state version, tpm1_da_state DA, tpm2_da_state, tpm1_bad_auth version) now use TMP_STDERR capture with DEBUG logging and unconditional cleanup. The 3 cleanup shapes (simple, rc-capturing, if/then/else) are documented in ux-patterns.md. doc/tpm.md: update Output and visibility to drop the obsolete BEFORE state marker; add Strategy markers subsection documenting the DEBUG-only design choice; add Lockout detection on TPM2 subsection explaining the 0x921 hex pattern and why it is needed. doc/ux-patterns.md: add Capturing TPM command stderr subsection with the three acceptable TMP_STDERR cleanup shapes (A/B/C). Signed-off-by: Thierry Laurion <insurgo@riseup.net>
37 tasks
…onest recovery docs
- da_lockout_msg: canonical "X of N allowed auth attempts used; one attempt
frees up after Z; ~Z until auth works again" body, shared by the boot
dialog, TOTP failure dialog, preflight WARN, and recovery shell; extended
with causes and reset reseal guidance lines.
- Both lockout dialogs (boot menu and update_totp) default to Waiting with a
live countdown refresh option ("w"), re-query da_state each pass, and lift
automatically once the counter drops below maxTries (TPM2 self-heal).
- set_tpm_reset_required / increment_tpm_counter / fail_preflight gate the
DA marker file and route lockout to the dedicated dialog instead of generic
reseal asks or rollback-counter wording.
- da_state/da_remaining report raw seconds from the TPM policy (LOCKOUT_INTERVAL,
not recovery), with getcapability fallback and truthful "duration unknown"
handling.
- doc/tpm.md + doc/ux-patterns.md: document LOCKOUT_INTERVAL semantics,
fixed-policy self-heal (one failed attempt forgotten per recoveryTime),
the marker-file protocol, and the 80x25 screen-size floor.
tlaurion
force-pushed
the
tpm_da_lockout_rework
branch
from
September 10, 2026 23:05
9a492fb to
d023d16
Compare
Collaborator
Author
37 tasks
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.
WiP to fix #2123