diff --git a/man/systemd-pcrphase.service.xml b/man/systemd-pcrphase.service.xml
index 9eda503e4c..9b7cc80b3a 100644
--- a/man/systemd-pcrphase.service.xml
+++ b/man/systemd-pcrphase.service.xml
@@ -131,6 +131,14 @@
all suitable TPM2 devices currently discovered.
+
+
+
+ If no TPM2 firmware, kernel subsystem, kernel driver or device support is found, exit
+ with exit status 0 (i.e. indicate success). If this is not specified any attempt to measure without a
+ TPM2 device will cause the invocation to fail.
+
+
diff --git a/src/boot/pcrphase.c b/src/boot/pcrphase.c
index 267f66767c..e5d33ff1a2 100644
--- a/src/boot/pcrphase.c
+++ b/src/boot/pcrphase.c
@@ -12,6 +12,7 @@
#include "tpm-pcr.h"
#include "tpm2-util.h"
+static bool arg_graceful = false;
static char *arg_tpm2_device = NULL;
static char **arg_banks = NULL;
@@ -33,6 +34,7 @@ static int help(int argc, char *argv[], void *userdata) {
" --version Print version\n"
" --bank=DIGEST Select TPM bank (SHA1, SHA256)\n"
" --tpm2-device=PATH Use specified TPM2 device\n"
+ " --graceful Exit gracefully if no TPM2 device is found\n"
"\nSee the %2$s for details.\n",
program_invocation_short_name,
link,
@@ -49,6 +51,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_VERSION = 0x100,
ARG_BANK,
ARG_TPM2_DEVICE,
+ ARG_GRACEFUL,
};
static const struct option options[] = {
@@ -56,6 +59,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "version", no_argument, NULL, ARG_VERSION },
{ "bank", required_argument, NULL, ARG_BANK },
{ "tpm2-device", required_argument, NULL, ARG_TPM2_DEVICE },
+ { "graceful", no_argument, NULL, ARG_GRACEFUL },
{}
};
@@ -103,6 +107,10 @@ static int parse_argv(int argc, char *argv[]) {
break;
}
+ case ARG_GRACEFUL:
+ arg_graceful = true;
+ break;
+
case '?':
return -EINVAL;
@@ -172,6 +180,11 @@ static int run(int argc, char *argv[]) {
if (isempty(word))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "String to measure cannot be empty, refusing.");
+ if (arg_graceful && tpm2_support() != TPM2_SUPPORT_FULL) {
+ log_notice("No complete TPM2 support detected, exiting gracefully.");
+ return EXIT_SUCCESS;
+ }
+
length = strlen(word);
/* Skip logic if sd-stub is not used, after all PCR 11 might have a very different purpose then. */
diff --git a/units/systemd-pcrphase-initrd.service.in b/units/systemd-pcrphase-initrd.service.in
index c1ad5ef844..e437c7e1ce 100644
--- a/units/systemd-pcrphase-initrd.service.in
+++ b/units/systemd-pcrphase-initrd.service.in
@@ -20,5 +20,5 @@ ConditionPathExists=/sys/firmware/efi/efivars/StubPcrKernelImage-4a67b082-0a4c-4
[Service]
Type=oneshot
RemainAfterExit=yes
-ExecStart={{ROOTLIBEXECDIR}}/systemd-pcrphase enter-initrd
-ExecStop={{ROOTLIBEXECDIR}}/systemd-pcrphase leave-initrd
+ExecStart={{ROOTLIBEXECDIR}}/systemd-pcrphase --graceful enter-initrd
+ExecStop={{ROOTLIBEXECDIR}}/systemd-pcrphase --graceful leave-initrd
diff --git a/units/systemd-pcrphase-sysinit.service.in b/units/systemd-pcrphase-sysinit.service.in
index 6b5ba7d878..a22fbbe935 100644
--- a/units/systemd-pcrphase-sysinit.service.in
+++ b/units/systemd-pcrphase-sysinit.service.in
@@ -21,5 +21,5 @@ ConditionPathExists=/sys/firmware/efi/efivars/StubPcrKernelImage-4a67b082-0a4c-4
[Service]
Type=oneshot
RemainAfterExit=yes
-ExecStart={{ROOTLIBEXECDIR}}/systemd-pcrphase sysinit
-ExecStop={{ROOTLIBEXECDIR}}/systemd-pcrphase final
+ExecStart={{ROOTLIBEXECDIR}}/systemd-pcrphase --graceful sysinit
+ExecStop={{ROOTLIBEXECDIR}}/systemd-pcrphase --graceful final
diff --git a/units/systemd-pcrphase.service.in b/units/systemd-pcrphase.service.in
index ce469befa8..5ba437e5b1 100644
--- a/units/systemd-pcrphase.service.in
+++ b/units/systemd-pcrphase.service.in
@@ -19,5 +19,5 @@ ConditionPathExists=/sys/firmware/efi/efivars/StubPcrKernelImage-4a67b082-0a4c-4
[Service]
Type=oneshot
RemainAfterExit=yes
-ExecStart={{ROOTLIBEXECDIR}}/systemd-pcrphase ready
-ExecStop={{ROOTLIBEXECDIR}}/systemd-pcrphase shutdown
+ExecStart={{ROOTLIBEXECDIR}}/systemd-pcrphase --graceful ready
+ExecStop={{ROOTLIBEXECDIR}}/systemd-pcrphase --graceful shutdown