From fbcf3de9776a5c4bc23d60e2ba4001e753a0d44d Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Sun, 29 Oct 2023 00:29:30 +0300 Subject: [PATCH 1/7] include/xen/slr_table.h: Secure Launch Resource Table definitions The file provides constants, structures and several helper functions for parsing SLRT. slr_add_entry() and slr_init_table() were omitted to not have issues with memcpy() usage (it comes from different places for different translation units). Signed-off-by: Sergii Dmytruk --- xen/include/xen/slr_table.h | 255 ++++++++++++++++++++++++++++++++++++ 1 file changed, 255 insertions(+) create mode 100644 xen/include/xen/slr_table.h diff --git a/xen/include/xen/slr_table.h b/xen/include/xen/slr_table.h new file mode 100644 index 0000000000..90120cb19a --- /dev/null +++ b/xen/include/xen/slr_table.h @@ -0,0 +1,255 @@ +/* SPDX-License-Identifier: GPL-3.0 */ + +/* + * Copyright (C) 2023 Oracle and/or its affiliates. + * + * Secure Launch Resource Table definitions + */ + +#ifndef _SLR_TABLE_H +#define _SLR_TABLE_H + +#define UEFI_SLR_TABLE_GUID \ + { 0x877a9b2a, 0x0385, 0x45d1, { 0xa0, 0x34, 0x9d, 0xac, 0x9c, 0x9e, 0x56, 0x5f }} + +/* SLR table header values */ +#define SLR_TABLE_MAGIC 0x4452544d +#define SLR_TABLE_REVISION 1 + +/* Current revisions for the policy and UEFI config */ +#define SLR_POLICY_REVISION 1 +#define SLR_UEFI_CONFIG_REVISION 1 + +/* SLR defined architectures */ +#define SLR_INTEL_TXT 1 +#define SLR_AMD_SKINIT 2 + +/* SLR defined bootloaders */ +#define SLR_BOOTLOADER_INVALID 0 +#define SLR_BOOTLOADER_GRUB 1 + +/* Log formats */ +#define SLR_DRTM_TPM12_LOG 1 +#define SLR_DRTM_TPM20_LOG 2 + +/* DRTM Policy Entry Flags */ +#define SLR_POLICY_FLAG_MEASURED 0x1 +#define SLR_POLICY_IMPLICIT_SIZE 0x2 + +/* Array Lengths */ +#define TPM_EVENT_INFO_LENGTH 32 +#define TXT_VARIABLE_MTRRS_LENGTH 32 + +/* Tags */ +#define SLR_ENTRY_INVALID 0x0000 +#define SLR_ENTRY_DL_INFO 0x0001 +#define SLR_ENTRY_LOG_INFO 0x0002 +#define SLR_ENTRY_DRTM_POLICY 0x0003 +#define SLR_ENTRY_INTEL_INFO 0x0004 +#define SLR_ENTRY_AMD_INFO 0x0005 +#define SLR_ENTRY_ARM_INFO 0x0006 +#define SLR_ENTRY_UEFI_INFO 0x0007 +#define SLR_ENTRY_UEFI_CONFIG 0x0008 +#define SLR_ENTRY_END 0xffff + +/* Entity Types */ +#define SLR_ET_UNSPECIFIED 0x0000 +#define SLR_ET_SLRT 0x0001 +#define SLR_ET_BOOT_PARAMS 0x0002 +#define SLR_ET_SETUP_DATA 0x0003 +#define SLR_ET_CMDLINE 0x0004 +#define SLR_ET_UEFI_MEMMAP 0x0005 +#define SLR_ET_RAMDISK 0x0006 +#define SLR_ET_MULTIBOOT_INFO 0x0007 +#define SLR_ET_MULTIBOOT_MODULE 0x0008 +#define SLR_ET_TXT_OS2MLE 0x0010 +#define SLR_ET_UNUSED 0xffff + +/* + * Primary SLR Table Header + */ +struct slr_table +{ + uint32_t magic; + uint16_t revision; + uint16_t architecture; + uint32_t size; + uint32_t max_size; + /* entries[] */ +} __packed; + +/* + * Common SLRT Table Header + */ +struct slr_entry_hdr +{ + uint16_t tag; + uint16_t size; +} __packed; + +/* + * Boot loader context + */ +struct slr_bl_context +{ + uint16_t bootloader; + uint16_t reserved; + uint64_t context; +} __packed; + +/* + * DRTM Dynamic Launch Configuration + */ +struct slr_entry_dl_info +{ + struct slr_entry_hdr hdr; + struct slr_bl_context bl_context; + uint64_t dl_handler; + uint64_t dce_base; + uint32_t dce_size; + uint64_t dlme_entry; +} __packed; + +/* + * TPM Log Information + */ +struct slr_entry_log_info +{ + struct slr_entry_hdr hdr; + uint16_t format; + uint16_t reserved; + uint64_t addr; + uint32_t size; +} __packed; + +/* + * DRTM Measurement Policy + */ +struct slr_entry_policy +{ + struct slr_entry_hdr hdr; + uint16_t revision; + uint16_t nr_entries; + /* policy_entries[] */ +} __packed; + +/* + * DRTM Measurement Entry + */ +struct slr_policy_entry +{ + uint16_t pcr; + uint16_t entity_type; + uint16_t flags; + uint16_t reserved; + uint64_t entity; + uint64_t size; + char evt_info[TPM_EVENT_INFO_LENGTH]; +} __packed; + +/* + * Secure Launch defined MTRR saving structures + */ +struct slr_txt_mtrr_pair +{ + uint64_t mtrr_physbase; + uint64_t mtrr_physmask; +} __packed; + +struct slr_txt_mtrr_state +{ + uint64_t default_mem_type; + uint64_t mtrr_vcnt; + struct slr_txt_mtrr_pair mtrr_pair[TXT_VARIABLE_MTRRS_LENGTH]; +} __packed; + +/* + * Intel TXT Info table + */ +struct slr_entry_intel_info +{ + struct slr_entry_hdr hdr; + uint64_t saved_misc_enable_msr; + struct slr_txt_mtrr_state saved_bsp_mtrrs; +} __packed; + +/* + * AMD SKINIT Info table + */ +struct slr_entry_amd_info +{ + struct slr_entry_hdr hdr; +} __packed; + +/* + * ARM DRTM Info table + */ +struct slr_entry_arm_info +{ + struct slr_entry_hdr hdr; +} __packed; + +struct slr_entry_uefi_config +{ + struct slr_entry_hdr hdr; + uint16_t revision; + uint16_t nr_entries; + /* uefi_cfg_entries[] */ +} __packed; + +struct slr_uefi_cfg_entry +{ + uint16_t pcr; + uint16_t reserved; + uint64_t cfg; /* address or value */ + uint32_t size; + char evt_info[TPM_EVENT_INFO_LENGTH]; +} __packed; + +static inline void * +slr_end_of_entries(struct slr_table *table) +{ + return (uint8_t *)table + table->size; +} + +static inline struct slr_entry_hdr * +slr_next_entry(struct slr_table *table, struct slr_entry_hdr *curr) +{ + struct slr_entry_hdr *next = (struct slr_entry_hdr *) + ((uint8_t *)curr + curr->size); + + if ( (void *)next >= slr_end_of_entries(table) ) + return NULL; + if ( next->tag == SLR_ENTRY_END ) + return NULL; + + return next; +} + +static inline struct slr_entry_hdr * +slr_next_entry_by_tag (struct slr_table *table, + struct slr_entry_hdr *entry, + uint16_t tag) +{ + if ( !entry ) /* Start from the beginning */ + entry = (struct slr_entry_hdr *)((uint8_t *)table + sizeof(*table)); + + for ( ; ; ) + { + if ( entry->tag == tag ) + return entry; + + entry = slr_next_entry(table, entry); + if ( !entry ) + return NULL; + } + + return NULL; +} + +/* + * slr_add_entry() and slr_init_table() were omitted to not have issues with + * memcpy() usage. + */ + +#endif /* _SLR_TABLE_H */ From 6ea9a7ad9f4a9ad79c44404f9ab4c55f73b182f1 Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Sun, 29 Oct 2023 00:39:23 +0300 Subject: [PATCH 2/7] arch/x86: switch to using SLRT interface `struct txt_os_mle_data` now contains pointer to Secure Launch Resource Table which stores various information about slaunch in an extensible way. Saved MTRRs and event log were moved there. Signed-off-by: Sergii Dmytruk --- xen/arch/x86/include/asm/intel_txt.h | 46 ++++++++++++++++------------ xen/arch/x86/intel_txt.c | 39 ++++++++++++++--------- xen/arch/x86/tpm.c | 11 ++----- 3 files changed, 52 insertions(+), 44 deletions(-) diff --git a/xen/arch/x86/include/asm/intel_txt.h b/xen/arch/x86/include/asm/intel_txt.h index f5ea390008..9796f12c0b 100644 --- a/xen/arch/x86/include/asm/intel_txt.h +++ b/xen/arch/x86/include/asm/intel_txt.h @@ -70,8 +70,6 @@ #define SL_ERROR_TPM_UNKNOWN_DIGEST 0xc0008020 #define SL_ERROR_TPM_INVALID_EVENT 0xc0008021 -#define TXT_OS_MLE_MAX_VARIABLE_MTRRS 32 - #define SLAUNCH_BOOTLOADER_MAGIC 0x4c534254 #define TXT_AP_BOOT_CS 0x0030 @@ -93,6 +91,8 @@ extern uint32_t trampoline_gdt[]; #define _txt(x) __va(x) #endif +#include + /* * Always use private space as some of registers are either read-only or not * present in public space. @@ -120,32 +120,16 @@ static inline void txt_reset(uint32_t error) while (1); } -/* - * Secure Launch defined MTRR saving structures - */ -struct txt_mtrr_pair { - uint64_t mtrr_physbase; - uint64_t mtrr_physmask; -} __packed; - -struct txt_mtrr_state { - uint64_t default_mem_type; - uint64_t mtrr_vcnt; - struct txt_mtrr_pair mtrr_pair[TXT_OS_MLE_MAX_VARIABLE_MTRRS]; -} __packed; - /* * Secure Launch defined OS/MLE TXT Heap table */ struct txt_os_mle_data { uint32_t version; uint32_t boot_params_addr; - uint64_t saved_misc_enable_msr; - struct txt_mtrr_state saved_bsp_mtrrs; + uint32_t slrt; + uint32_t txt_info; uint32_t ap_wake_block; uint32_t ap_wake_block_size; - uint64_t evtlog_addr; - uint32_t evtlog_size; uint8_t mle_scratch[64]; } __packed; @@ -341,6 +325,28 @@ static inline int is_in_pmr(struct txt_os_sinit_data *os_sinit, uint64_t base, return 0; } +/* evt_log is a physical address and the caller must map it to virtual, if + * needed. */ +static inline void find_evt_log(void **evt_log, uint32_t *evt_log_size) +{ + struct txt_os_mle_data *os_mle; + struct slr_table *slrt; + struct slr_entry_log_info *log_info; + + os_mle = txt_os_mle_data_start(_txt(read_txt_reg(TXTCR_HEAP_BASE))); + slrt = _txt(os_mle->slrt); + + log_info = (struct slr_entry_log_info *) + slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_LOG_INFO); + if ( log_info != NULL ) { + *evt_log = _p(log_info->addr); + *evt_log_size = log_info->size; + } else { + *evt_log = NULL; + *evt_log_size = 0; + } +} + extern void protect_txt_mem_regions(void); extern void txt_restore_mtrrs(bool e820_verbose); diff --git a/xen/arch/x86/intel_txt.c b/xen/arch/x86/intel_txt.c index 0edb8a6a85..585a813806 100644 --- a/xen/arch/x86/intel_txt.c +++ b/xen/arch/x86/intel_txt.c @@ -5,6 +5,7 @@ #include #include #include +#include static uint64_t __initdata txt_heap_base, txt_heap_size; @@ -82,7 +83,8 @@ void __init protect_txt_mem_regions(void) /* TXT Heap */ if ( txt_heap_base != 0 ) { - struct txt_os_mle_data *os_mle; + void *evt_log_addr; + uint32_t evt_log_size; printk("SLAUNCH: reserving TXT heap (%#lx - %#lx)\n", txt_heap_base, txt_heap_base + txt_heap_size); @@ -92,13 +94,14 @@ void __init protect_txt_mem_regions(void) /* TXT TPM Event Log */ map_l2(txt_heap_base, txt_heap_size); - os_mle = txt_os_mle_data_start(__va(txt_heap_base)); - - if ( os_mle->evtlog_addr != 0 ) { - printk("SLAUNCH: reserving event log (%#lx - %#lx)\n", os_mle->evtlog_addr, - os_mle->evtlog_addr + os_mle->evtlog_size); - e820_change_range_type(&e820_raw, os_mle->evtlog_addr, - os_mle->evtlog_addr + os_mle->evtlog_size, + find_evt_log(&evt_log_addr, &evt_log_size); + + if ( evt_log_addr != 0 ) { + printk("SLAUNCH: reserving event log (%#lx - %#lx)\n", + (uint64_t)evt_log_addr, + (uint64_t)evt_log_addr + evt_log_size); + e820_change_range_type(&e820_raw, (uint64_t)evt_log_addr, + (uint64_t)evt_log_addr + evt_log_size, E820_RAM, E820_RESERVED); } @@ -123,6 +126,8 @@ void __init protect_txt_mem_regions(void) void __init txt_restore_mtrrs(bool e820_verbose) { struct txt_os_mle_data *os_mle; + struct slr_table *slrt; + struct slr_entry_intel_info *intel_info; int os_mle_size; uint64_t mtrr_cap, mtrr_def, base, mask; unsigned int i; @@ -152,21 +157,25 @@ void __init txt_restore_mtrrs(bool e820_verbose) } } - if ( (mtrr_cap & 0xFF) != os_mle->saved_bsp_mtrrs.mtrr_vcnt ) { + slrt = __va(os_mle->slrt); + intel_info = (struct slr_entry_intel_info *) + slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_INTEL_INFO); + + if ( (mtrr_cap & 0xFF) != intel_info->saved_bsp_mtrrs.mtrr_vcnt ) { printk("Bootloader saved %ld MTRR values, but there should be %ld\n", - os_mle->saved_bsp_mtrrs.mtrr_vcnt, mtrr_cap & 0xFF); + intel_info->saved_bsp_mtrrs.mtrr_vcnt, mtrr_cap & 0xFF); /* Choose the smaller one to be on the safe side. */ - mtrr_cap = (mtrr_cap & 0xFF) > os_mle->saved_bsp_mtrrs.mtrr_vcnt ? - os_mle->saved_bsp_mtrrs.mtrr_vcnt : mtrr_cap; + mtrr_cap = (mtrr_cap & 0xFF) > intel_info->saved_bsp_mtrrs.mtrr_vcnt ? + intel_info->saved_bsp_mtrrs.mtrr_vcnt : mtrr_cap; } /* Restore MTRRs saved by bootloader. */ - wrmsrl(MSR_MTRRdefType, os_mle->saved_bsp_mtrrs.default_mem_type); + wrmsrl(MSR_MTRRdefType, intel_info->saved_bsp_mtrrs.default_mem_type); for ( i = 0; i < (uint8_t)mtrr_cap; i++ ) { - base = os_mle->saved_bsp_mtrrs.mtrr_pair[i].mtrr_physbase; - mask = os_mle->saved_bsp_mtrrs.mtrr_pair[i].mtrr_physmask; + base = intel_info->saved_bsp_mtrrs.mtrr_pair[i].mtrr_physbase; + mask = intel_info->saved_bsp_mtrrs.mtrr_pair[i].mtrr_physmask; wrmsrl(MSR_IA32_MTRR_PHYSBASE(i), base); wrmsrl(MSR_IA32_MTRR_PHYSMASK(i), mask); } diff --git a/xen/arch/x86/tpm.c b/xen/arch/x86/tpm.c index c7a0f26f75..9dfa78c5f8 100644 --- a/xen/arch/x86/tpm.c +++ b/xen/arch/x86/tpm.c @@ -29,6 +29,7 @@ asm ( #include "boot/defs.h" #include "include/asm/intel_txt.h" +#include #ifdef __va #error "__va defined in non-paged mode!" #endif @@ -167,15 +168,6 @@ static inline bool is_tpm12(void) (tis_read32(TPM_STS_(0)) & TPM_FAMILY_MASK) == 0); } -static inline void find_evt_log(void **evt_log, uint32_t *evt_log_size) -{ - struct txt_os_mle_data *os_mle; - os_mle = txt_os_mle_data_start(__va(read_txt_reg(TXTCR_HEAP_BASE))); - - *evt_log = __va(os_mle->evtlog_addr); - *evt_log_size = os_mle->evtlog_size; -} - /****************************** TPM1.2 & TPM2.0 *******************************/ /* @@ -933,6 +925,7 @@ void tpm_hash_extend(unsigned loc, unsigned pcr, uint8_t *buf, unsigned size, uint32_t evt_log_size; find_evt_log(&evt_log_addr, &evt_log_size); + evt_log_addr = __va(evt_log_addr); #ifndef __EARLY_TPM__ /* From b5c689c36d70a6451356ee9d0a268ca4d3dff14b Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Sat, 18 Nov 2023 00:35:45 +0200 Subject: [PATCH 3/7] Revert "x86/dom0_build.c: measure kernel and initrd before dom0 is constructed" This reverts commit 7962cb8b862beabd9de2c78f9dae5b02530e7f07. --- xen/arch/x86/Makefile | 1 - xen/arch/x86/dom0_build.c | 23 ----------------------- 2 files changed, 24 deletions(-) diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile index 594093fcca..312932d50f 100644 --- a/xen/arch/x86/Makefile +++ b/xen/arch/x86/Makefile @@ -64,7 +64,6 @@ obj-y += spec_ctrl.o obj-y += srat.o obj-y += string.o obj-y += time.o -obj-y += tpm.o obj-y += traps.o obj-y += tsx.o obj-y += usercopy.o diff --git a/xen/arch/x86/dom0_build.c b/xen/arch/x86/dom0_build.c index 115e95d3c6..79234f18ff 100644 --- a/xen/arch/x86/dom0_build.c +++ b/xen/arch/x86/dom0_build.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include @@ -586,28 +585,6 @@ int __init construct_dom0(struct domain *d, const module_t *image, BUG_ON(d->vcpu[0] == NULL); BUG_ON(d->vcpu[0]->is_initialised); - if ( sl_status ) { - /* - * Note: __start_xen() changed the meaning of mod_start and mod_end - * fields, they are now MFN and module length in bytes, respectively. - * For kernel, image_headroom was added both to mod_end and mod_start. - */ - printk("Measuring dom0 kernel...\n"); - tpm_hash_extend(DRTM_LOC, DRTM_CODE_PCR, - __va(image->mod_start * PAGE_SIZE + image_headroom), - image->mod_end - image_headroom, TXT_EVTYPE_KERNEL, - NULL, 0); - - if ( initrd != NULL ) { - process_pending_softirqs(); - - printk("Measuring dom0 initrd...\n"); - tpm_hash_extend(DRTM_LOC, DRTM_CODE_PCR, - __va(initrd->mod_start * PAGE_SIZE), - initrd->mod_end, TXT_EVTYPE_INITRD, NULL, 0); - } - } - process_pending_softirqs(); if ( is_hvm_domain(d) ) From 04c0fbeed6f4460345571e274a56fb9b22562f91 Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Sat, 18 Nov 2023 00:45:58 +0200 Subject: [PATCH 4/7] x86/Makefile: compile tpm.c Signed-off-by: Sergii Dmytruk --- xen/arch/x86/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile index 312932d50f..594093fcca 100644 --- a/xen/arch/x86/Makefile +++ b/xen/arch/x86/Makefile @@ -64,6 +64,7 @@ obj-y += spec_ctrl.o obj-y += srat.o obj-y += string.o obj-y += time.o +obj-y += tpm.o obj-y += traps.o obj-y += tsx.o obj-y += usercopy.o From bdfad3c6cb2fad93de1c998d6c072f39a1c039dc Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Fri, 8 Dec 2023 00:45:48 +0200 Subject: [PATCH 5/7] arch/x86: map TXT regions once and don't unmap them Extract mapping of TXT registers, heap and TPM log into new map_txt_mem_regions() function that should be called before those which need those mappings. They will all be gone when Xen rebuilds memory maps. Also make map_l2() function externally visible so that code external relative to x86/intel_txt.c unit can add more temporary mappings. Signed-off-by: Sergii Dmytruk --- xen/arch/x86/include/asm/intel_txt.h | 13 ++++++ xen/arch/x86/intel_txt.c | 62 ++++++++-------------------- xen/arch/x86/setup.c | 6 ++- 3 files changed, 35 insertions(+), 46 deletions(-) diff --git a/xen/arch/x86/include/asm/intel_txt.h b/xen/arch/x86/include/asm/intel_txt.h index 9796f12c0b..7f2d384b0c 100644 --- a/xen/arch/x86/include/asm/intel_txt.h +++ b/xen/arch/x86/include/asm/intel_txt.h @@ -325,6 +325,18 @@ static inline int is_in_pmr(struct txt_os_sinit_data *os_sinit, uint64_t base, return 0; } +/* + * This helper function is used to map memory using L2 page tables by aligning + * mapped regions to 2MB. This way page allocator (which at this point isn't + * yet initialized) isn't needed for creating new L1 mappings. The function + * also checks and skips memory already mapped by the prebuilt tables. + * + * There is no unmap_l2() because the function is meant to be used for code that + * accesses TXT registers and TXT heap soon after which Xen rebuilds memory + * maps, effectively dropping all existing mappings. + */ +extern int map_l2(unsigned long paddr, unsigned long size); + /* evt_log is a physical address and the caller must map it to virtual, if * needed. */ static inline void find_evt_log(void **evt_log, uint32_t *evt_log_size) @@ -347,6 +359,7 @@ static inline void find_evt_log(void **evt_log, uint32_t *evt_log_size) } } +extern void map_txt_mem_regions(void); extern void protect_txt_mem_regions(void); extern void txt_restore_mtrrs(bool e820_verbose); diff --git a/xen/arch/x86/intel_txt.c b/xen/arch/x86/intel_txt.c index 585a813806..502a9c35d3 100644 --- a/xen/arch/x86/intel_txt.c +++ b/xen/arch/x86/intel_txt.c @@ -13,16 +13,7 @@ unsigned long __initdata sl_status; #define PREBUILT_MAP_LIMIT (1 << L2_PAGETABLE_SHIFT) -/* - * These helper functions are used to (un)map memory using L2 page tables by - * aligning mapped regions to 2MB. This way page allocator (which at this point - * isn't yet initialized) isn't needed for creating new L1 mappings. Functions - * also check and skip memory already mapped by the prebuilt tables. - * - * There are no tests against multiple mappings in the same superpage, in such - * case first call to unmap_l2() destroys all mappings to given memory range. - */ -static int map_l2(unsigned long paddr, unsigned long size) +int __init map_l2(unsigned long paddr, unsigned long size) { unsigned long aligned_paddr = paddr & ~((1ULL << L2_PAGETABLE_SHIFT) - 1); unsigned long pages = ((paddr + size) - aligned_paddr); @@ -43,44 +34,29 @@ static int map_l2(unsigned long paddr, unsigned long size) pages, PAGE_HYPERVISOR); } -static int unmap_l2(unsigned long paddr, unsigned long size) +void __init map_txt_mem_regions(void) { - unsigned long aligned_paddr = paddr & ~((1ULL << L2_PAGETABLE_SHIFT) - 1); - unsigned long pages = ((paddr + size) - aligned_paddr); - pages += (1ULL << L2_PAGETABLE_SHIFT) - 1; - pages &= ~((1ULL << L2_PAGETABLE_SHIFT) - 1); - pages >>= PAGE_SHIFT; + map_l2(TXT_PRIV_CONFIG_REGS_BASE, NR_TXT_CONFIG_PAGES * PAGE_SIZE); - if ( (aligned_paddr + pages * PAGE_SIZE) <= PREBUILT_MAP_LIMIT ) - return 0; + /* TXT Heap */ + txt_heap_base = read_txt_reg(TXTCR_HEAP_BASE); + txt_heap_size = read_txt_reg(TXTCR_HEAP_SIZE); - if ( aligned_paddr < PREBUILT_MAP_LIMIT ) { - pages -= (PREBUILT_MAP_LIMIT - aligned_paddr) >> PAGE_SHIFT; - aligned_paddr = PREBUILT_MAP_LIMIT; - } + if ( txt_heap_base != 0 ) { + void *evt_log_addr; + uint32_t evt_log_size; + + map_l2(txt_heap_base, txt_heap_size); - return destroy_xen_mappings(aligned_paddr, - aligned_paddr + pages * PAGE_SIZE); + find_evt_log(&evt_log_addr, &evt_log_size); + map_l2((unsigned long)evt_log_addr, evt_log_size); + } } void __init protect_txt_mem_regions(void) { uint64_t sinit_base, sinit_size; - map_l2(TXT_PUB_CONFIG_REGS_BASE, NR_TXT_CONFIG_PAGES * PAGE_SIZE); - - txt_heap_base = txt_heap_size = sinit_base = sinit_size = 0; - - /* TXT Heap */ - txt_heap_base = read_txt_reg(TXTCR_HEAP_BASE); - txt_heap_size = read_txt_reg(TXTCR_HEAP_SIZE); - /* SINIT */ - sinit_base = read_txt_reg(TXTCR_SINIT_BASE); - sinit_size = read_txt_reg(TXTCR_SINIT_SIZE); - - /* Remove mapping of TXT register space. */ - unmap_l2(TXT_PUB_CONFIG_REGS_BASE, NR_TXT_CONFIG_PAGES * PAGE_SIZE); - /* TXT Heap */ if ( txt_heap_base != 0 ) { void *evt_log_addr; @@ -93,7 +69,6 @@ void __init protect_txt_mem_regions(void) E820_RAM, E820_RESERVED); /* TXT TPM Event Log */ - map_l2(txt_heap_base, txt_heap_size); find_evt_log(&evt_log_addr, &evt_log_size); if ( evt_log_addr != 0 ) { @@ -104,10 +79,11 @@ void __init protect_txt_mem_regions(void) (uint64_t)evt_log_addr + evt_log_size, E820_RAM, E820_RESERVED); } - - unmap_l2(txt_heap_base, txt_heap_size); } + sinit_base = read_txt_reg(TXTCR_SINIT_BASE); + sinit_size = read_txt_reg(TXTCR_SINIT_SIZE); + /* SINIT */ if ( sinit_base != 0 ) { printk("SLAUNCH: reserving SINIT memory (%#lx - %#lx)\n", sinit_base, @@ -132,8 +108,6 @@ void __init txt_restore_mtrrs(bool e820_verbose) uint64_t mtrr_cap, mtrr_def, base, mask; unsigned int i; - map_l2(txt_heap_base, txt_heap_size); - os_mle_size = txt_os_mle_data_size(__va(txt_heap_base)); os_mle = txt_os_mle_data_start(__va(txt_heap_base)); @@ -180,8 +154,6 @@ void __init txt_restore_mtrrs(bool e820_verbose) wrmsrl(MSR_IA32_MTRR_PHYSMASK(i), mask); } - unmap_l2(txt_heap_base, txt_heap_size); - if ( e820_verbose ) printk("Restored MTRRs:\n"); /* Printed by caller, mtrr_top_of_ram(). */ } diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index fa59a2bd00..57721583cc 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -1148,9 +1148,13 @@ void __init noreturn __start_xen(unsigned long mbi_p) #endif } - /* Reserve TXT heap and SINIT for Secure Launch path. */ if ( sl_status ) + { + /* Prepare for TXT-related code. */ + map_txt_mem_regions(); + /* Reserve TXT heap and SINIT. */ protect_txt_mem_regions(); + } /* Sanitise the raw E820 map to produce a final clean version. */ max_page = raw_max_page = init_e820(memmap_type, &e820_raw); From ece248feaca7f9674c07313698d0d432f8aaa139 Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Sun, 29 Oct 2023 00:42:04 +0300 Subject: [PATCH 6/7] arch/x86: process DRTM policy Signed-off-by: Sergii Dmytruk --- xen/arch/x86/include/asm/intel_txt.h | 34 +++-- xen/arch/x86/setup.c | 9 ++ xen/arch/x86/tpm.c | 214 +++++++++++++++++++++++++-- 3 files changed, 232 insertions(+), 25 deletions(-) diff --git a/xen/arch/x86/include/asm/intel_txt.h b/xen/arch/x86/include/asm/intel_txt.h index 7f2d384b0c..bbf6f566ed 100644 --- a/xen/arch/x86/include/asm/intel_txt.h +++ b/xen/arch/x86/include/asm/intel_txt.h @@ -2,6 +2,8 @@ * TXT configuration registers (offsets from TXT_{PUB, PRIV}_CONFIG_REGS_BASE) */ +#include + #define TXT_PUB_CONFIG_REGS_BASE 0xfed30000 #define TXT_PRIV_CONFIG_REGS_BASE 0xfed20000 @@ -363,19 +365,33 @@ extern void map_txt_mem_regions(void); extern void protect_txt_mem_regions(void); extern void txt_restore_mtrrs(bool e820_verbose); -#define DRTM_LOC 2 -#define DRTM_CODE_PCR 17 -#define DRTM_DATA_PCR 18 +#define DRTM_LOC 2 +#define DRTM_CODE_PCR 17 +#define DRTM_DATA_PCR 18 -/* TXT-defined use 0x4xx, TrenchBoot in Linux uses 0x5xx, use 0x6xx here. */ -#define TXT_EVTYPE_MBI 0x600 -#define TXT_EVTYPE_KERNEL 0x601 -#define TXT_EVTYPE_INITRD 0x602 +/* + * Secure Launch event log entry type. The TXT specification defines the + * base event value as 0x400 for DRTM values. + */ +#define TXT_EVTYPE_BASE 0x400 +#define TXT_EVTYPE_SLAUNCH (TXT_EVTYPE_BASE + 0x102) +#define TXT_EVTYPE_SLAUNCH_START (TXT_EVTYPE_BASE + 0x103) +#define TXT_EVTYPE_SLAUNCH_END (TXT_EVTYPE_BASE + 0x104) -#define SHA1_DIGEST_SIZE 20 -#define SHA256_DIGEST_SIZE 32 +#define SHA1_DIGEST_SIZE 20 +#define SHA256_DIGEST_SIZE 32 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__ */ diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index 57721583cc..12255a438e 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -1152,6 +1152,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(); } @@ -1174,6 +1177,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 ( sl_status ) + tpm_process_drtm_policy(mbi); + /* Early kexec reservation (explicit static start address). */ nr_pages = 0; for ( i = 0; i < e820.nr_map; i++ ) diff --git a/xen/arch/x86/tpm.c b/xen/arch/x86/tpm.c index 9dfa78c5f8..bb27123571 100644 --- a/xen/arch/x86/tpm.c +++ b/xen/arch/x86/tpm.c @@ -803,7 +803,7 @@ static uint32_t tpm2_hash_extend(unsigned loc, uint8_t *buf, unsigned size, else if ( hash->alg == TPM_ALG_SHA256 ) sha256_hash(buf, size, (uint32_t *)hash->data); else - /* create_log_event20() took take of initializing the digest. */; + /* create_log_event20() took care of initializing the digest. */; if ( supported_hashes.count == MAX_HASH_COUNT ) { printk(XENLOG_ERR "Hit hash count implementation limit: %d\n", @@ -927,15 +927,6 @@ void tpm_hash_extend(unsigned loc, unsigned pcr, uint8_t *buf, unsigned size, find_evt_log(&evt_log_addr, &evt_log_size); evt_log_addr = __va(evt_log_addr); -#ifndef __EARLY_TPM__ - /* - * Low mappings are destroyed somewhere during the boot process, it includes - * event log (marked as reserved by protect_txt_mem_regions(). - */ - map_pages_to_xen((unsigned long)evt_log_addr, maddr_to_mfn(__pa(evt_log_addr)), - PFN_UP(evt_log_size), __PAGE_HYPERVISOR_RW); -#endif - if ( is_tpm12() ) { uint8_t sha1_digest[SHA1_DIGEST_SIZE]; @@ -964,11 +955,6 @@ void tpm_hash_extend(unsigned loc, unsigned pcr, uint8_t *buf, unsigned size, #endif } } - -#ifndef __EARLY_TPM__ - destroy_xen_mappings((unsigned long)evt_log_addr, - (unsigned long)evt_log_addr + PFN_UP(evt_log_size) * PAGE_SIZE); -#endif } #ifdef __EARLY_TPM__ @@ -976,6 +962,202 @@ void __stdcall tpm_extend_mbi(uint32_t *mbi) { /* MBI starts with uint32_t total_size. */ tpm_hash_extend(DRTM_LOC, DRTM_DATA_PCR, (uint8_t *)mbi, *mbi, - TXT_EVTYPE_MBI, NULL, 0); + 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_MULTIBOOT_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_MULTIBOOT_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_MULTIBOOT_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_MULTIBOOT_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_MULTIBOOT_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 From 3dc5991be74c5fd498e2fb9d7ff2b53289abba9d Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Sun, 10 Dec 2023 23:39:22 +0200 Subject: [PATCH 7/7] Revert "x86/setup.c: don't use XSM policy and ucode updates with slaunch" This reverts commit 8a496bec884af2843e937b197e846ce65ecd6cd6. Proper handling of DRTM obsoletes these changes. --- xen/arch/x86/setup.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index 12255a438e..d1c233868c 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -1029,13 +1029,6 @@ void __init noreturn __start_xen(unsigned long mbi_p) mbi->mods_count); } - if ( sl_status ) - if ( mbi->mods_count > 2 ) - { - mbi->mods_count = 2; - printk("Excessive multiboot modules for slaunch - limiting to 2\n"); - } - bitmap_fill(module_map, mbi->mods_count); __clear_bit(0, module_map); /* Dom0 kernel is always first */ @@ -1730,9 +1723,7 @@ void __init noreturn __start_xen(unsigned long mbi_p) mmio_ro_ranges = rangeset_new(NULL, "r/o mmio ranges", RANGESETF_prettyprint_hex); - /* TODO: XSM policies are not supported by slaunch yet. */ - if ( sl_status == 0 ) - xsm_multiboot_init(module_map, mbi); + xsm_multiboot_init(module_map, mbi); /* * IOMMU-related ACPI table parsing may require some of the system domains @@ -1801,9 +1792,7 @@ void __init noreturn __start_xen(unsigned long mbi_p) init_IRQ(); - /* TODO: Microcode updates are not supported by slaunch yet. */ - if ( sl_status == 0 ) - microcode_grab_module(module_map, mbi); + microcode_grab_module(module_map, mbi); timer_init();