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).
#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
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;
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));
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++;
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) {
* 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);
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[]) {