:: commit 932d17b7fdfcbc1eb4109cc4a0e8ca4f055523ff

Mintsuki <mintsuki@protonmail.com> — 2026-04-30 15:53

parents: c8326335f1

lib/misc: Add measured_boot config option

diff --git a/common/lib/config.c b/common/lib/config.c
index af4f56d3..45baec1a 100644
--- a/common/lib/config.c
+++ b/common/lib/config.c
@@ -28,6 +28,18 @@ no_unwind bool bad_config = false;
 
 static char *config_addr;
 
+#if defined (UEFI)
+// Snapshot of the on-disk config bytes, kept across the in-place mutations
+// in init_config so the menu can measure them once measured_boot is known.
+static char *config_raw_addr;
+static size_t config_raw_size;
+
+const char *config_get_raw(size_t *size_out) {
+    *size_out = config_raw_size;
+    return config_raw_addr;
+}
+#endif
+
 #if defined (UEFI)
 
 #define EFI_APP_PATH_LEN 128
@@ -386,9 +398,11 @@ int init_config(size_t config_size) {
     }
 
 #if defined (UEFI)
-    // Measure the on-disk config bytes before the in-place mutations below.
-    tpm_measure(TPM_PCR_BOOT_AUTH, TPM_EV_IPL,
-                config_addr, config_size - 2, "Limine config");
+    // Snapshot the raw bytes; the menu measures them once measured_boot
+    // is final.
+    config_raw_size = config_size - 2;
+    config_raw_addr = ext_mem_alloc(config_raw_size);
+    memcpy(config_raw_addr, config_addr, config_raw_size);
 #endif
 
     // add trailing newline if not present
diff --git a/common/lib/config.h b/common/lib/config.h
index ff2a8fdd..7952e385 100644
--- a/common/lib/config.h
+++ b/common/lib/config.h
@@ -29,6 +29,10 @@ int init_config_disk(struct volume *part);
 bool init_config_smbios(void);
 int init_config(size_t config_size);
 
+#if defined (UEFI)
+const char *config_get_raw(size_t *size_out);
+#endif
+
 char *config_get_value(const char *config, size_t index, const char *key);
 struct conf_tuple config_get_tuple(const char *config, size_t index,
                                    const char *key1, const char *key2);
diff --git a/common/lib/misc.h b/common/lib/misc.h
index 00d815b2..5de32a92 100644
--- a/common/lib/misc.h
+++ b/common/lib/misc.h
@@ -38,7 +38,7 @@ extern struct volume *boot_volume;
 extern bool stage3_loaded;
 #endif
 
-extern bool quiet, serial, editor_enabled, help_hidden, hash_mismatch_panic, secure_boot_active;
+extern bool quiet, serial, editor_enabled, help_hidden, hash_mismatch_panic, secure_boot_active, measured_boot;
 
 extern uint64_t usec_at_bootloader_entry;
 
diff --git a/common/lib/misc.s2.c b/common/lib/misc.s2.c
index 9f486980..1995a390 100644
--- a/common/lib/misc.s2.c
+++ b/common/lib/misc.s2.c
@@ -7,6 +7,7 @@ bool verbose = false;
 bool quiet = false;
 bool serial = false;
 bool hash_mismatch_panic = false;
+bool measured_boot = false;
 
 uint8_t bcd_to_int(uint8_t val) {
     return (val & 0x0f) + ((val & 0xf0) >> 4) * 10;
diff --git a/common/lib/panic.s2.c b/common/lib/panic.s2.c
index 8bbc050e..91753fb6 100644
--- a/common/lib/panic.s2.c
+++ b/common/lib/panic.s2.c
@@ -19,6 +19,14 @@ noreturn void panic(bool allow_menu, const char *fmt, ...) {
 
     va_start(args, fmt);
 
+#if defined (UEFI)
+    // Don't return to the menu under measured boot: a partial boot may
+    // have already dirtied the TPM PCRs.
+    if (measured_boot) {
+        allow_menu = false;
+    }
+#endif
+
     quiet = false;
 
     FOR_TERM(TERM->autoflush = true);
diff --git a/common/lib/tpm.c b/common/lib/tpm.c
index 55ea83fa..53ed40fe 100644
--- a/common/lib/tpm.c
+++ b/common/lib/tpm.c
@@ -93,10 +93,14 @@ void tpm_init(void) {
     }
 }
 
+bool tpm_present(void) {
+    return tcg2 != NULL || cc != NULL;
+}
+
 void tpm_measure(uint32_t pcr, uint32_t event_type,
                  const void *data, size_t data_size,
                  const char *description) {
-    if (data == NULL) {
+    if (!measured_boot || data == NULL) {
         return;
     }
 
diff --git a/common/lib/tpm.h b/common/lib/tpm.h
index c94bc277..91d81a81 100644
--- a/common/lib/tpm.h
+++ b/common/lib/tpm.h
@@ -17,6 +17,10 @@
 #if defined (UEFI)
 
 void tpm_init(void);
+
+// True if a TCG2 or CC measurement protocol is available.
+bool tpm_present(void);
+
 void tpm_measure(uint32_t pcr, uint32_t event_type,
                  const void *data, size_t data_size,
                  const char *description);
diff --git a/common/menu.c b/common/menu.c
index ad9e9b01..98ae2556 100644
--- a/common/menu.c
+++ b/common/menu.c
@@ -9,6 +9,9 @@
 #include <lib/misc.h>
 #include <lib/libc.h>
 #include <lib/config.h>
+#if defined (UEFI)
+#  include <lib/tpm.h>
+#endif
 #include <lib/term.h>
 #include <lib/gterm.h>
 #include <lib/getchar.h>
@@ -1174,6 +1177,26 @@ noreturn void _menu(bool first_run) {
         editor_enabled = false;
     }
 
+#if defined (UEFI)
+    char *measured_boot_str = config_get_value(NULL, 0, "MEASURED_BOOT");
+    measured_boot = measured_boot_str != NULL && strcmp(measured_boot_str, "yes") == 0;
+    if (secure_boot_active) {
+        measured_boot = true;
+    }
+    // Cannot do measured boot without a TPM/CC interface.
+    if (!tpm_present()) {
+        measured_boot = false;
+    }
+
+    // Measure the on-disk config bytes now that measured_boot is final.
+    size_t raw_size;
+    const char *raw = config_get_raw(&raw_size);
+    if (raw != NULL) {
+        tpm_measure(TPM_PCR_BOOT_AUTH, TPM_EV_IPL,
+                    raw, raw_size, "Limine config");
+    }
+#endif
+
     char *randomise_mem_str = config_get_value(NULL, 0, "RANDOMISE_MEMORY");
     if (randomise_mem_str == NULL)
         randomise_mem_str = config_get_value(NULL, 0, "RANDOMIZE_MEMORY");
diff --git a/common/protos/limine.c b/common/protos/limine.c
index 4e51f53e..ea07f461 100644
--- a/common/protos/limine.c
+++ b/common/protos/limine.c
@@ -1341,7 +1341,10 @@ FEAT_START
         print("limine: Loading module `%#`...\n", module_path);
 
         struct file_handle *f;
-        if ((f = uri_open(module_path, MEMMAP_KERNEL_AND_MODULES, true
+        // Refuse >4 GiB allocations under measured boot on IA-32: firmware's
+        // HashLogExtendEvent can't reach them, so we'd be unable to measure
+        // the module.
+        if ((f = uri_open(module_path, MEMMAP_KERNEL_AND_MODULES, !measured_boot
 #if defined (__i386__)
             , limine_memcpy_to_64, limine_memcpy_from_64
 #endif
@@ -1363,10 +1366,8 @@ FEAT_START
         *l = get_file(f, module_cmdline);
 
 #if defined (UEFI)
-        if (!f->is_high_mem) {
-            tpm_measure(TPM_PCR_LOADED_IMAGES, TPM_EV_IPL,
-                        f->fd, f->size, "Limine module");
-        }
+        tpm_measure(TPM_PCR_LOADED_IMAGES, TPM_EV_IPL,
+                    f->fd, f->size, "Limine module");
 #endif
 
         fclose(f);
tab: 248 wrap: offon