From 27b17c36a2f3b1dc7bd9598b08c35bc45094f72e Mon Sep 17 00:00:00 2001 From: Thierry Laurion Date: Sat, 4 Jul 2026 15:42:57 -0400 Subject: [PATCH] initrd: remove TPM2 primary handle hash check and creation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The kexec_primhdl_hash.txt feature stored a sha256sum of the TPM2 primary handle and verified it on every boot. It was originally added as a canary to detect TPM state changes, then accidentally dropped during the PR #2130 refactoring and re-added as a regression fix in PR #2145. However, this check is redundant with existing protections: - The TPM rollback counter (kexec_rollback.txt) already detects TPM state changes — a different or reset TPM either lacks the counter entirely or holds a different value, causing a fatal mismatch - The TPM Disk Unlock Key unseal fails if the primary handle changed, since the key is sealed to the original handle — booting into an OS where the DUK cannot unseal is futile - TOTP/HOTP secrets sealed to the TPM similarly fail to unseal on a changed handle In every realistic scenario the primary handle check catches, either the rollback counter or the TPM unseal (DUK, TOTP, or HOTP) catches it as well, with a clearer error message and the same outcome. The check also created UX problems: it was fatal (DIE) on mismatch even after an intentional TPM reset, requiring a workaround in the TPM reset flow (which explicitly removed kexec_primhdl_hash.txt). And it added another file to manage in /boot with no non-redundant security value. Removed from: - kexec-select-boot.sh: the boot-time verification check - kexec-save-default.sh: PRIMHASH_FILE variable and creation block - gui-init.sh: the TPM reset workaround (TODO comment + rm -f) - functions.sh: refresh_tpm2_primary_handle_hash() and its caller Signed-off-by: Thierry Laurion --- initrd/bin/gui-init.sh | 6 ------ initrd/bin/kexec-save-default.sh | 12 ----------- initrd/bin/kexec-select-boot.sh | 18 ----------------- initrd/etc/functions.sh | 34 -------------------------------- 4 files changed, 70 deletions(-) diff --git a/initrd/bin/gui-init.sh b/initrd/bin/gui-init.sh index ce03d953b..7f681717d 100755 --- a/initrd/bin/gui-init.sh +++ b/initrd/bin/gui-init.sh @@ -798,13 +798,7 @@ reset_tpm() { # now that the TPM is reset, remove invalid TPM counter files mount_boot mount -o rw,remount /boot - #TODO: this is really problematic, we should really remove the primary handle hash - - STATUS "Removing rollback and primary handle hashes under /boot" - - DEBUG "Removing /boot/kexec_rollback.txt and /boot/kexec_primhdl_hash.txt" rm -f /boot/kexec_rollback.txt - rm -f /boot/kexec_primhdl_hash.txt # create Heads TPM counter before any others check_tpm_counter /boot/kexec_rollback.txt "" "$tpm_owner_passphrase" || diff --git a/initrd/bin/kexec-save-default.sh b/initrd/bin/kexec-save-default.sh index 551c934d9..207b30f46 100755 --- a/initrd/bin/kexec-save-default.sh +++ b/initrd/bin/kexec-save-default.sh @@ -34,7 +34,6 @@ paramsdir="${paramsdir%%/}" TMP_MENU_FILE="/tmp/kexec/kexec_menu.txt" ENTRY_FILE="$paramsdir/kexec_default.$index.txt" HASH_FILE="$paramsdir/kexec_default_hashes.txt" -PRIMHASH_FILE="$paramsdir/kexec_primhdl_hash.txt" KEY_DEVICES="$paramsdir/kexec_key_devices.txt" KEY_LVM="$paramsdir/kexec_key_lvm.txt" @@ -291,17 +290,6 @@ done cp "$bootdir/kexec_initrd_crypttab_overrides.txt" "$stagedir/" DEBUG "Seeded $stagedir with existing config files from $paramsdir" -if [ "$CONFIG_TPM2_TOOLS" = "y" ]; then - if [ -f /tmp/secret/primary.handle ]; then - DEBUG "Hashing TPM2 primary key handle..." - sha256sum /tmp/secret/primary.handle > "$stagedir/kexec_primhdl_hash.txt" || - DIE "ERROR: Failed to Hash TPM2 primary key handle!" - DEBUG "TPM2 primary key handle hash written to $stagedir/kexec_primhdl_hash.txt" - else - DIE "ERROR: TPM2 primary key handle file does not exist!" - fi -fi - # Remove old kexec_default.*.txt from staging; new entry written below rm "$stagedir"/kexec_default.*.txt 2>/dev/null || true echo "$entry" >"$stagedir/kexec_default.$index.txt" diff --git a/initrd/bin/kexec-select-boot.sh b/initrd/bin/kexec-select-boot.sh index 09111a974..a652dfd73 100755 --- a/initrd/bin/kexec-select-boot.sh +++ b/initrd/bin/kexec-select-boot.sh @@ -69,24 +69,6 @@ if [ -z "$_HEADS_TEST" ]; then paramsdir="${paramsdir%%/}" fi -PRIMHASH_FILE="$paramsdir/kexec_primhdl_hash.txt" -if [ "$CONFIG_TPM2_TOOLS" = "y" ]; then - if [ -s "$PRIMHASH_FILE" ]; then - sha256sum -c "$PRIMHASH_FILE" >/dev/null 2>&1 || - { - WARN "Hash of TPM2 primary key handle mismatch - if you have not intentionally regenerated the TPM2 primary key, your system may have been compromised" - DEBUG "Hash of TPM2 primary key handle mismatched for $PRIMHASH_FILE" - DEBUG "Contents of $PRIMHASH_FILE:" - DEBUG "$(cat $PRIMHASH_FILE)" - DIE "Hash of TPM2 primary key handle mismatch ($PRIMHASH_FILE). If you did not intentionally regenerate the TPM2 primary key, this may indicate compromise." - } - else - WARN "Hash of TPM2 primary key handle does not exist - rebuild it by setting a default OS to boot: Options -> Boot Options -> Show OS Boot Menu -> pick OS -> Make default" - default_failed="y" - DEBUG "Hash of TPM2 primary key handle does not exist under $PRIMHASH_FILE" - fi -fi - verify_rollback_counter() { TRACE_FUNC TPM_COUNTER=$(grep counter $TMP_ROLLBACK_FILE | cut -d- -f2) diff --git a/initrd/etc/functions.sh b/initrd/etc/functions.sh index f0ecf0a90..b7f1a6228 100644 --- a/initrd/etc/functions.sh +++ b/initrd/etc/functions.sh @@ -2309,33 +2309,6 @@ secret_from_rom_hash() { sha256sum "${ROM_IMAGE}" | cut -f1 -d ' ' | fromhex_plain } -# Refresh /boot hash of the TPM2 primary handle when available. -# This prevents a follow-up prompt to "set default boot" solely to rebuild -# kexec_primhdl_hash.txt after TPM reset/reseal flows. -refresh_tpm2_primary_handle_hash() { - TRACE_FUNC - local primhash_file="${1:-/boot/kexec_primhdl_hash.txt}" - - if [ "$CONFIG_TPM2_TOOLS" != "y" ]; then - DEBUG "Skipping TPM2 primary handle hash refresh: CONFIG_TPM2_TOOLS != y" - return 0 - fi - - if [ ! -s /tmp/secret/primary.handle ]; then - DEBUG "Skipping TPM2 primary handle hash refresh: /tmp/secret/primary.handle not available" - return 0 - fi - - DEBUG "Refreshing TPM2 primary key handle hash into $primhash_file" - if ! DO_WITH_DEBUG sha256sum /tmp/secret/primary.handle >"$primhash_file"; then - WARN "Failed to refresh TPM2 primary key handle hash at $primhash_file" - return 1 - fi - - DEBUG "TPM2 primary key handle hash saved to $primhash_file" - return 0 -} - # Update the checksums of the files in /boot and sign them update_checksums() { TRACE_FUNC @@ -2359,13 +2332,6 @@ update_checksums() { fi fi - # Keep this best-effort and run it before signing while /boot is RW. - # Running after kexec-sign-config.sh can fail because that path may remount - # /boot read-only before returning. - if ! refresh_tpm2_primary_handle_hash; then - WARN "Proceeding without refreshed TPM2 primary key handle hash" - fi - signing_targets="$(find /boot/kexec*.txt 2>/dev/null | tr '\n' ' ')" DEBUG "update_checksums: signing targets under /boot: ${signing_targets:-}" DEBUG "update_checksums: rollback marker path is $reset_required_marker"