Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions catalog/systemd.catalog.in
Original file line number Diff line number Diff line change
Expand Up @@ -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).
5 changes: 4 additions & 1 deletion src/shared/tpm2-util.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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) {
Expand Down
6 changes: 3 additions & 3 deletions src/shared/varlink-io.systemd.Hostname.c
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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),
Expand Down
3 changes: 3 additions & 0 deletions src/systemd/sd-messages.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
43 changes: 27 additions & 16 deletions src/tpm2-setup/tpm2-setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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));
Expand All @@ -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++;
Expand All @@ -455,33 +458,41 @@ 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) {
/* If we didn't anchor anything right now, but we anchored something earlier, then it might
* 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);
else
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[]) {
Expand Down
Loading