From 58c9a06983cb68f04548713208b25c0b579b4043 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20=C5=BBygowski?= Date: Thu, 1 Sep 2022 17:58:53 +0200 Subject: [PATCH] multiboot2: Implement TXT slaunch support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The code makes sure that MBI entry goes first in DRTM, so the payload can measure it first on launch. SLRT table is allocated on the heap first, size for it is reserved inside TXT heap by TXT code and data is later copied into its final place. Signed-off-by: Sergii Dmytruk Signed-off-by: Michał Żygowski Signed-off-by: Tomasz Żyjewski Signed-off-by: Krystian Hebel --- grub-core/loader/multiboot.c | 23 ++++++- grub-core/loader/multiboot_elfxx.c | 104 ++++++++++++++++++++++++++--- grub-core/loader/multiboot_mbi2.c | 99 +++++++++++++++++++++++++++ include/grub/multiboot2.h | 2 + 4 files changed, 219 insertions(+), 9 deletions(-) diff --git a/grub-core/loader/multiboot.c b/grub-core/loader/multiboot.c index 07173f60e..17a922be2 100644 --- a/grub-core/loader/multiboot.c +++ b/grub-core/loader/multiboot.c @@ -52,6 +52,7 @@ #include #if defined (__i386__) || defined (__x86_64__) #include +#include #endif GRUB_MOD_LICENSE ("GPLv3+"); @@ -164,7 +165,17 @@ efi_boot (struct grub_relocator *rel __attribute__ ((unused)), static void normal_boot (struct grub_relocator *rel, struct grub_relocator32_state state) { - state.edi = SLP_NONE; + struct grub_slaunch_params *slparams = grub_slaunch_params(); + state.edi = grub_slaunch_platform_type (); + + if (state.edi == SLP_INTEL_TXT) + { + /* Configure relocator GETSEC[SENTER] call. */ + state.eax = GRUB_SMX_LEAF_SENTER; + state.ebx = slparams->dce_base; + state.ecx = slparams->dce_size; + state.edx = 0; + } grub_relocator32_boot (rel, state, 0); } @@ -194,6 +205,16 @@ grub_multiboot_boot (void) if (err) return err; +#ifdef GRUB_USE_MULTIBOOT2 + if (grub_slaunch_platform_type () == SLP_INTEL_TXT) + { + err = grub_multiboot2_prepare_slaunch_txt (state.MULTIBOOT_MBI_REGISTER, + mbi_size); + if (err) + return err; + } +#endif + if (grub_efi_is_finished) normal_boot (GRUB_MULTIBOOT (relocator), state); else diff --git a/grub-core/loader/multiboot_elfxx.c b/grub-core/loader/multiboot_elfxx.c index f2318e0d1..438cedc2c 100644 --- a/grub-core/loader/multiboot_elfxx.c +++ b/grub-core/loader/multiboot_elfxx.c @@ -34,6 +34,8 @@ #error "I'm confused" #endif +#include +#include #include #define CONCAT(a,b) CONCAT_(a, b) @@ -60,6 +62,9 @@ CONCAT(grub_multiboot_load_elf, XX) (mbi_load_data_t *mld) grub_uint32_t load_offset = 0, load_size; int i; void *source = NULL; + struct grub_slaunch_params *slparams = grub_slaunch_params(); + grub_size_t total_size; + grub_uint32_t mle_hdr_offset; if (ehdr->e_ident[EI_MAG0] != ELFMAG0 || ehdr->e_ident[EI_MAG1] != ELFMAG1 @@ -106,25 +111,87 @@ CONCAT(grub_multiboot_load_elf, XX) (mbi_load_data_t *mld) (long) mld->align, mld->preference, load_size, mld->avoid_efi_boot_services); - if (load_size > mld->max_addr || mld->min_addr > mld->max_addr - load_size) + if (grub_slaunch_platform_type () == SLP_INTEL_TXT) + { +#ifndef GRUB_USE_MULTIBOOT2 + return grub_error (GRUB_ERR_BAD_OS, "Only multiboot2 supported for slaunch"); +#else + /* + * We allocate the the binary together with page tables to make one + * contiguous block for MLE. We have to align up to PMR (2MB). + */ + total_size = ALIGN_UP(load_size, GRUB_TXT_PMR_ALIGN); + + slparams->mle_size = total_size; + + slparams->mle_ptab_size = grub_txt_get_mle_ptab_size (total_size); + slparams->mle_ptab_size = ALIGN_UP (slparams->mle_ptab_size, GRUB_TXT_PMR_ALIGN); + + /* Do not go below GRUB_TXT_PMR_ALIGN. */ + if (mld->align < GRUB_TXT_PMR_ALIGN) + mld->align = GRUB_TXT_PMR_ALIGN; +#endif + } + else + { + total_size = load_size; + slparams->mle_ptab_size = 0; + } + + if (total_size > mld->max_addr || mld->min_addr > mld->max_addr - total_size) return grub_error (GRUB_ERR_BAD_OS, "invalid min/max address and/or load size"); err = grub_relocator_alloc_chunk_align_safe (GRUB_MULTIBOOT (relocator), &ch, - mld->min_addr, mld->max_addr, - load_size, mld->align ? mld->align : 1, + mld->min_addr, mld->max_addr - total_size, + total_size, mld->align ? mld->align : 1, mld->preference, mld->avoid_efi_boot_services); if (err) - { - grub_dprintf ("multiboot_loader", "Cannot allocate memory for OS image\n"); - return err; - } + { + grub_dprintf ("multiboot_loader", "Cannot allocate memory for OS image\n"); + return err; + } mld->load_base_addr = get_physical_target_address (ch); source = get_virtual_current_address (ch); + grub_memset (get_virtual_current_address (ch), 0, total_size); + grub_dprintf ("multiboot_loader", "load_base_addr=0x%lx, source=0x%lx\n", + (long) mld->load_base_addr, (long) source); + + if (grub_slaunch_platform_type () == SLP_INTEL_TXT) + { +#ifndef GRUB_USE_MULTIBOOT2 + return grub_error (GRUB_ERR_BAD_OS, "Only multiboot2 supported for slaunch"); +#else + slparams->mle_start = mld->load_base_addr; + slparams->mle_mem = source; + + err = grub_relocator_alloc_chunk_align_safe (GRUB_MULTIBOOT (relocator), &ch, + GRUB_MEMORY_MACHINE_UPPER_START, + mld->load_base_addr - slparams->mle_ptab_size, + slparams->mle_ptab_size, GRUB_TXT_PMR_ALIGN, + GRUB_RELOCATOR_PREFERENCE_NONE, 1); + if (err) + { + grub_dprintf ("multiboot_loader", "Cannot allocate memory for MLE page tables\n"); + return err; + } + + slparams->mle_ptab_mem = get_virtual_current_address (ch); + slparams->mle_ptab_target = (grub_uint64_t) get_physical_target_address (ch); + grub_dprintf ("multiboot_loader", "mle_ptab_mem = %p, mle_ptab_target = %lx, mle_ptab_size = %x\n", + slparams->mle_ptab_mem, (unsigned long) slparams->mle_ptab_target, + (unsigned) slparams->mle_ptab_size); +#endif + } } else - mld->load_base_addr = mld->link_base_addr; + { + mld->load_base_addr = mld->link_base_addr; + /* TODO: support non-relocatable */ + if (grub_slaunch_platform_type () == SLP_INTEL_TXT) + return grub_error (GRUB_ERR_BAD_OS, "Non-relocatable ELF not supported with slaunch"); + } grub_dprintf ("multiboot_loader", "relocatable=%d, link_base_addr=0x%x, " "load_base_addr=0x%x\n", mld->relocatable, @@ -180,6 +247,27 @@ CONCAT(grub_multiboot_load_elf, XX) (mbi_load_data_t *mld) } } + if (grub_slaunch_platform_type () == SLP_INTEL_TXT) + { + slparams->mle_header_offset = 0xffffffff; + + /* TODO: decide on universal way of conveying location of MLE header */ + for (mle_hdr_offset = 0; mle_hdr_offset < 0x1000; mle_hdr_offset += 16) + { + if ( !grub_memcmp ((void *)((grub_addr_t) source + mle_hdr_offset), GRUB_TXT_MLE_UUID, 16) ) + { + slparams->mle_header_offset = mle_hdr_offset; + break; + } + } + + if (slparams->mle_header_offset == 0xffffffff) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "MLE header not found"); + + grub_dprintf ("slaunch", "slparams->mle_header_offset: 0x%08x\n", + slparams->mle_header_offset); + } + for (i = 0; i < ehdr->e_phnum; i++) if (phdr(i)->p_vaddr <= ehdr->e_entry && phdr(i)->p_vaddr + phdr(i)->p_memsz > ehdr->e_entry) diff --git a/grub-core/loader/multiboot_mbi2.c b/grub-core/loader/multiboot_mbi2.c index 197afd1b1..fd93bc0e4 100644 --- a/grub-core/loader/multiboot_mbi2.c +++ b/grub-core/loader/multiboot_mbi2.c @@ -36,6 +36,10 @@ #include #include #include +#include +#include +#include +#include #if defined (GRUB_MACHINE_EFI) #include @@ -277,6 +281,9 @@ grub_multiboot2_load (grub_file_t file, const char *filename) if (addr_tag) { + if (grub_slaunch_platform_type () == SLP_INTEL_TXT) + return grub_error (GRUB_ERR_BAD_OS, "Slaunch not supported with multiboot addr tag"); + grub_uint64_t load_addr = (addr_tag->load_addr + 1) ? addr_tag->load_addr : (addr_tag->header_addr - ((char *) header - (char *) mld.buffer)); @@ -390,6 +397,34 @@ grub_multiboot2_load (grub_file_t file, const char *filename) err = grub_multiboot2_set_console (GRUB_MULTIBOOT2_CONSOLE_EGA_TEXT, accepted_consoles, 0, 0, 0, console_required); + + if (grub_slaunch_platform_type () == SLP_INTEL_TXT) + { + grub_relocator_chunk_t ch; + struct grub_slaunch_params *slparams = grub_slaunch_params(); + + if (grub_relocator_alloc_chunk_align_safe (grub_multiboot2_relocator, &ch, 0x1000000, + UP_TO_TOP32 (GRUB_SLAUNCH_TPM_EVT_LOG_SIZE), + GRUB_SLAUNCH_TPM_EVT_LOG_SIZE, GRUB_PAGE_SIZE, + GRUB_RELOCATOR_PREFERENCE_HIGH, 1)) + { + grub_free (mld.buffer); + return grub_error (GRUB_ERR_OUT_OF_MEMORY, "Could not allocate TPM event log area"); + } + + slparams->tpm_evt_log_base = get_physical_target_address (ch); + slparams->tpm_evt_log_size = GRUB_SLAUNCH_TPM_EVT_LOG_SIZE; + + grub_txt_init_tpm_event_log(get_virtual_current_address (ch), + slparams->tpm_evt_log_size); + + grub_dprintf ("multiboot_loader", "tpm_evt_log_base = %lx, tpm_evt_log_size = %x\n", + (unsigned long) slparams->tpm_evt_log_base, + (unsigned) slparams->tpm_evt_log_size); + + grub_txt_setup_mle_ptab (slparams); + } + return err; } @@ -722,7 +757,12 @@ grub_multiboot2_make_mbi (grub_uint32_t *target, grub_uint32_t *size) ptrorig = get_virtual_current_address (ch); #if defined (__i386__) || defined (__x86_64__) + struct grub_slaunch_params *slparams = grub_slaunch_params(); + *target = get_physical_target_address (ch); + /* Save MBI pointer in the TXT heap area */ + if (grub_slaunch_platform_type () == SLP_INTEL_TXT) + slparams->boot_params_addr = *target; #elif defined (__mips) *target = get_physical_target_address (ch) | 0x80000000; #else @@ -1128,3 +1168,62 @@ grub_multiboot2_set_bootdev (void) bootdev_set = 1; } + +static void +add_multiboot2_slrt_policy_entries (void) +{ + unsigned i; + struct module *cur; + + for (i = 0, cur = modules; i < modcnt; i++, cur = cur->next) + { + grub_slaunch_add_slrt_policy_entry (17, + GRUB_SLR_ET_MULTIBOOT2_MODULE, + /*flags=*/0, + cur->start, + cur->size, + "Measured MB2 module"); + } +} + +grub_err_t +grub_multiboot2_prepare_slaunch_txt (grub_uint32_t mbi_target, + grub_uint32_t mbi_size) +{ + grub_err_t err; + struct grub_slaunch_params *slparams = grub_slaunch_params (); + + slparams->slr_table_base = GRUB_SLAUNCH_STORE_IN_OS2MLE; + slparams->slr_table_size = GRUB_PAGE_SIZE; + + slparams->slr_table_mem = grub_zalloc (slparams->slr_table_size); + if (slparams->slr_table_mem == NULL) + return GRUB_ERR_OUT_OF_MEMORY; + + err = grub_txt_boot_prepare (slparams); + if (err != GRUB_ERR_NONE) + { + grub_printf ("TXT boot preparation failed"); + return err; + } + + grub_slaunch_add_slrt_policy_entry (18, + GRUB_SLR_ET_MULTIBOOT2_INFO, + /*flags=*/0, + mbi_target, + mbi_size, + "Measured MB2 information"); + grub_slaunch_add_slrt_policy_entries (); + grub_txt_add_slrt_policy_entries (); + add_multiboot2_slrt_policy_entries (); + grub_slaunch_finish_slr_table (); + + grub_dprintf ("multiboot_loader", "slr_table_base = %lx, slr_table_size = %x\n", + (unsigned long) slparams->slr_table_base, + (unsigned) slparams->slr_table_size); + grub_memcpy ((void *)(grub_addr_t) slparams->slr_table_base, + slparams->slr_table_mem, + slparams->slr_table_size); + + return GRUB_ERR_NONE; +} diff --git a/include/grub/multiboot2.h b/include/grub/multiboot2.h index d1e3b3a8b..0ca577e73 100644 --- a/include/grub/multiboot2.h +++ b/include/grub/multiboot2.h @@ -43,6 +43,8 @@ void grub_multiboot2_set_bootdev (void); void grub_multiboot2_add_elfsyms (grub_size_t num, grub_size_t entsize, unsigned shndx, void *data); +grub_err_t grub_multiboot2_prepare_slaunch_txt (grub_uint32_t mbi_target, + grub_uint32_t mbi_size); grub_uint32_t grub_multiboot2_get_mmap_count (void); grub_err_t grub_multiboot2_set_video_mode (void);