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);
