]> xenbits.xensource.com Git - people/andrewcoop/xen.git/commitdiff
arch/x86: process DRTM policy
authorSergii Dmytruk <sergii.dmytruk@3mdeb.com>
Sat, 28 Oct 2023 21:42:04 +0000 (00:42 +0300)
committerKrystian Hebel <krystian.hebel@3mdeb.com>
Fri, 26 Apr 2024 16:11:03 +0000 (18:11 +0200)
Signed-off-by: Sergii Dmytruk <sergii.dmytruk@3mdeb.com>
xen/arch/x86/include/asm/intel_txt.h
xen/arch/x86/setup.c
xen/arch/x86/tpm.c

index aab896aca39d4fa29ed58b062dcc5ba9a876abac..b939d00ba729a184cddd44bcdc7754eced5e728f 100644 (file)
@@ -1,3 +1,5 @@
+#include <xen/multiboot.h>
+
 /*
  * TXT configuration registers (offsets from TXT_{PUB, PRIV}_CONFIG_REGS_BASE)
  */
@@ -380,4 +382,14 @@ extern void txt_restore_mtrrs(bool e820_verbose);
 void tpm_hash_extend(unsigned loc, unsigned pcr, uint8_t *buf, unsigned size,
                      uint32_t type, uint8_t *log_data, unsigned log_data_size);
 
+/* Measures essential parts of SLR table before making use of them. */
+void tpm_measure_slrt(void);
+
+/* Takes measurements of DRTM policy entries except for MBI and SLRT which
+ * should have been measured by the time this is called. Also performs sanity
+ * checks of the policy and panics on failure. In particular, the function
+ * verifies that DRTM is consistent with MultibootInfo (MBI) (the MBI address
+ * is assumed to be virtual). */
+void tpm_process_drtm_policy(const multiboot_info_t *mbi);
+
 #endif /* __ASSEMBLY__ */
index 22cbdbdc880c73f2a4129e04e9e5e75521e16a54..bb58ecd2a4ac08c5cc62bb5a7c6cd8cd9d734e90 100644 (file)
@@ -1172,6 +1172,9 @@ void __init noreturn __start_xen(unsigned long mbi_p)
     {
         /* Prepare for TXT-related code. */
         map_txt_mem_regions();
+        /* Measure SLRT here because it gets used by init_e820(), the rest is
+         * measured below by tpm_process_drtm_policy(). */
+        tpm_measure_slrt();
         /* Reserve TXT heap and SINIT. */
         protect_txt_mem_regions();
     }
@@ -1194,6 +1197,12 @@ void __init noreturn __start_xen(unsigned long mbi_p)
     /* Create a temporary copy of the E820 map. */
     memcpy(&boot_e820, &e820, sizeof(e820));
 
+    /* Process all yet unmeasured DRTM entries after E820 initialization to not
+     * do this while memory is uncached (too slow). This must also happen before
+     * fields of Multiboot modules change their format below. */
+    if ( slaunch_active )
+        tpm_process_drtm_policy(mbi);
+
     /* Early kexec reservation (explicit static start address). */
     nr_pages = 0;
     for ( i = 0; i < e820.nr_map; i++ )
index 6dc349d3d533aeb67be550cbdd0f63c4f11b485c..1d07ca8d007e8712dd3fc7c6157636f2f20eca99 100644 (file)
@@ -963,4 +963,200 @@ void __stdcall tpm_extend_mbi(uint32_t *mbi)
     tpm_hash_extend(DRTM_LOC, DRTM_DATA_PCR, (uint8_t *)mbi, *mbi,
                     TXT_EVTYPE_SLAUNCH, NULL, 0);
 }
+#else
+static struct slr_table *slr_get_table(void)
+{
+    struct txt_os_mle_data *os_mle;
+    struct slr_table *slrt;
+
+    os_mle = txt_os_mle_data_start(__va(read_txt_reg(TXTCR_HEAP_BASE)));
+
+    map_l2(os_mle->slrt, PAGE_SIZE);
+    slrt = __va(os_mle->slrt);
+
+    if ( slrt->magic != SLR_TABLE_MAGIC )
+        panic("SLRT has invalid magic value: %#08x!\n", slrt->magic);
+    /* XXX: are newer revisions allowed? */
+    if ( slrt->revision != SLR_TABLE_REVISION )
+        panic("SLRT is of unsupported revision: %#04x!\n", slrt->revision);
+    if ( slrt->architecture != SLR_INTEL_TXT )
+        panic("SLRT is for unexpected architecture: %#04x!\n",
+              slrt->architecture);
+    if ( slrt->size > slrt->max_size )
+        panic("SLRT is larger than its max size: %#08x > %#08x!\n",
+              slrt->size, slrt->max_size);
+
+    if ( slrt->size > PAGE_SIZE )
+        map_l2(os_mle->slrt, slrt->size);
+
+    return slrt;
+}
+
+void tpm_measure_slrt(void)
+{
+    struct slr_table *slrt = slr_get_table();
+
+    if ( slrt->revision == 1 ) {
+        /* In revision one of the SLRT, only Intel info table is measured. */
+        struct slr_entry_intel_info *intel_info =
+            (void *)slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_INTEL_INFO);
+        if ( intel_info == NULL )
+            panic("SLRT is missing Intel-specific information!\n");
+
+        tpm_hash_extend(DRTM_LOC, DRTM_DATA_PCR, (uint8_t *)intel_info,
+                        sizeof(*intel_info), TXT_EVTYPE_SLAUNCH, NULL, 0);
+    } else {
+        /*
+         * slr_get_table() checks that the revision is valid, so we must not
+         * get here unless the code is wrong.
+         */
+        panic("Unhandled SLRT revision: %d!\n", slrt->revision);
+    }
+}
+
+static struct slr_entry_policy *slr_get_policy(struct slr_table *slrt)
+{
+    struct slr_entry_policy *policy;
+
+    policy = (struct slr_entry_policy *)
+        slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_DRTM_POLICY);
+    if (policy == NULL)
+        panic("SLRT is missing DRTM policy!\n");
+
+    /* XXX: are newer revisions allowed? */
+    if ( policy->revision != SLR_POLICY_REVISION )
+        panic("DRTM policy in SLRT is of unsupported revision: %#04x!\n",
+              slrt->revision);
+
+    return policy;
+}
+
+static void check_drtm_policy(struct slr_table *slrt,
+                              struct slr_entry_policy *policy,
+                              struct slr_policy_entry *policy_entry,
+                              const multiboot_info_t *mbi)
+{
+    uint32_t i;
+    module_t *mods;
+    uint32_t num_mod_entries;
+
+    if ( policy->nr_entries < 2 )
+        panic("DRTM policy in SLRT contains less than 2 entries (%d)!\n",
+              policy->nr_entries);
+
+    /* MBI policy entry must be the first one, so that measuring order matches
+     * policy order. */
+    if ( policy_entry[0].entity_type != SLR_ET_MULTIBOOT2_INFO )
+        panic("First entry of DRTM policy in SLRT is not MBI: %#04x!\n",
+              policy_entry[0].entity_type);
+    if ( policy_entry[0].pcr != DRTM_DATA_PCR )
+        panic("MBI was measured to %d instead of %d PCR!\n", DRTM_DATA_PCR,
+              policy_entry[0].pcr);
+
+    /* SLRT policy entry must be the second one. */
+    if ( policy_entry[1].entity_type != SLR_ET_SLRT )
+        panic("Second entry of DRTM policy in SLRT is not SLRT: %#04x!\n",
+              policy_entry[1].entity_type);
+    if ( policy_entry[1].pcr != DRTM_DATA_PCR )
+        panic("SLRT was measured to %d instead of %d PCR!\n", DRTM_DATA_PCR,
+              policy_entry[1].pcr);
+    if ( policy_entry[1].entity != (uint64_t)__pa(slrt) )
+        panic("SLRT address (%#08lx) differes from its DRTM entry (%#08lx)\n",
+              __pa(slrt), policy_entry[1].entity);
+
+    mods = __va(mbi->mods_addr);
+    for ( i = 0; i < mbi->mods_count; i++ ) {
+        uint16_t j;
+        uint64_t start = mods[i].mod_start;
+        uint64_t size = mods[i].mod_end - mods[i].mod_start;
+
+        for ( j = 0; j < policy->nr_entries; j++ ) {
+            if ( policy_entry[j].entity_type != SLR_ET_MULTIBOOT2_MODULE )
+                continue;
+
+            if ( policy_entry[j].entity == start &&
+                 policy_entry[j].size == size )
+                break;
+        }
+
+        if ( j >= policy->nr_entries ) {
+            panic("Couldn't find Multiboot module \"%s\" (at %d) in DRTM of Secure Launch\n",
+                  (const char *)__va(mods[i].string), i);
+        }
+    }
+
+    num_mod_entries = 0;
+    for ( i = 0; i < policy->nr_entries; i++ ) {
+        if ( policy_entry[i].entity_type == SLR_ET_MULTIBOOT2_MODULE )
+            num_mod_entries++;
+    }
+
+    if ( mbi->mods_count != num_mod_entries ) {
+        panic("Unexpected number of Multiboot modules: %d instead of %d\n",
+              (int)mbi->mods_count, (int)num_mod_entries);
+    }
+}
+
+void tpm_process_drtm_policy(const multiboot_info_t *mbi)
+{
+    struct slr_table *slrt;
+    struct slr_entry_policy *policy;
+    struct slr_policy_entry *policy_entry;
+    uint16_t i;
+
+    slrt = slr_get_table();
+
+    policy = slr_get_policy(slrt);
+    policy_entry = (struct slr_policy_entry *)
+        ((uint8_t *)policy + sizeof(*policy));
+
+    check_drtm_policy(slrt, policy, policy_entry, mbi);
+    /* MBI was measured in tpm_extend_mbi(). */
+    policy_entry[0].flags |= SLR_POLICY_FLAG_MEASURED;
+    /* SLRT was measured in tpm_measure_slrt(). */
+    policy_entry[1].flags |= SLR_POLICY_FLAG_MEASURED;
+
+    for ( i = 2; i < policy->nr_entries; i++ ) {
+        uint64_t start = policy_entry[i].entity;
+        uint64_t size = policy_entry[i].size;
+
+        /* No already measured entries are expected here. */
+        if ( policy_entry[i].flags & SLR_POLICY_FLAG_MEASURED )
+            panic("DRTM entry at %d was measured out of order!\n", i);
+
+        switch ( policy_entry[i].entity_type ) {
+        case SLR_ET_MULTIBOOT2_INFO:
+            panic("Duplicated MBI entry in DRTM of Secure Launch at %d\n", i);
+        case SLR_ET_SLRT:
+            panic("Duplicated SLRT entry in DRTM of Secure Launch at %d\n", i);
+
+        case SLR_ET_UNSPECIFIED:
+        case SLR_ET_BOOT_PARAMS:
+        case SLR_ET_SETUP_DATA:
+        case SLR_ET_CMDLINE:
+        case SLR_ET_UEFI_MEMMAP:
+        case SLR_ET_RAMDISK:
+        case SLR_ET_MULTIBOOT2_MODULE:
+        case SLR_ET_TXT_OS2MLE:
+            /* Measure this entry below. */
+            break;
+
+        case SLR_ET_UNUSED:
+            /* Skip this entry. */
+            continue;
+        }
+
+        if ( policy_entry[i].flags & SLR_POLICY_IMPLICIT_SIZE )
+            panic("Unexpected implicitly-sized DRTM entry of Secure Launch at %d\n",
+                  i);
+
+        map_l2(start, size);
+        tpm_hash_extend(DRTM_LOC, policy_entry[i].pcr, __va(start), size,
+                        TXT_EVTYPE_SLAUNCH, (uint8_t *)policy_entry[i].evt_info,
+                        strnlen(policy_entry[i].evt_info,
+                                TPM_EVENT_INFO_LENGTH));
+
+        policy_entry[i].flags |= SLR_POLICY_FLAG_MEASURED;
+    }
+}
 #endif