diff --git a/man/systemd-analyze.xml b/man/systemd-analyze.xml index 10518dc791d..ce0e83c5440 100644 --- a/man/systemd-analyze.xml +++ b/man/systemd-analyze.xml @@ -962,7 +962,9 @@ default ignore - - discovered/supported/used, prints no. Otherwise prints partial. In either of these two cases exits with non-zero exit status. It also shows five lines indicating separately whether firmware, drivers, the system, the kernel and libraries - discovered/support/use TPM2. + discovered/support/use TPM2. Currently, required libraries are libtss2-esys.so.0, + libtss2-rc.so.0, and libtss2-mu.so.0. The requirement may be + changed in the future release. Note, this checks for TPM 2.0 devices only, and does not consider TPM 1.2 at all. diff --git a/shell-completion/bash/systemd-analyze b/shell-completion/bash/systemd-analyze index 9bb50a37b2c..7c5cb1c5123 100644 --- a/shell-completion/bash/systemd-analyze +++ b/shell-completion/bash/systemd-analyze @@ -67,7 +67,7 @@ _systemd_analyze() { ) local -A VERBS=( - [STANDALONE]='time blame unit-files unit-paths exit-status compare-versions calendar timestamp timespan pcrs srk' + [STANDALONE]='time blame unit-files unit-paths exit-status compare-versions calendar timestamp timespan pcrs srk has-tpm2' [CRITICAL_CHAIN]='critical-chain' [DOT]='dot' [DUMP]='dump' diff --git a/shell-completion/zsh/_systemd-analyze b/shell-completion/zsh/_systemd-analyze index 20b89646b17..50542b39628 100644 --- a/shell-completion/zsh/_systemd-analyze +++ b/shell-completion/zsh/_systemd-analyze @@ -73,6 +73,7 @@ JSON or table format' 'timespan:Parse a systemd syntax timespan' 'security:Analyze security settings of a service' 'inspect-elf:Parse and print ELF package metadata' + 'has-tpm2:Report whether TPM2 support is available' # log-level, log-target, service-watchdogs have been deprecated ) diff --git a/src/analyze/analyze-pcrs.c b/src/analyze/analyze-pcrs.c index 1c3da3fd840..0848f8e5b49 100644 --- a/src/analyze/analyze-pcrs.c +++ b/src/analyze/analyze-pcrs.c @@ -96,7 +96,7 @@ int verb_pcrs(int argc, char *argv[], void *userdata) { const char *alg = NULL; int r; - if (tpm2_support() != TPM2_SUPPORT_FULL) + if (!tpm2_is_fully_supported()) log_notice("System lacks full TPM2 support, not showing PCR state."); else { r = get_pcr_alg(&alg); diff --git a/src/boot/bootctl-status.c b/src/boot/bootctl-status.c index 58c6527ab81..61d76dd6795 100644 --- a/src/boot/bootctl-status.c +++ b/src/boot/bootctl-status.c @@ -411,7 +411,6 @@ int verb_status(int argc, char *argv[], void *userdata) { _cleanup_free_ char *fw_type = NULL, *fw_info = NULL, *loader = NULL, *loader_path = NULL, *stub = NULL, *stub_path = NULL, *current_entry = NULL, *oneshot_entry = NULL, *default_entry = NULL; uint64_t loader_features = 0, stub_features = 0; - Tpm2Support s; int have; (void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE(LoaderFirmwareType), &fw_type); @@ -440,7 +439,7 @@ int verb_status(int argc, char *argv[], void *userdata) { else printf("\n"); - s = tpm2_support(); + Tpm2Support s = tpm2_support_full(TPM2_SUPPORT_FIRMWARE|TPM2_SUPPORT_DRIVER); printf(" TPM2 Support: %s%s%s\n", FLAGS_SET(s, TPM2_SUPPORT_FIRMWARE|TPM2_SUPPORT_DRIVER) ? ansi_highlight_green() : (s & (TPM2_SUPPORT_FIRMWARE|TPM2_SUPPORT_DRIVER)) != 0 ? ansi_highlight_red() : ansi_highlight_yellow(), diff --git a/src/boot/measure.c b/src/boot/measure.c index 1af5fef720f..36d42147a1f 100644 --- a/src/boot/measure.c +++ b/src/boot/measure.c @@ -1005,7 +1005,7 @@ static int validate_stub(void) { bool found = false; int r; - if (tpm2_support() != TPM2_SUPPORT_FULL) + if (!tpm2_is_fully_supported()) return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Sorry, system lacks full TPM2 support."); r = efi_stub_get_features(&features); diff --git a/src/pcrextend/pcrextend.c b/src/pcrextend/pcrextend.c index 92f117c2cee..1bf39caf43d 100644 --- a/src/pcrextend/pcrextend.c +++ b/src/pcrextend/pcrextend.c @@ -369,7 +369,7 @@ static int run(int argc, char *argv[]) { event = TPM2_EVENT_PHASE; } - if (arg_graceful && tpm2_support() != TPM2_SUPPORT_FULL) { + if (arg_graceful && !tpm2_is_fully_supported()) { log_notice("No complete TPM2 support detected, exiting gracefully."); return EXIT_SUCCESS; } diff --git a/src/shared/condition.c b/src/shared/condition.c index 2e231dfdff5..da5c6f6309c 100644 --- a/src/shared/condition.c +++ b/src/shared/condition.c @@ -667,7 +667,7 @@ static int has_tpm2(void) { * * Note that we don't check if we ourselves are built with TPM2 support here! */ - return FLAGS_SET(tpm2_support(), TPM2_SUPPORT_SUBSYSTEM|TPM2_SUPPORT_FIRMWARE); + return FLAGS_SET(tpm2_support_full(TPM2_SUPPORT_SUBSYSTEM|TPM2_SUPPORT_FIRMWARE), TPM2_SUPPORT_SUBSYSTEM|TPM2_SUPPORT_FIRMWARE); } static int condition_test_security(Condition *c, char **env) { diff --git a/src/shared/creds-util.c b/src/shared/creds-util.c index 180ab560fa7..8cd7c9d7c50 100644 --- a/src/shared/creds-util.c +++ b/src/shared/creds-util.c @@ -886,7 +886,7 @@ int encrypt_credential_and_warn( * container tpm2_support will detect this, and will return a different flag combination of * TPM2_SUPPORT_FULL, effectively skipping the use of TPM2 when inside one. */ - try_tpm2 = tpm2_support() == TPM2_SUPPORT_FULL; + try_tpm2 = tpm2_is_fully_supported(); if (!try_tpm2) log_debug("System lacks TPM2 support or running in a container, not attempting to use TPM2."); } else diff --git a/src/shared/tpm2-util.c b/src/shared/tpm2-util.c index 38e4da40127..a9f6620a67d 100644 --- a/src/shared/tpm2-util.c +++ b/src/shared/tpm2-util.c @@ -3,6 +3,7 @@ #include #include "alloc-util.h" +#include "ansi-color.h" #include "constants.h" #include "creds-util.h" #include "cryptsetup-util.h" @@ -7872,11 +7873,11 @@ int tpm2_sym_mode_from_string(const char *mode) { return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown symmetric mode name '%s'", mode); } -Tpm2Support tpm2_support(void) { +Tpm2Support tpm2_support_full(Tpm2Support mask) { Tpm2Support support = TPM2_SUPPORT_NONE; int r; - if (detect_container() <= 0) { + if (((mask & (TPM2_SUPPORT_SUBSYSTEM|TPM2_SUPPORT_DRIVER)) != 0) && detect_container() <= 0) { /* Check if there's a /dev/tpmrm* device via sysfs. If we run in a container we likely just * got the host sysfs mounted. Since devices are generally not virtualized for containers, * let's assume containers never have a TPM, at least for now. */ @@ -7893,18 +7894,24 @@ Tpm2Support tpm2_support(void) { support |= TPM2_SUPPORT_SUBSYSTEM; } - if (efi_has_tpm2()) + if (FLAGS_SET(mask, TPM2_SUPPORT_FIRMWARE) && efi_has_tpm2()) support |= TPM2_SUPPORT_FIRMWARE; #if HAVE_TPM2 support |= TPM2_SUPPORT_SYSTEM; - r = dlopen_tpm2(); - if (r >= 0) - support |= TPM2_SUPPORT_LIBRARIES; + if (FLAGS_SET(mask, TPM2_SUPPORT_LIBRARIES)) { + r = dlopen_tpm2(); + if (r >= 0) + support |= TPM2_SUPPORT_LIBRARIES; + } #endif - return support; + return support & mask; +} + +static void print_field(const char *s, bool supported) { + printf("%s%s%s%s\n", supported ? ansi_green() : ansi_red(), plus_minus(supported), s, ansi_normal()); } int verb_has_tpm2_generic(bool quiet) { @@ -7914,22 +7921,17 @@ int verb_has_tpm2_generic(bool quiet) { if (!quiet) { if (s == TPM2_SUPPORT_FULL) - puts("yes"); + printf("%syes%s\n", ansi_green(), ansi_normal()); else if (s == TPM2_SUPPORT_NONE) - puts("no"); + printf("%sno%s\n", ansi_red(), ansi_normal()); else - puts("partial"); + printf("%spartial%s\n", ansi_yellow(), ansi_normal()); - printf("%sfirmware\n" - "%sdriver\n" - "%ssystem\n" - "%ssubsystem\n" - "%slibraries\n", - plus_minus(s & TPM2_SUPPORT_FIRMWARE), - plus_minus(s & TPM2_SUPPORT_DRIVER), - plus_minus(s & TPM2_SUPPORT_SYSTEM), - plus_minus(s & TPM2_SUPPORT_SUBSYSTEM), - plus_minus(s & TPM2_SUPPORT_LIBRARIES)); + print_field("firmware", FLAGS_SET(s, TPM2_SUPPORT_FIRMWARE)); + print_field("driver", FLAGS_SET(s, TPM2_SUPPORT_DRIVER)); + print_field("system", FLAGS_SET(s, TPM2_SUPPORT_SYSTEM)); + print_field("subsystem", FLAGS_SET(s, TPM2_SUPPORT_SUBSYSTEM)); + print_field("libraries", FLAGS_SET(s, TPM2_SUPPORT_LIBRARIES)); } /* Return inverted bit flags. So that TPM2_SUPPORT_FULL becomes EXIT_SUCCESS and the other values diff --git a/src/shared/tpm2-util.h b/src/shared/tpm2-util.h index 31ce2e89dbc..0bd9c3d9d1b 100644 --- a/src/shared/tpm2-util.h +++ b/src/shared/tpm2-util.h @@ -450,8 +450,8 @@ typedef struct { } systemd_tpm2_plugin_params; typedef enum Tpm2Support { - /* NOTE! The systemd-creds tool returns these flags 1:1 as exit status. Hence these flags are pretty - * much ABI! Hence, be extra careful when changing/extending these definitions. */ + /* NOTE! The systemd-analyze has-tpm2 command returns these flags 1:1 as exit status. Hence these + * flags are pretty much ABI! Hence, be extra careful when changing/extending these definitions. */ TPM2_SUPPORT_NONE = 0, /* no support */ TPM2_SUPPORT_FIRMWARE = 1 << 0, /* firmware reports TPM2 was used */ TPM2_SUPPORT_DRIVER = 1 << 1, /* the kernel has a driver loaded for it */ @@ -461,7 +461,13 @@ typedef enum Tpm2Support { TPM2_SUPPORT_FULL = TPM2_SUPPORT_FIRMWARE|TPM2_SUPPORT_DRIVER|TPM2_SUPPORT_SYSTEM|TPM2_SUPPORT_SUBSYSTEM|TPM2_SUPPORT_LIBRARIES, } Tpm2Support; -Tpm2Support tpm2_support(void); +Tpm2Support tpm2_support_full(Tpm2Support mask); +static inline Tpm2Support tpm2_support(void) { + return tpm2_support_full(TPM2_SUPPORT_FULL); +} +static inline bool tpm2_is_fully_supported(void) { + return tpm2_support() == TPM2_SUPPORT_FULL; +} int verb_has_tpm2_generic(bool quiet); diff --git a/src/tpm2-setup/tpm2-setup.c b/src/tpm2-setup/tpm2-setup.c index b95c5e7a581..ee9d243d5ee 100644 --- a/src/tpm2-setup/tpm2-setup.c +++ b/src/tpm2-setup/tpm2-setup.c @@ -259,7 +259,7 @@ static int run(int argc, char *argv[]) { if (r <= 0) return r; - if (arg_graceful && tpm2_support() != TPM2_SUPPORT_FULL) { + if (arg_graceful && !tpm2_is_fully_supported()) { log_notice("No complete TPM2 support detected, exiting gracefully."); return EXIT_SUCCESS; }