:: commit 2e19eb6a841366dcd0fee299f2156ed5b96abbe9

Mintsuki <mintsuki@protonmail.com> — 2026-04-30 17:21

parents: 4f55a8f051

lib/misc: Measure device tree blob before fdt_open_into resizes it

diff --git a/common/lib/misc.c b/common/lib/misc.c
index 1173e70d..de7f50a0 100644
--- a/common/lib/misc.c
+++ b/common/lib/misc.c
@@ -10,6 +10,7 @@
 #include <lib/uri.h>
 #include <lib/bli.h>
 #include <lib/rng_seed.h>
+#include <lib/tpm.h>
 #include <fs/file.h>
 #include <mm/pmm.h>
 #include <libfdt.h>
@@ -117,7 +118,8 @@ size_t get_trailing_zeros(uint64_t val) {
     return 64;
 }
 
-void *get_device_tree_blob(const char *config, size_t extra_size) {
+void *get_device_tree_blob(const char *config, size_t extra_size,
+                           const char *measure_label) {
     int ret;
 
     size_t size = 0;
@@ -152,6 +154,13 @@ void *get_device_tree_blob(const char *config, size_t extra_size) {
                 panic(soft_panic, "dtb: Invalid device tree blob at `%#`: '%s'", dtb_path, fdt_strerror(ret));
             }
 
+#if defined (UEFI)
+            if (measure_label != NULL) {
+                tpm_measure(TPM_PCR_LOADED_IMAGES, TPM_EV_IPL,
+                            dtb, size, measure_label);
+            }
+#endif
+
             printv("dtb: loaded dtb at %p from file `%#`\n", dtb, dtb_path);
         }
     }
@@ -164,6 +173,10 @@ void *get_device_tree_blob(const char *config, size_t extra_size) {
             if (memcmp(&cur_table->VendorGuid, &dtb_guid, sizeof(EFI_GUID)))
                 continue;
             size = fdt_totalsize(cur_table->VendorTable);
+            if (measure_label != NULL) {
+                tpm_measure(TPM_PCR_LOADED_IMAGES, TPM_EV_IPL,
+                            cur_table->VendorTable, size, measure_label);
+            }
             dtb = ext_mem_alloc(size);
             ret = fdt_open_into(cur_table->VendorTable, dtb, size);
             if (ret < 0) {
@@ -173,6 +186,8 @@ void *get_device_tree_blob(const char *config, size_t extra_size) {
             break;
         }
     }
+#else
+    (void)measure_label;
 #endif
 
     if (extra_size == 0) {
diff --git a/common/lib/misc.h b/common/lib/misc.h
index 5de32a92..394449dc 100644
--- a/common/lib/misc.h
+++ b/common/lib/misc.h
@@ -30,7 +30,8 @@ bool efi_exit_boot_services(void);
 bool is_efi_serial_present(void);
 #endif
 
-void *get_device_tree_blob(const char *config, size_t extra_size);
+void *get_device_tree_blob(const char *config, size_t extra_size,
+                           const char *measure_label);
 
 extern struct volume *boot_volume;
 
diff --git a/common/protos/limine.c b/common/protos/limine.c
index b1a6b212..d13213c1 100644
--- a/common/protos/limine.c
+++ b/common/protos/limine.c
@@ -1180,16 +1180,9 @@ FEAT_START
         break; // next feature
     }
 
-    void *dtb = get_device_tree_blob(config, 0);
+    void *dtb = get_device_tree_blob(config, 0, "Limine DTB");
 
     if (dtb) {
-#if defined (UEFI)
-        // Measure the device tree as loaded, before applying our memory-node
-        // fixups below, so the resulting PCR is stable across boots.
-        tpm_measure(TPM_PCR_LOADED_IMAGES, TPM_EV_IPL,
-                    dtb, fdt_totalsize(dtb), "Limine DTB");
-#endif
-
         // Delete all /memory@... nodes.
         // The executable must use the given UEFI memory map instead.
         while (true) {
diff --git a/common/protos/linux_risc.c b/common/protos/linux_risc.c
index bdb8f07e..9b15e023 100644
--- a/common/protos/linux_risc.c
+++ b/common/protos/linux_risc.c
@@ -172,11 +172,6 @@ static void prepare_device_tree_blob(struct boot_param *p) {
     void *dtb = p->dtb;
     int ret;
 
-    // Measure the device tree as loaded, before applying our /chosen and
-    // memory-node fixups, so the resulting PCR is stable across boots.
-    tpm_measure(TPM_PCR_LOADED_IMAGES, TPM_EV_IPL,
-                dtb, fdt_totalsize(dtb), "Linux DTB");
-
     // Delete all /memory@... nodes. Linux will use the given UEFI memory map
     // instead.
     while (true) {
@@ -474,7 +469,7 @@ noreturn void linux_load(char *config, char *cmdline) {
     struct boot_param p;
     memset(&p, 0, sizeof(p));
     p.cmdline = cmdline;
-    p.dtb = get_device_tree_blob(config, 0x1000);
+    p.dtb = get_device_tree_blob(config, 0x1000, "Linux DTB");
 
     if (cmdline != NULL) {
         tpm_measure(TPM_PCR_BOOT_AUTH, TPM_EV_IPL,
diff --git a/common/sys/cpu_riscv.c b/common/sys/cpu_riscv.c
index 0330b45d..70210622 100644
--- a/common/sys/cpu_riscv.c
+++ b/common/sys/cpu_riscv.c
@@ -313,7 +313,7 @@ void init_riscv(const char *config) {
     if (!prioritise_dtb && acpi_get_rsdp()) {
         init_riscv_acpi();
     } else {
-        riscv_fdt = get_device_tree_blob(config, 0);
+        riscv_fdt = get_device_tree_blob(config, 0, NULL);
         if (riscv_fdt != NULL) {
             init_riscv_fdt(riscv_fdt);
         } else {
diff --git a/common/sys/smp.c b/common/sys/smp.c
index 7393218b..feb68c87 100644
--- a/common/sys/smp.c
+++ b/common/sys/smp.c
@@ -798,7 +798,7 @@ struct limine_mp_info *init_smp(const char *config,
         return info;
 
     // No RSDP means no ACPI, try device trees in that case.
-    void *dtb = get_device_tree_blob(config, 0);
+    void *dtb = get_device_tree_blob(config, 0, NULL);
     if (dtb) {
         info = try_dtb_smp(dtb,
                            cpu_count, bsp_mpidr, pagemap,
@@ -1212,7 +1212,7 @@ struct limine_mp_info *init_smp(size_t *cpu_count, uint32_t *bsp_phys_id,
     if (acpi_get_rsdp() && (info = try_acpi_smp(cpu_count, bsp_phys_id, pagemap, hhdm_offset)))
         return info;
 
-    void *dtb = get_device_tree_blob(NULL, 0);
+    void *dtb = get_device_tree_blob(NULL, 0, NULL);
     if (dtb) {
         info = try_dtb_smp(dtb, cpu_count, bsp_phys_id, pagemap, hhdm_offset);
         pmm_free(dtb, fdt_totalsize(dtb));
tab: 248 wrap: offon