From: Lennart Poettering Date: Thu, 26 Feb 2026 10:23:08 +0000 (+0100) Subject: tpm2-setup: make NV index space exhaustion issues more discoverable X-Git-Tag: v260-rc2~69^2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=ac8266c7c2e787dc8ffb01a09070fd34ee0a42ea;p=thirdparty%2Fsystemd.git tpm2-setup: make NV index space exhaustion issues more discoverable Let's log about this explicitly, and include a message catalog entry for it. --- diff --git a/catalog/systemd.catalog.in b/catalog/systemd.catalog.in index 473edf2f07b..6f6ca9c4ea8 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 32ad35df49d..4de6f46aed6 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); diff --git a/src/systemd/sd-messages.h b/src/systemd/sd-messages.h index 5465db8b131..7bc4199408f 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 1d057ea0e24..a811ea436db 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[]) {