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;
}