diff --git a/catalog/systemd.catalog.in b/catalog/systemd.catalog.in index 473edf2f07bcc..6f6ca9c4ea851 100644 --- a/catalog/systemd.catalog.in +++ b/catalog/systemd.catalog.in @@ -1002,3 +1002,16 @@ device nodes appear early in boot, while regular users may appear only later. For devices managed by systemd-udevd, it is instead recommended to use the "uaccess"/"xaccess" mechanisms to grant limited and temporary access to device nodes, see sd-login(8). + +-- ab984ea008964fb88d6e389fb513fb94 +Subject: TPM NV index space exhausted, unable to initialize NvPCR +Defined-By: systemd +Support: %SUPPORT_URL% + +The Trusted Platform Module's (TPM) NV index space has been exhausted, and an +additional NvPCR, i.e. additional Platform Configuration Register (PCR) stored in +non-volatile indexes (NV Indexes), could not be initialized. + +This typically means the persistent NV index memory available on the TPM is +taken up by other resources, or is extremely limited. A TPM reset might help +recovering space (but will invalidate all TPM bound keys and resources). diff --git a/src/shared/tpm2-util.c b/src/shared/tpm2-util.c index 3b559bf84c2bc..4de6f46aed60c 100644 --- a/src/shared/tpm2-util.c +++ b/src/shared/tpm2-util.c @@ -6031,6 +6031,9 @@ int tpm2_define_nvpcr_nv_index( /* auth= */ NULL, &public_info, &new_handle->esys_handle); + if (rc == TPM2_RC_NV_SPACE) + return log_debug_errno(SYNTHETIC_ERRNO(ENOSPC), + "NV index space on TPM exhausted, cannot allocate NvPCR."); if (rc == TPM2_RC_NV_DEFINED) { log_debug("NV index 0x%" PRIu32 " already registered.", nv_index); @@ -7326,7 +7329,7 @@ int tpm2_nvpcr_initialize( _cleanup_close_ int dfd = open_mkdir("/run/systemd/nvpcr", O_CLOEXEC, 0755); if (dfd < 0) - return log_error_errno(dfd, "Failed to open directory '/run/systemd/nvpcr': %m"); + return log_debug_errno(dfd, "Failed to open directory '/run/systemd/nvpcr': %m"); const char *anchor_fname = strjoina(name, ".anchor"); if (faccessat(dfd, anchor_fname, F_OK, AT_SYMLINK_NOFOLLOW) < 0) { diff --git a/src/shared/varlink-io.systemd.Hostname.c b/src/shared/varlink-io.systemd.Hostname.c index e10f113046639..e06587039b510 100644 --- a/src/shared/varlink-io.systemd.Hostname.c +++ b/src/shared/varlink-io.systemd.Hostname.c @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "bus-polkit.h" -#include "varlink-io.systemd.Credentials.h" +#include "varlink-io.systemd.Hostname.h" static SD_VARLINK_DEFINE_METHOD( Describe, @@ -28,8 +28,8 @@ static SD_VARLINK_DEFINE_METHOD( SD_VARLINK_DEFINE_OUTPUT(OperatingSystemHomeURL, SD_VARLINK_STRING, SD_VARLINK_NULLABLE), SD_VARLINK_DEFINE_OUTPUT(OperatingSystemSupportEnd, SD_VARLINK_INT, SD_VARLINK_NULLABLE), SD_VARLINK_DEFINE_OUTPUT(OperatingSystemReleaseData, SD_VARLINK_STRING, SD_VARLINK_NULLABLE|SD_VARLINK_ARRAY), - SD_VARLINK_DEFINE_OUTPUT(OperatingSystemImageID, SD_VARLINK_INT, SD_VARLINK_NULLABLE), - SD_VARLINK_DEFINE_OUTPUT(OperatingSystemImageVersion, SD_VARLINK_INT, SD_VARLINK_NULLABLE), + SD_VARLINK_DEFINE_OUTPUT(OperatingSystemImageID, SD_VARLINK_STRING, SD_VARLINK_NULLABLE), + SD_VARLINK_DEFINE_OUTPUT(OperatingSystemImageVersion, SD_VARLINK_STRING, SD_VARLINK_NULLABLE), SD_VARLINK_DEFINE_OUTPUT(MachineInformationData, SD_VARLINK_STRING, SD_VARLINK_NULLABLE|SD_VARLINK_ARRAY), SD_VARLINK_DEFINE_OUTPUT(HardwareVendor, SD_VARLINK_STRING, SD_VARLINK_NULLABLE), SD_VARLINK_DEFINE_OUTPUT(HardwareModel, SD_VARLINK_STRING, SD_VARLINK_NULLABLE), diff --git a/src/systemd/sd-messages.h b/src/systemd/sd-messages.h index 5465db8b1311f..7bc4199408f13 100644 --- a/src/systemd/sd-messages.h +++ b/src/systemd/sd-messages.h @@ -306,6 +306,9 @@ _SD_BEGIN_DECLARATIONS; #define SD_MESSAGE_SYSTEM_ACCOUNT_REQUIRED SD_ID128_MAKE(34,05,20,5d,36,8e,49,fe,b5,ab,39,25,fe,e1,38,74) #define SD_MESSAGE_SYSTEM_ACCOUNT_REQUIRED_STR SD_ID128_MAKE_STR(34,05,20,5d,36,8e,49,fe,b5,ab,39,25,fe,e1,38,74) +#define SD_MESSAGE_TPM_INVINDEX_EXHAUSTED SD_ID128_MAKE(ab,98,4e,a0,08,96,4f,b8,8d,6e,38,9f,b5,13,fb,94) +#define SD_MESSAGE_TPM_INVINDEX_EXHAUSTED_STR SD_ID128_MAKE_STR(ab,98,4e,a0,08,96,4f,b8,8d,6e,38,9f,b5,13,fb,94) + _SD_END_DECLARATIONS; #endif diff --git a/src/tpm2-setup/tpm2-setup.c b/src/tpm2-setup/tpm2-setup.c index 1d057ea0e24da..a811ea436dbee 100644 --- a/src/tpm2-setup/tpm2-setup.c +++ b/src/tpm2-setup/tpm2-setup.c @@ -385,7 +385,7 @@ static int setup_srk(void) { typedef struct SetupNvPCRContext { Tpm2Context *tpm2_context; struct iovec anchor_secret; - size_t n_already, n_anchored; + size_t n_already, n_anchored, n_failed; Set *done; } SetupNvPCRContext; @@ -404,16 +404,11 @@ static int setup_nvpcr_one( assert(c); assert(name); + assert(c->tpm2_context); if (set_contains(c->done, name)) return 0; - if (!c->tpm2_context) { - r = tpm2_context_new_or_warn(arg_tpm2_device, &c->tpm2_context); - if (r < 0) - return r; - } - r = tpm2_nvpcr_initialize(c->tpm2_context, /* session= */ NULL, name, &c->anchor_secret); if (r == -EUNATCH) { assert(!iovec_is_set(&c->anchor_secret)); @@ -427,8 +422,16 @@ static int setup_nvpcr_one( r = tpm2_nvpcr_initialize(c->tpm2_context, /* session= */ NULL, name, &c->anchor_secret); } - if (r < 0) + if (r == -ENOSPC) { + c->n_failed++; + return log_struct_errno(LOG_ERR, r, + LOG_MESSAGE("The TPM's NV index space is exhausted, unable to allocate NvPCR '%s': %m", name), + LOG_MESSAGE_ID(SD_MESSAGE_TPM_INVINDEX_EXHAUSTED_STR)); + } + if (r < 0) { + c->n_failed++; return log_error_errno(r, "Failed to extend NvPCR index with anchor secret: %m"); + } if (r > 0) c->n_anchored++; @@ -455,10 +458,17 @@ static int setup_nvpcr(void) { if (r < 0) return log_error_errno(r, "Failed to find .nvpcr files: %m"); + int ret = 0; STRV_FOREACH(i, l) { - r = setup_nvpcr_one(&c, *i); - if (r < 0) - return r; + if (!c.tpm2_context) { + /* Inability to contact the TPM shall be fatal for us */ + r = tpm2_context_new_or_warn(arg_tpm2_device, &c.tpm2_context); + if (r < 0) + return r; + } + + /* But if we fail to initialize some NvPCR, we go on */ + RET_GATHER(ret, setup_nvpcr_one(&c, *i)); } if (c.n_already > 0 && c.n_anchored == 0 && !arg_early) { @@ -466,11 +476,12 @@ static int setup_nvpcr(void) { * have happened in the initrd, and thus the anchor ID was not committed to /var/ or the ESP * yet. Hence, let's explicitly do so now, to catch up. */ - r = tpm2_nvpcr_acquire_anchor_secret(/* ret= */ NULL, /* sync_secondary= */ true); - if (r < 0) - return r; + RET_GATHER(ret, tpm2_nvpcr_acquire_anchor_secret(/* ret= */ NULL, /* sync_secondary= */ true)); } + if (c.n_failed > 0) + log_warning("%zu NvPCRs failed to initialize, proceeding anyway.", c.n_failed); + if (c.n_anchored > 0) { if (c.n_already == 0) log_info("%zu NvPCRs initialized.", c.n_anchored); @@ -478,10 +489,10 @@ static int setup_nvpcr(void) { log_info("%zu NvPCRs initialized. (%zu NvPCRs were already initialized.)", c.n_anchored, c.n_already); } else if (c.n_already > 0) log_info("%zu NvPCRs already initialized.", c.n_already); - else + else if (c.n_failed == 0) log_debug("No NvPCRs defined, nothing initialized."); - return r; + return ret; } static int run(int argc, char *argv[]) {