From 855b4cd731fbded090f6ea38aaa553393cba3253 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 24 Dec 2025 08:37:22 +0100 Subject: [PATCH 1/3] analyze: properly handle nvpcrs that have not been initialized yet Let's explicitly check if NvPCRs are fully set up (allocated, anchored) before we try to show them. Alternative to: #40184 --- src/analyze/analyze-nvpcrs.c | 9 ++++---- src/shared/tpm2-util.c | 40 ++++++++++++++++++++++++++++-------- 2 files changed, 36 insertions(+), 13 deletions(-) diff --git a/src/analyze/analyze-nvpcrs.c b/src/analyze/analyze-nvpcrs.c index 4da2452393510..ae134dfc2b27b 100644 --- a/src/analyze/analyze-nvpcrs.c +++ b/src/analyze/analyze-nvpcrs.c @@ -27,10 +27,11 @@ static int add_nvpcr_to_table(Tpm2Context **c, Table *t, const char *name) { r = tpm2_nvpcr_read(*c, /* session= */ NULL, name, &digest, &nv_index); if (r < 0) return log_error_errno(r, "Failed to read NvPCR '%s': %m", name); - - h = hexmem(digest.iov_base, digest.iov_len); - if (!h) - return log_oom(); + if (r > 0) { /* set? */ + h = hexmem(digest.iov_base, digest.iov_len); + if (!h) + return log_oom(); + } } else { r = tpm2_nvpcr_get_index(name, &nv_index); if (r < 0) diff --git a/src/shared/tpm2-util.c b/src/shared/tpm2-util.c index 4ba83a47ae0dc..8592485bf478a 100644 --- a/src/shared/tpm2-util.c +++ b/src/shared/tpm2-util.c @@ -7474,6 +7474,21 @@ int tpm2_nvpcr_read( if (r < 0) return r; + /* Check if the NvPCR is already anchored */ + const char *anchor_fname = strjoina("/run/systemd/nvpcr/", name, ".anchor"); + r = access_nofollow(anchor_fname, F_OK); + if (r < 0) { + if (r != -ENOENT) + return log_debug_errno(r, "Failed to check if '%s' exists: %m", anchor_fname); + + /* valid, but not anchored */ + *ret_value = (struct iovec) {}; + if (ret_nv_index) + *ret_nv_index = p.nv_index; + + return 0; + } + _cleanup_(tpm2_handle_freep) Tpm2Handle *nv_handle = NULL; r = tpm2_index_to_handle( c, @@ -7488,19 +7503,26 @@ int tpm2_nvpcr_read( log_debug("Successfully acquired handle to NV index 0x%" PRIx32 ".", p.nv_index); - r = tpm2_read_nv_index( - c, - /* session= */ NULL, - p.nv_index, - nv_handle, - ret_value); - if (r < 0) - return r; + if (r > 0) { + r = tpm2_read_nv_index( + c, + /* session= */ NULL, + p.nv_index, + nv_handle, + ret_value); + if (r < 0) + return r; + + r = 1; + } else { + *ret_value = (struct iovec) {}; + r = 0; + } if (ret_nv_index) *ret_nv_index = p.nv_index; - return 0; + return r; #else /* HAVE_OPENSSL */ return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "OpenSSL support is disabled."); #endif From 82dea1c9254a59fac8f304a262ad086cd51724b8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 2 Jan 2026 16:30:58 +0100 Subject: [PATCH 2/3] switch-root: don't do rm_rf() of old superblock on switch root if pivot_root() worked We do the rm_rf_children() call only because in some cases we cannot pivot_root() and hence the orginal root superblock stays pinned, and we thus have to empty it to minimize its memory use. But if pivot_root() worked (and the umount() for the old root), then there's really no need to do this work. Dropping this codepath is useful in context of Christian's recent work to make the original initrd tmpfs unmountable, which means pivot_root() will work, and thus there's no need to empty the tmpfs anymore, and we can speed up boot a bit. Fixes: #40250 --- src/shared/switch-root.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/shared/switch-root.c b/src/shared/switch-root.c index d5f34c5d37d4e..6017200d79c3e 100644 --- a/src/shared/switch-root.c +++ b/src/shared/switch-root.c @@ -54,7 +54,7 @@ int switch_root(const char *new_root, if (new_root_fd < 0) return log_error_errno(errno, "Failed to open target directory '%s': %m", new_root); - r = fds_are_same_mount(old_root_fd, new_root_fd); + r = fds_are_same_mount(old_root_fd, new_root_fd); /* checks if referenced inodes and mounts match */ if (r < 0) return log_error_errno(r, "Failed to check if old and new root directory/mount are the same: %m"); if (r > 0) { @@ -186,18 +186,23 @@ int switch_root(const char *new_root, if (chdir(".") < 0) return log_error_errno(errno, "Failed to change directory: %m"); - } - if (istmp > 0) { - struct stat rb; + /* Now empty the old root superblock */ + if (istmp > 0) { + struct stat rb; - if (fstat(old_root_fd, &rb) < 0) - return log_error_errno(errno, "Failed to stat old root directory: %m"); + if (fstat(old_root_fd, &rb) < 0) + return log_error_errno(errno, "Failed to stat old root directory: %m"); - /* Note: the below won't operate on non-memory file systems (i.e. only on tmpfs, ramfs), and - * it will stop at mount boundaries */ - (void) rm_rf_children(TAKE_FD(old_root_fd), 0, &rb); /* takes possession of the dir fd, even on failure */ - } + /* Note: the below won't operate on non-memory file systems (i.e. only on tmpfs, ramfs), and + * it will stop at mount boundaries */ + (void) rm_rf_children(TAKE_FD(old_root_fd), 0, &rb); /* takes possession of the dir fd, even on failure */ + } + } else + /* NB: we don't bother with emptying the old root superblock here, under the assumption the + * pivot_root() + umount() sufficiently detached from the superblock to the point we don't + * need to empty it anymore */ + log_debug("Pivoting root worked."); return 0; } From cf79f61238fa812d1850987e04d3767ce71dd972 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 4 Jan 2026 09:37:46 +0900 Subject: [PATCH 3/3] calendarspec: day of month also needs to be reset when year is changed Fixes #40260. --- src/shared/calendarspec.c | 5 +++-- src/test/test-calendarspec.c | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/shared/calendarspec.c b/src/shared/calendarspec.c index 88a4467187c5d..dc13ae0f77994 100644 --- a/src/shared/calendarspec.c +++ b/src/shared/calendarspec.c @@ -1194,9 +1194,10 @@ static int tm_within_bounds(struct tm *tm, bool utc) { * other sub time units are already reset in find_next(). */ int cmp; - if ((cmp = CMP(t.tm_year, tm->tm_year)) != 0) + if ((cmp = CMP(t.tm_year, tm->tm_year)) != 0) { t.tm_mon = 0; - else if ((cmp = CMP(t.tm_mon, tm->tm_mon)) != 0) + t.tm_mday = 1; + } else if ((cmp = CMP(t.tm_mon, tm->tm_mon)) != 0) t.tm_mday = 1; else if ((cmp = CMP(t.tm_mday, tm->tm_mday)) != 0) t.tm_hour = 0; diff --git a/src/test/test-calendarspec.c b/src/test/test-calendarspec.c index 0b1cbacd625a2..6c901b1893c57 100644 --- a/src/test/test-calendarspec.c +++ b/src/test/test-calendarspec.c @@ -219,6 +219,8 @@ TEST(calendar_spec_next) { test_next("Sun *-*-* 01:00:00 Europe/Dublin", "IST", 1616412478000000, 1617494400000000); /* Europe/Dublin TZ that moves DST backwards */ test_next("hourly", "IST-1GMT-0,M10.5.0/1,M3.5.0/1", 1743292800000000, 1743296400000000); + /* Check when the year changes, see issue #40260 */ + test_next("*-*-1/11 23:00:00 UTC", "", 1763938800000000, 1764630000000000); } TEST(calendar_spec_from_string) {