From 44e44c1c3868dbeb203e03029fc3d02cfb901a36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20=C5=BBygowski?= Date: Sat, 17 Aug 2024 17:35:02 +0200 Subject: [PATCH 1/2] grub-core/loader/i386/txt/txt.c: Use MAXPHYADDR in MTRR masks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Based on Intel TXT MLE Developer Guide revision 017.4 Table 4 the SINIT capabilities bit 8 indicates whether fixed 36bit masks or MAXPHYADDR masks are to be used in MTRR calculations. Failing to adhere to it may lead to creation of potentially disjoint WB cache ranges and violation of CRAM protections - according to the document. Signed-off-by: Michał Żygowski --- grub-core/loader/i386/txt/txt.c | 42 +++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/grub-core/loader/i386/txt/txt.c b/grub-core/loader/i386/txt/txt.c index ec144b5ebf..fd133a1c99 100644 --- a/grub-core/loader/i386/txt/txt.c +++ b/grub-core/loader/i386/txt/txt.c @@ -350,6 +350,21 @@ fls (int mask) return (mask == 0 ? mask : (int)bsrl ((grub_uint32_t)mask) + 1); } +static grub_uint32_t cpu_phys_addr(void) +{ + grub_uint32_t eax, ebx, ecx, edx; + grub_uint32_t phys_bits = 36; + /* Find the physical address size for this CPU. */ + grub_cpuid (0x80000000, eax, ebx, ecx, edx); + if ( eax >= 0x80000008 ) + { + grub_cpuid (0x80000008, eax, ebx, ecx, edx); + phys_bits = eax & 0xFF; + } + + return phys_bits; +} + /* * set the memory type for specified range (base to base+size) * to mem_type and everything else to UC @@ -360,9 +375,10 @@ set_mtrr_mem_type (const grub_uint8_t *base, grub_uint32_t size, { grub_uint64_t mtrr_def_type; grub_uint64_t mtrr_cap; + grub_uint64_t mtrr_mask; union mtrr_physbase_t mtrr_physbase; union mtrr_physmask_t mtrr_physmask; - grub_uint32_t vcnt, pages_in_range; + grub_uint32_t vcnt, pages_in_range, sinit_caps; unsigned long ndx, base_v; int i = 0, j, num_pages, mtrr_s; @@ -376,6 +392,16 @@ set_mtrr_mem_type (const grub_uint8_t *base, grub_uint32_t size, mtrr_cap = grub_rdmsr (GRUB_MSR_X86_MTRRCAP); vcnt = (mtrr_cap & GRUB_MSR_X86_VCNT_MASK); + sinit_caps = grub_txt_get_sinit_capabilities ((struct grub_txt_acm_header *)base); + if (!(sinit_caps & GRUB_TXT_CAPS_MAXPHYSADDR_SUPPORT)) { + /* Legacy 36bit mask */ + mtrr_mask = SINIT_MTRR_MASK; + } else { + /* Calculate the MTRR mask because MAXPHYADDR is used per SINIT caps */ + mtrr_mask = ((1ull << cpu_phys_addr()) - 1) & ~((1ull << 12) - 1); + mtrr_mask = mtrr_mask >> GRUB_PAGE_SHIFT; + } + for ( ndx = 0; ndx < vcnt; ndx++ ) { mtrr_physmask.raw = grub_rdmsr (GRUB_MSR_X86_MTRR_PHYSMASK (ndx)); @@ -411,13 +437,12 @@ set_mtrr_mem_type (const grub_uint8_t *base, grub_uint32_t size, while ( num_pages >= mtrr_s ) { mtrr_physbase.raw = grub_rdmsr (GRUB_MSR_X86_MTRR_PHYSBASE (ndx)); - mtrr_physbase.base = ((unsigned long)base >> GRUB_PAGE_SHIFT) & - SINIT_MTRR_MASK; + mtrr_physbase.base = ((unsigned long)base >> GRUB_PAGE_SHIFT) & mtrr_mask; mtrr_physbase.type = mem_type; grub_wrmsr (GRUB_MSR_X86_MTRR_PHYSBASE (ndx), mtrr_physbase.raw); mtrr_physmask.raw = grub_rdmsr (GRUB_MSR_X86_MTRR_PHYSMASK (ndx)); - mtrr_physmask.mask = ~(mtrr_s - 1) & SINIT_MTRR_MASK; + mtrr_physmask.mask = ~(mtrr_s - 1) & mtrr_mask; mtrr_physmask.v = 1; grub_wrmsr (GRUB_MSR_X86_MTRR_PHYSMASK (ndx), mtrr_physmask.raw); @@ -433,8 +458,7 @@ set_mtrr_mem_type (const grub_uint8_t *base, grub_uint32_t size, { /* Set the base of the current MTRR */ mtrr_physbase.raw = grub_rdmsr (GRUB_MSR_X86_MTRR_PHYSBASE (ndx)); - mtrr_physbase.base = ((unsigned long)base >> GRUB_PAGE_SHIFT) & - SINIT_MTRR_MASK; + mtrr_physbase.base = ((unsigned long)base >> GRUB_PAGE_SHIFT) & mtrr_mask; mtrr_physbase.type = mem_type; grub_wrmsr (GRUB_MSR_X86_MTRR_PHYSBASE (ndx), mtrr_physbase.raw); @@ -446,7 +470,7 @@ set_mtrr_mem_type (const grub_uint8_t *base, grub_uint32_t size, pages_in_range = 1 << (fls (num_pages) - 1); mtrr_physmask.raw = grub_rdmsr (GRUB_MSR_X86_MTRR_PHYSMASK (ndx)); - mtrr_physmask.mask = ~(pages_in_range - 1) & SINIT_MTRR_MASK; + mtrr_physmask.mask = ~(pages_in_range - 1) & mtrr_mask; mtrr_physmask.v = 1; grub_wrmsr (GRUB_MSR_X86_MTRR_PHYSMASK (ndx), mtrr_physmask.raw); @@ -759,6 +783,10 @@ init_txt_heap (struct grub_slaunch_params *slparams, struct grub_txt_acm_header } } + /* Use MAXPHYADDR for MTRR masks if available */ + if (sinit_caps & GRUB_TXT_CAPS_MAXPHYSADDR_SUPPORT) + os_sinit_data->capabilities |= GRUB_TXT_CAPS_MAXPHYSADDR_SUPPORT; + /* * APs (application processors) can't be brought up by usual INIT-SIPI-SIPI * sequence after Measured Launch, otherwise the MLE integrity is lost. From 90ce968a509c62962f1863dffd5ea3d2b64a2c64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20=C5=BBygowski?= Date: Sun, 15 Sep 2024 14:03:13 +0200 Subject: [PATCH 2/2] grub-core/loader/i386/txt: Set proper capabilities for CBnT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CBnT requires the auth PCR usage and no legacy PCR usage as per TXT MLE Software Development Guide revision 017.4. Signed-off-by: Michał Żygowski --- grub-core/loader/i386/txt/txt.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/grub-core/loader/i386/txt/txt.c b/grub-core/loader/i386/txt/txt.c index fd133a1c99..4ab7736b63 100644 --- a/grub-core/loader/i386/txt/txt.c +++ b/grub-core/loader/i386/txt/txt.c @@ -764,6 +764,15 @@ init_txt_heap (struct grub_slaunch_params *slparams, struct grub_txt_acm_header */ os_sinit_data->capabilities = GRUB_TXT_CAPS_TPM_12_AUTH_PCR_USAGE; + /* CBnT must set bits 4 and 5 */ + if (sinit_caps & GRUB_TXT_CAPS_CBNT_SUPPORT) + { + os_sinit_data->capabilities |= GRUB_TXT_CAPS_CBNT_SUPPORT; + + if (sinit_caps & GRUB_TXT_CAPS_TPM_12_NO_LEGACY_PCR_USAGE) + os_sinit_data->capabilities |= GRUB_TXT_CAPS_TPM_12_NO_LEGACY_PCR_USAGE; + } + if (grub_get_tpm_ver () == GRUB_TPM_20) { if ((sinit_caps & os_sinit_data->capabilities) != os_sinit_data->capabilities) @@ -773,14 +782,14 @@ init_txt_heap (struct grub_slaunch_params *slparams, struct grub_txt_acm_header else { if (!(sinit_caps & GRUB_TXT_CAPS_TPM_12_AUTH_PCR_USAGE)) - { - grub_dprintf ("slaunch", "Details/authorities PCR usage is not supported. Trying legacy"); - if (sinit_caps & GRUB_TXT_CAPS_TPM_12_NO_LEGACY_PCR_USAGE) - return grub_error (GRUB_ERR_BAD_ARGUMENT, - N_("Not a single PCR usage available in SINIT capabilities")); + { + grub_dprintf ("slaunch", "Details/authorities PCR usage is not supported. Trying legacy"); + if (sinit_caps & GRUB_TXT_CAPS_TPM_12_NO_LEGACY_PCR_USAGE) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + N_("Not a single PCR usage available in SINIT capabilities")); - os_sinit_data->capabilities = 0; - } + os_sinit_data->capabilities = 0; + } } /* Use MAXPHYADDR for MTRR masks if available */