]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
measure: Take SizeOfImage into account as well for .linux section
authorDaan De Meyer <daan.j.demeyer@gmail.com>
Fri, 4 Oct 2024 08:22:37 +0000 (10:22 +0200)
committerDaan De Meyer <daan.j.demeyer@gmail.com>
Sun, 20 Oct 2024 11:22:54 +0000 (13:22 +0200)
Same change as https://github.com/systemd/systemd/pull/34583 but for
systemd-measure. Otherwise we end up with PCR policy digest mismatches
as systemd-stub will measure the full virtual size of the kernel image
after it has been loaded while systemd-measure will disregard the extra
size introduced by SizeOfImage.

While ideally the stub would only measure the data that's actually on
disk and not the uninitialized data introduced by VirtualSize > SizeOfRawData,
we want newer systemd-measure to work with older stubs so we have to fix
systemd-measure and can't fix this in the stub.

src/boot/measure.c

index 36d42147a1f360fdd9bd594526dc5a044be1abb3..f2d644ff03699ab509a63bac3978a4bef10fa767 100644 (file)
@@ -16,6 +16,7 @@
 #include "openssl-util.h"
 #include "parse-argument.h"
 #include "parse-util.h"
+#include "pe-binary.h"
 #include "pretty-print.h"
 #include "sha256.h"
 #include "strv.h"
@@ -517,6 +518,38 @@ static int measure_kernel(PcrState *pcr_states, size_t n) {
                         m += sz;
                 }
 
+                if (c == UNIFIED_SECTION_LINUX) {
+                        _cleanup_free_ PeHeader *pe_header = NULL;
+
+                        r = pe_load_headers(fd, /*ret_dos_header=*/ NULL, &pe_header);
+                        if (r < 0)
+                                log_warning_errno(r, "Failed to parse kernel image file '%s', ignoring: %m", arg_sections[c]);
+                        else if (m < pe_header->optional.SizeOfImage) {
+                                memzero(buffer, BUFFER_SIZE);
+
+                                /* Our EFI stub measures VirtualSize bytes of the .linux section into PCR 11.
+                                 * Notably, VirtualSize can be larger than the section's size on disk. In
+                                 * that case the extra space is initialized with zeros, so the stub ends up
+                                 * measuring a bunch of zeros. To accomodate this, we have to measure the
+                                 * same number of zeros here. We opt to measure extra zeros here instead of
+                                 * modifying the stub to only measure the number of bytes on disk as we want
+                                 * newer ukify + systemd-measure to work with older versions of the stub and
+                                 * as of 6.12 the kernel image's VirtualSize won't be larger than its size on
+                                 * disk anymore (see https://github.com/systemd/systemd/issues/34578#issuecomment-2382459515).
+                                 */
+
+                                while (m < pe_header->optional.SizeOfImage) {
+                                        uint64_t sz = MIN(BUFFER_SIZE, pe_header->optional.SizeOfImage - m);
+
+                                        for (size_t i = 0; i < n; i++)
+                                                if (EVP_DigestUpdate(mdctx[i], buffer, sz) != 1)
+                                                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to run digest.");
+
+                                        m += sz;
+                                }
+                        }
+                }
+
                 fd = safe_close(fd);
 
                 if (m == 0) /* We skip over empty files, the stub does so too */