From 5b4c163002be61e240b1622a64917aee1793c00a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 11 Feb 2021 23:09:54 +0100 Subject: [PATCH 1/4] efivars: debug log if we fail to detect whether /sys/firmware/efi/ exists --- src/basic/efivars.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/basic/efivars.c b/src/basic/efivars.c index 5aeddef7e2..8e8d5f1d0b 100644 --- a/src/basic/efivars.c +++ b/src/basic/efivars.c @@ -290,8 +290,11 @@ bool is_efi_boot(void) { if (cache < 0) { if (detect_container() > 0) cache = false; - else + else { cache = access("/sys/firmware/efi/", F_OK) >= 0; + if (!cache && errno != ENOENT) + log_debug_errno(errno, "Unable to test whether /sys/firmware/efi/ exists, assuming EFI not available: %m"); + } } return cache; From d0ddaf587f23f68c9c34bd88b272d63ca098dd0d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 11 Feb 2021 23:10:07 +0100 Subject: [PATCH 2/4] efi-loader: add efi_has_tpm2() helper The helper checks if the UEFI firmware is hooked up to a TPM2 chip. This is useful to know in trusted boot scenarios, in particular during early boot in auto-enroll scenarios where we want to know whether TPM2 is available or not, and the Linux drivers are not loaded yet, and where it might or not be worth waiting for it. --- src/shared/efi-loader.c | 23 +++++++++++++++++++++++ src/shared/efi-loader.h | 6 ++++++ 2 files changed, 29 insertions(+) diff --git a/src/shared/efi-loader.c b/src/shared/efi-loader.c index 20f70da31a..2aab39c32d 100644 --- a/src/shared/efi-loader.c +++ b/src/shared/efi-loader.c @@ -783,6 +783,29 @@ int efi_loader_update_entry_one_shot_cache(char **cache, struct stat *cache_stat return 0; } +bool efi_has_tpm2(void) { + static int cache = -1; + + /* Returns whether the system has a TPM2 chip which is known to the EFI firmware. */ + + if (cache < 0) { + + /* First, check if we are on an EFI boot at all. */ + if (!is_efi_boot()) + cache = false; + else { + /* Then, check if the ACPI table "TPM2" exists, which is the TPM2 event log table, see: + * https://trustedcomputinggroup.org/wp-content/uploads/TCG_ACPIGeneralSpecification_v1.20_r8.pdf + * This table exists whenever the firmware is hooked up to TPM2. */ + cache = access("/sys/firmware/acpi/tables/TPM2", F_OK) >= 0; + if (!cache && errno != ENOENT) + log_debug_errno(errno, "Unable to test whether /sys/firmware/acpi/tables/TPM2 exists, assuming it doesn't: %m"); + } + } + + return cache; +} + #endif bool efi_loader_entry_name_valid(const char *s) { diff --git a/src/shared/efi-loader.h b/src/shared/efi-loader.h index 7621794736..bc5769bb6b 100644 --- a/src/shared/efi-loader.h +++ b/src/shared/efi-loader.h @@ -29,6 +29,8 @@ int efi_loader_get_features(uint64_t *ret); int efi_loader_get_config_timeout_one_shot(usec_t *ret); int efi_loader_update_entry_one_shot_cache(char **cache, struct stat *cache_stat); +bool efi_has_tpm2(void); + #else static inline int efi_reboot_to_firmware_supported(void) { @@ -91,6 +93,10 @@ static inline int efi_loader_update_entry_one_shot_cache(char **cache, struct st return -EOPNOTSUPP; } +static inline bool efi_has_tpm2(void) { + return false; +} + #endif bool efi_loader_entry_name_valid(const char *s); From b2a220492bc91c2f589381fc11556d9b46586c00 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 11 Feb 2021 23:11:56 +0100 Subject: [PATCH 3/4] bootctl: show whether the firmware has TPM2 support --- src/boot/bootctl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c index 7b759bcd02..cccd834cc8 100644 --- a/src/boot/bootctl.c +++ b/src/boot/bootctl.c @@ -1233,6 +1233,7 @@ static int verb_status(int argc, char *argv[], void *userdata) { printf(" Firmware: %s%s (%s)%s\n", ansi_highlight(), strna(fw_type), strna(fw_info), ansi_normal()); printf(" Secure Boot: %sd\n", enable_disable(is_efi_secure_boot())); printf(" Setup Mode: %s\n", is_efi_secure_boot_setup_mode() ? "setup" : "user"); + printf(" TPM2 Support: %s\n", yes_no(efi_has_tpm2())); k = efi_get_reboot_to_firmware(); if (k > 0) From 537c10f937745f379b8397205c0758125ecec606 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 11 Feb 2021 23:12:46 +0100 Subject: [PATCH 4/4] condition: if spelunking through /sys/class/tpmrm doesn't work ask EFI if TPM2 exists This makes ConditionSecurity=tpm2 work reliably during early boot: if Linux doesn't know about the TPM2 then maybe the firmware does. --- src/shared/condition.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/shared/condition.c b/src/shared/condition.c index 8b00697762..485b3bab39 100644 --- a/src/shared/condition.c +++ b/src/shared/condition.c @@ -487,6 +487,17 @@ static int has_tpm2(void) { * class device */ r = dir_is_empty("/sys/class/tpmrm"); + if (r == 0) + return true; /* nice! we have a device */ + + /* Hmm, so Linux doesn't know of the TPM2 device (or we couldn't check for it), most likely because + * the driver wasn't loaded yet. Let's see if the firmware knows about a TPM2 device, in this + * case. This way we can answer the TPM2 question already during early boot (where we most likely + * need it) */ + if (efi_has_tpm2()) + return true; + + /* OK, this didn't work either, in this case propagate the original errors */ if (r == -ENOENT) return false; if (r < 0)