From: Ross Philipson <ross.philip...@oracle.com> Signed-off-by: Ross Philipson <ross.philip...@oracle.com> Signed-off-by: Daniel Kiper <daniel.ki...@oracle.com> Signed-off-by: Krystian Hebel <krystian.he...@3mdeb.com> Signed-off-by: Sergii Dmytruk <sergii.dmyt...@3mdeb.com> --- grub-core/Makefile.am | 6 + grub-core/Makefile.core.def | 15 + grub-core/lib/i386/relocator32.S | 8 + grub-core/loader/i386/bsd.c | 4 + grub-core/loader/i386/coreboot/chainloader.c | 2 + grub-core/loader/i386/linux.c | 314 ++++++++++++++++++- grub-core/loader/i386/pc/plan9.c | 3 +- grub-core/loader/i386/slaunch.c | 308 ++++++++++++++++++ grub-core/loader/i386/xnu.c | 3 + grub-core/loader/multiboot.c | 5 + include/grub/file.h | 3 + include/grub/i386/linux.h | 14 +- 12 files changed, 671 insertions(+), 14 deletions(-) create mode 100644 grub-core/loader/i386/slaunch.c
diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am index 1eda467e0..38aea8804 100644 --- a/grub-core/Makefile.am +++ b/grub-core/Makefile.am @@ -103,6 +103,8 @@ KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/kernel.h KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/pxe.h KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/int.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/tsc.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/slaunch.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/slr_table.h endif if COND_i386_xen_pvh @@ -122,6 +124,8 @@ KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/kernel.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/efi.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/disk.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/tsc.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/slaunch.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/slr_table.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/acpi.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/pci.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/pmtimer.h @@ -184,6 +188,8 @@ KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/kernel.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/efi.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/disk.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/tsc.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/slaunch.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/slr_table.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/pci.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/acpi.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/pmtimer.h diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index b988362df..f2975713d 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -1871,6 +1871,15 @@ module = { common = lib/cmdline.c; }; +module = { + name = slaunch; + x86 = loader/i386/slaunch.c; + x86 = loader/i386/txt/txt.c; + x86 = loader/i386/txt/acmod.c; + x86 = loader/i386/txt/verify.c; + enable = x86; +}; + module = { name = fdt; efi = loader/efi/fdt.c; @@ -2555,6 +2564,12 @@ module = { common = commands/testspeed.c; }; +module = { + name = tpm; + x86 = commands/i386/tpm.c; + enable = x86; +}; + module = { name = tpm_verifier; common = commands/tpm_verifier.c; diff --git a/grub-core/lib/i386/relocator32.S b/grub-core/lib/i386/relocator32.S index 09ce56ad0..a2b377197 100644 --- a/grub-core/lib/i386/relocator32.S +++ b/grub-core/lib/i386/relocator32.S @@ -24,6 +24,8 @@ #include "relocator_common.S" +#include <grub/i386/slaunch.h> + .p2align 4 /* force 16-byte alignment */ VARIABLE(grub_relocator32_start) @@ -110,11 +112,17 @@ VARIABLE(grub_relocator32_edx) payload and makes this implementation easier. */ cld + cmpl $SLP_INTEL_TXT, %edi + je LOCAL(intel_txt) + .byte 0xea VARIABLE(grub_relocator32_eip) .long 0 .word CODE_SEGMENT +LOCAL(intel_txt): + getsec + /* GDT. Copied from loader/i386/linux.c. */ .p2align 4 LOCAL(gdt): diff --git a/grub-core/loader/i386/bsd.c b/grub-core/loader/i386/bsd.c index 1f9128f6f..920b7b289 100644 --- a/grub-core/loader/i386/bsd.c +++ b/grub-core/loader/i386/bsd.c @@ -21,6 +21,7 @@ #include <grub/i386/cpuid.h> #include <grub/memory.h> #include <grub/i386/memory.h> +#include <grub/i386/slaunch.h> #include <grub/file.h> #include <grub/err.h> #include <grub/dl.h> @@ -792,6 +793,7 @@ grub_freebsd_boot (void) #endif grub_memcpy (&stack[9], &bi, sizeof (bi)); + state.edi = SLP_NONE; state.eip = entry; state.esp = stack_target; state.ebp = stack_target; @@ -907,6 +909,7 @@ grub_openbsd_boot (void) return err; #endif + state.edi = SLP_NONE; state.eip = entry; state.ebp = state.esp = ((grub_uint8_t *) stack - (grub_uint8_t *) buf0) + buf_target; @@ -1229,6 +1232,7 @@ grub_netbsd_boot (void) return err; #endif + state.edi = SLP_NONE; state.eip = entry; state.esp = stack_target; state.ebp = stack_target; diff --git a/grub-core/loader/i386/coreboot/chainloader.c b/grub-core/loader/i386/coreboot/chainloader.c index 4a5179806..215356a0a 100644 --- a/grub-core/loader/i386/coreboot/chainloader.c +++ b/grub-core/loader/i386/coreboot/chainloader.c @@ -33,6 +33,7 @@ #include <grub/lib/LzmaDec.h> #include <grub/efi/pe32.h> #include <grub/i386/cpuid.h> +#include <grub/i386/slaunch.h> GRUB_MOD_LICENSE ("GPLv3+"); @@ -47,6 +48,7 @@ grub_chain_boot (void) grub_video_set_mode ("text", 0, 0); state.eip = entry; + state.edi = SLP_NONE; return grub_relocator32_boot (relocator, state, 0); } diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c index 977757f2c..f482fa4af 100644 --- a/grub-core/loader/i386/linux.c +++ b/grub-core/loader/i386/linux.c @@ -34,9 +34,12 @@ #include <grub/i386/relocator.h> #include <grub/i18n.h> #include <grub/lib/cmdline.h> +#include <grub/i386/slaunch.h> +#include <grub/i386/txt.h> #include <grub/linux.h> #include <grub/machine/kernel.h> #include <grub/safemath.h> +#include <grub/slr_table.h> GRUB_MOD_LICENSE ("GPLv3+"); @@ -63,18 +66,36 @@ GRUB_MOD_LICENSE ("GPLv3+"); #define ACCEPTS_PURE_TEXT 1 #endif +/* See kernel_info in Documentation/arch/x86/boot.rst in the kernel tree */ +#define KERNEL_INFO_HEADER "LToP" +#define KERNEL_INFO_MIN_SIZE_TOTAL 12 + +struct linux_params_efi_info +{ + grub_uint32_t efi_signature; + grub_uint32_t efi_system_table; + grub_uint32_t efi_mem_desc_size; + grub_uint32_t efi_mem_desc_version; + grub_uint32_t efi_mmap; + grub_uint32_t efi_mmap_size; + grub_uint32_t efi_system_table_hi; + grub_uint32_t efi_mmap_hi; +}; + static grub_dl_t my_mod; static grub_size_t linux_mem_size; static int loaded; static void *prot_mode_mem; static grub_addr_t prot_mode_target; +static grub_size_t prot_file_size; static void *initrd_mem; static grub_addr_t initrd_mem_target; static grub_size_t prot_init_space; static struct grub_relocator *relocator = NULL; static void *efi_mmap_buf; static grub_size_t maximal_cmdline_size; +static struct linux_kernel_info *linux_info; static struct linux_kernel_params linux_params; static char *linux_cmdline; #ifdef GRUB_MACHINE_EFI @@ -98,6 +119,8 @@ static struct idt_descriptor idt_desc = }; #endif +#define OFFSET_OF(x, y) ((grub_size_t) ((grub_uint8_t *) (&(y)->x) - (grub_uint8_t *) (y))) + static inline grub_size_t page_align (grub_size_t size) { @@ -150,11 +173,38 @@ allocate_pages (grub_size_t prot_size, grub_size_t *align, grub_uint64_t preferred_address) { grub_err_t err; + grub_size_t total_size; + struct grub_slaunch_params *slparams = grub_slaunch_params(); if (prot_size == 0) prot_size = 1; - prot_size = page_align (prot_size); + if (grub_slaunch_platform_type () == SLP_INTEL_TXT) + { + if (prot_size > GRUB_TXT_MLE_MAX_SIZE) + { + err = GRUB_ERR_OUT_OF_RANGE; + goto fail; + } + + /* Check performed above makes sure that this doesn't overflow. */ + prot_size = ALIGN_UP (prot_size, GRUB_TXT_PMR_ALIGN); + + slparams->mle_ptab_size = grub_txt_get_mle_ptab_size (prot_size); + slparams->mle_ptab_size = ALIGN_UP (slparams->mle_ptab_size, GRUB_TXT_PMR_ALIGN); + /* Do not go below GRUB_TXT_PMR_ALIGN. */ + preferred_address = (preferred_address > slparams->mle_ptab_size) ? + (preferred_address - slparams->mle_ptab_size) : GRUB_TXT_PMR_ALIGN; + preferred_address = ALIGN_UP (preferred_address, GRUB_TXT_PMR_ALIGN); + } + else + { + prot_size = page_align (prot_size); + slparams->mle_ptab_size = 0; + } + + /* Protected mode code immediately follows MLE page table. */ + total_size = slparams->mle_ptab_size + prot_size; /* Initialize the memory pointers with NULL for convenience. */ free_pages (); @@ -176,15 +226,15 @@ allocate_pages (grub_size_t prot_size, grub_size_t *align, err = grub_relocator_alloc_chunk_align (relocator, &ch, preferred_address, preferred_address, - prot_size, 1, + total_size, 1, GRUB_RELOCATOR_PREFERENCE_LOW, 1); for (; err && *align + 1 > min_align; (*align)--) { grub_errno = GRUB_ERR_NONE; err = grub_relocator_alloc_chunk_align (relocator, &ch, 0x1000000, - UP_TO_TOP32 (prot_size), - prot_size, 1 << *align, + UP_TO_TOP32 (total_size), + total_size, 1 << *align, GRUB_RELOCATOR_PREFERENCE_LOW, 1); } @@ -194,11 +244,80 @@ allocate_pages (grub_size_t prot_size, grub_size_t *align, else err = grub_relocator_alloc_chunk_addr (relocator, &ch, preferred_address, - prot_size); + total_size); if (err) goto fail; prot_mode_mem = get_virtual_current_address (ch); prot_mode_target = get_physical_target_address (ch); + + if (grub_slaunch_platform_type () == SLP_INTEL_TXT) + { + /* Zero out memory to get stable MLE measurements. */ + grub_memset (prot_mode_mem, 0, total_size); + + slparams->mle_ptab_mem = prot_mode_mem; + slparams->mle_ptab_target = prot_mode_target; + + prot_mode_mem = (char *)prot_mode_mem + slparams->mle_ptab_size; + prot_mode_target += slparams->mle_ptab_size; + + slparams->mle_start = prot_mode_target; + slparams->mle_size = prot_size; + slparams->mle_mem = prot_mode_mem; + + grub_dprintf ("linux", "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); + + err = grub_relocator_alloc_chunk_align (relocator, &ch, 0x1000000, + 0xffffffff - GRUB_PAGE_SIZE, + GRUB_PAGE_SIZE, GRUB_PAGE_SIZE, + GRUB_RELOCATOR_PREFERENCE_NONE, 1); + if (err) + goto fail; + + slparams->slr_table_base = get_physical_target_address (ch); + slparams->slr_table_size = GRUB_PAGE_SIZE; + slparams->slr_table_mem = get_virtual_current_address (ch); + + grub_memset (slparams->slr_table_mem, 0, slparams->slr_table_size); + + grub_dprintf ("linux", "slr_table_base = %lx, slr_table_size = %x\n", + (unsigned long) slparams->slr_table_base, + (unsigned) slparams->slr_table_size); + + err = grub_relocator_alloc_chunk_align (relocator, &ch, 0x1000000, + 0xffffffff - GRUB_SLAUNCH_TPM_EVT_LOG_SIZE, + GRUB_SLAUNCH_TPM_EVT_LOG_SIZE, GRUB_PAGE_SIZE, + GRUB_RELOCATOR_PREFERENCE_NONE, 1); + if (err) + goto fail; + + 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 ("linux", "tpm_evt_log_base = %lx, tpm_evt_log_size = %x\n", + (unsigned long) slparams->tpm_evt_log_base, + (unsigned) slparams->tpm_evt_log_size); + + if (grub_relocator_alloc_chunk_align (relocator, &ch, 0x1000000, + 0xffffffff - GRUB_MLE_AP_WAKE_BLOCK_SIZE, + GRUB_MLE_AP_WAKE_BLOCK_SIZE, GRUB_PAGE_SIZE, + GRUB_RELOCATOR_PREFERENCE_NONE, 1)) + goto fail; + + slparams->ap_wake_block = get_physical_target_address (ch); + slparams->ap_wake_block_size = GRUB_MLE_AP_WAKE_BLOCK_SIZE; + + grub_memset (get_virtual_current_address (ch), 0, slparams->ap_wake_block_size); + + grub_dprintf ("linux", "ap_wake_block = %lx, ap_wake_block_size = %lx\n", + (unsigned long) slparams->ap_wake_block, + (unsigned long) slparams->ap_wake_block_size); + } } grub_dprintf ("linux", "prot_mode_mem = %p, prot_mode_target = %lx, prot_size = %x\n", @@ -398,6 +517,63 @@ grub_linux_boot_mmap_fill (grub_uint64_t addr, grub_uint64_t size, return 0; } +static void +grub_linux_setup_slr_table (struct grub_slaunch_params *slparams) +{ + struct linux_kernel_params *boot_params = (void *) (grub_addr_t) slparams->boot_params_addr; + struct linux_params_efi_info *efi_info; + + /* A bit of work to extract the v2.08 EFI info from the linux params */ + efi_info = (void *)((grub_uint8_t *)&boot_params->v0208 + 2*sizeof(grub_uint32_t)); + + grub_slaunch_add_slrt_policy_entry (GRUB_SLAUNCH_DATA_PCR, + GRUB_SLR_ET_BOOT_PARAMS, + /*flags=*/0, + (grub_addr_t) boot_params, + GRUB_PAGE_SIZE, + "Measured boot parameters"); + + if (boot_params->setup_data) + grub_slaunch_add_slrt_policy_entry (GRUB_SLAUNCH_DATA_PCR, + GRUB_SLR_ET_SETUP_DATA, + GRUB_SLR_POLICY_IMPLICIT_SIZE, + boot_params->setup_data, + /*size=*/0, + "Measured Kernel setup_data"); + + /* The cmdline ptr can have hi bits but GRUB puts it always < 4G */ + grub_slaunch_add_slrt_policy_entry (GRUB_SLAUNCH_DATA_PCR, + GRUB_SLR_ET_CMDLINE, + /*flags=*/0, + boot_params->cmd_line_ptr, + boot_params->cmdline_size, + "Measured Kernel command line"); + + if (!grub_memcmp(&efi_info->efi_signature, "EL64", sizeof(grub_uint32_t))) + { + grub_uint64_t mmap_addr = + ((grub_uint64_t) efi_info->efi_mmap_hi << 32) | efi_info->efi_mmap; + grub_slaunch_add_slrt_policy_entry (GRUB_SLAUNCH_DATA_PCR, + GRUB_SLR_ET_UEFI_MEMMAP, + /*flags=*/0, + mmap_addr, + efi_info->efi_mmap_size, + "Measured EFI memory map"); + } + + if (boot_params->ramdisk_image) + /* + * The initrd image and size can have hi bits but in GRUB it is always + * < 4G, see GRUB_LINUX_INITRD_MAX_ADDRESS in grub_cmd_initrd(). + */ + grub_slaunch_add_slrt_policy_entry (GRUB_SLAUNCH_CODE_PCR, + GRUB_SLR_ET_RAMDISK, + /*flags=*/0, + boot_params->ramdisk_image, + boot_params->ramdisk_size, + "Measured Kernel initrd"); +} + static grub_err_t grub_linux_boot (void) { @@ -411,6 +587,7 @@ grub_linux_boot (void) }; grub_size_t mmap_size; grub_size_t cl_offset; + struct grub_slaunch_params *slparams = grub_slaunch_params(); #ifdef GRUB_MACHINE_IEEE1275 { @@ -587,6 +764,8 @@ grub_linux_boot (void) ctx.params->secure_boot = grub_efi_get_secureboot (); + grub_dprintf ("linux", "EFI exit boot services\n"); + err = grub_efi_finish_boot_services (&efi_mmap_size, efi_mmap_buf, NULL, &efi_desc_size, &efi_desc_version); if (err) @@ -636,12 +815,38 @@ grub_linux_boot (void) } #endif - /* FIXME. */ - /* asm volatile ("lidt %0" : : "m" (idt_desc)); */ - state.ebp = state.edi = state.ebx = 0; - state.esi = ctx.real_mode_target; - state.esp = ctx.real_mode_target; - state.eip = ctx.params->code32_start; + state.edi = grub_slaunch_platform_type (); + + if (state.edi == SLP_INTEL_TXT) + { + slparams->boot_params_addr = ctx.real_mode_target; + + err = grub_txt_boot_prepare (slparams); + + if (err != GRUB_ERR_NONE) + return grub_error (err, "TXT boot preparation failed"); + + grub_slaunch_add_slrt_policy_entries (); + grub_txt_add_slrt_policy_entries (); + grub_linux_setup_slr_table (slparams); + grub_slaunch_finish_slr_table (); + + /* Configure relocator GETSEC[SENTER] call. */ + state.eax = GRUB_SMX_LEAF_SENTER; + state.ebx = slparams->dce_base; + state.ecx = slparams->dce_size; + state.edx = 0; + } + else + { + /* FIXME. */ + /* asm volatile ("lidt %0" : : "m" (idt_desc)); */ + state.ebp = state.edi = state.ebx = 0; + state.esi = ctx.real_mode_target; + state.esp = ctx.real_mode_target; + state.eip = ctx.params->code32_start; + } + return grub_relocator32_boot (relocator, state, 0); } @@ -662,12 +867,13 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), grub_file_t file = 0; struct linux_i386_kernel_header lh; grub_uint8_t setup_sects; - grub_size_t real_size, prot_size, prot_file_size; + grub_size_t real_size, prot_size; grub_ssize_t len; int i; grub_size_t align, min_align; int relocatable; grub_uint64_t preferred_address = GRUB_LINUX_BZIMAGE_ADDR; + struct grub_slaunch_params *slparams = grub_slaunch_params(); grub_dl_ref (my_mod); @@ -772,6 +978,13 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), prot_init_space = page_align (prot_size) * 3; } + if (grub_slaunch_platform_type () == SLP_INTEL_TXT) + { + /* PMRs require GRUB_TXT_PMR_ALIGN_SHIFT aligments. */ + min_align = grub_max (min_align, GRUB_TXT_PMR_ALIGN_SHIFT); + align = grub_max (align, GRUB_TXT_PMR_ALIGN_SHIFT); + } + if (allocate_pages (prot_size, &align, min_align, relocatable, preferred_address)) @@ -779,6 +992,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), grub_memset (&linux_params, 0, sizeof (linux_params)); + if (grub_slaunch_platform_type () == SLP_INTEL_TXT) + grub_txt_setup_mle_ptab (slparams); + /* * The Linux 32-bit boot protocol defines the setup header end * to be at 0x202 + the byte value at 0x201. @@ -805,6 +1021,80 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), goto fail; } + /* Read the kernel_info struct. */ + if (grub_le_to_cpu16 (lh.version) >= 0x020f) + { + if (grub_file_seek (file, (grub_off_t) grub_le_to_cpu32 (lh.kernel_info_offset) + + real_size + GRUB_DISK_SECTOR_SIZE) == ((grub_off_t) -1)) + goto fail; + + linux_info = grub_malloc (KERNEL_INFO_MIN_SIZE_TOTAL); + + if (!linux_info) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate memory for kernel_info")); + goto fail; + } + + /* Load minimal kernel_info struct. */ + if (grub_file_read (file, linux_info, + KERNEL_INFO_MIN_SIZE_TOTAL) != KERNEL_INFO_MIN_SIZE_TOTAL) + { + if (!grub_errno) + grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), argv[0]); + goto fail; + } + + if (grub_memcmp (&linux_info->header, KERNEL_INFO_HEADER, sizeof (linux_info->header))) + { + grub_error (GRUB_ERR_BAD_OS, N_("incorrect kernel_info header")); + goto fail; + } + + linux_info->size_total = grub_le_to_cpu32 (linux_info->size_total); + if (linux_info->size_total < KERNEL_INFO_MIN_SIZE_TOTAL) + { + grub_error (GRUB_ERR_BAD_OS, N_("incorrect kernel_info size")); + goto fail; + } + + linux_info = grub_realloc (linux_info, linux_info->size_total); + + if (!linux_info) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot reallocate memory for kernel_info")); + goto fail; + } + + /* Load the rest of kernel_info struct. */ + if (grub_file_read (file, &linux_info->setup_type_max, + linux_info->size_total - KERNEL_INFO_MIN_SIZE_TOTAL) != + (grub_ssize_t)(linux_info->size_total - KERNEL_INFO_MIN_SIZE_TOTAL)) + { + if (!grub_errno) + grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), argv[0]); + goto fail; + } + + if (grub_slaunch_platform_type () != SLP_NONE) + { + if (OFFSET_OF (mle_header_offset, linux_info) >= + grub_le_to_cpu32 (linux_info->size)) + { + if (!grub_errno) + grub_error (GRUB_ERR_BAD_OS, N_("not slaunch kernel: lack of mle_header_offset")); + goto fail; + } + + slparams->mle_header_offset = grub_le_to_cpu32 (linux_info->mle_header_offset); + } + } + else if (grub_slaunch_platform_type () != SLP_NONE) + { + grub_error (GRUB_ERR_BAD_OS, N_("not slaunch kernel: boot protocol too old")); + goto fail; + } + linux_params.code32_start = prot_mode_target + lh.code32_start - GRUB_LINUX_BZIMAGE_ADDR; linux_params.kernel_alignment = (1 << align); linux_params.ps_mouse = linux_params.padding11 = 0; diff --git a/grub-core/loader/i386/pc/plan9.c b/grub-core/loader/i386/pc/plan9.c index 960e866f4..9ec461c75 100644 --- a/grub-core/loader/i386/pc/plan9.c +++ b/grub-core/loader/i386/pc/plan9.c @@ -34,6 +34,7 @@ #include <grub/cpu/relocator.h> #include <grub/extcmd.h> #include <grub/verify.h> +#include <grub/i386/slaunch.h> GRUB_MOD_LICENSE ("GPLv3+"); @@ -84,7 +85,7 @@ grub_plan9_boot (void) .ebx = 0, .ecx = 0, .edx = 0, - .edi = 0, + .edi = SLP_NONE, .esp = 0, .ebp = 0, .esi = 0 diff --git a/grub-core/loader/i386/slaunch.c b/grub-core/loader/i386/slaunch.c new file mode 100644 index 000000000..824b5c23b --- /dev/null +++ b/grub-core/loader/i386/slaunch.c @@ -0,0 +1,308 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2020 Oracle and/or its affiliates. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <grub/loader.h> +#include <grub/memory.h> +#include <grub/normal.h> +#include <grub/err.h> +#include <grub/misc.h> +#include <grub/types.h> +#include <grub/dl.h> +#include <grub/slr_table.h> +#include <grub/cpu/relocator.h> +#include <grub/i386/cpuid.h> +#include <grub/i386/msr.h> +#include <grub/i386/mmio.h> +#include <grub/i386/slaunch.h> +#include <grub/i386/tpm.h> +#include <grub/i386/txt.h> + +GRUB_MOD_LICENSE ("GPLv3+"); + +static grub_uint32_t slp = SLP_NONE; + +static void *slaunch_module = NULL; + +static struct grub_slaunch_params slparams; + +/* Area to collect and build SLR Table information. */ +static struct grub_slr_entry_dl_info slr_dl_info_staging; +static struct grub_slr_entry_log_info slr_log_info_staging; +static grub_uint8_t slr_policy_buf[GRUB_PAGE_SIZE]; +static struct grub_slr_entry_policy *slr_policy_staging = + (struct grub_slr_entry_policy *)slr_policy_buf; + +grub_uint32_t +grub_slaunch_platform_type (void) +{ + return slp; +} + +void * +grub_slaunch_module (void) +{ + return slaunch_module; +} + +struct grub_slaunch_params * +grub_slaunch_params (void) +{ + return &slparams; +} + +void +grub_slaunch_init_slrt_storage (int arch) +{ + struct grub_txt_mle_header *mle_header = + (void *) ((grub_uint8_t *) slparams.mle_mem + slparams.mle_header_offset); + + /* Setup the generic bits of the SLRT. */ + grub_slr_init_table(slparams.slr_table_mem, arch, slparams.slr_table_size); + + /* Setup DCE and DLME information. */ + slr_dl_info_staging.hdr.tag = GRUB_SLR_ENTRY_DL_INFO; + slr_dl_info_staging.hdr.size = sizeof(struct grub_slr_entry_dl_info); + slr_dl_info_staging.dce_base = slparams.dce_base; + slr_dl_info_staging.dce_size = slparams.dce_size; + slr_dl_info_staging.dlme_base = slparams.mle_start; + slr_dl_info_staging.dlme_size = slparams.mle_size; + slr_dl_info_staging.dlme_entry = mle_header->entry_point; + + slr_log_info_staging.hdr.tag = GRUB_SLR_ENTRY_LOG_INFO; + slr_log_info_staging.hdr.size = sizeof(struct grub_slr_entry_log_info); + slr_log_info_staging.addr = slparams.tpm_evt_log_base; + slr_log_info_staging.size = slparams.tpm_evt_log_size; + slr_log_info_staging.format = + (grub_get_tpm_ver () == GRUB_TPM_20) ? + GRUB_SLR_DRTM_TPM20_LOG : GRUB_SLR_DRTM_TPM12_LOG; + + slr_policy_staging->hdr.tag = GRUB_SLR_ENTRY_DRTM_POLICY; + slr_policy_staging->hdr.size = sizeof(struct grub_slr_entry_policy); + slr_policy_staging->revision = GRUB_SLR_TABLE_REVISION; + slr_policy_staging->nr_entries = 0; +} + +void grub_slaunch_add_slrt_policy_entries (void) +{ + /* The SLR table should be measured too, at least parts of it. */ + grub_slaunch_add_slrt_policy_entry (GRUB_SLAUNCH_DATA_PCR, + GRUB_SLR_ET_SLRT, + GRUB_SLR_POLICY_IMPLICIT_SIZE, + slparams.slr_table_base, + /*size=*/0, + "Measured SLR Table"); +} + +void +grub_slaunch_add_slrt_policy_entry (grub_uint16_t pcr, + grub_uint16_t entity_type, + grub_uint16_t flags, + grub_uint64_t entity, + grub_uint64_t size, + const char *evt_info) +{ + struct grub_slr_policy_entry *entry = + (void *)((grub_uint8_t *) slr_policy_staging + + sizeof(struct grub_slr_entry_policy) + + slr_policy_staging->nr_entries*sizeof(*entry)); + + if (slr_policy_staging->hdr.size > sizeof(slr_policy_buf) - sizeof(*entry)) + grub_fatal ("Not enough space for adding policy entry: %s! The buffer is full.", + evt_info); + + entry->pcr = pcr; + entry->entity_type = entity_type; + entry->flags = flags; + entry->entity = entity; + entry->size = size; + + grub_strncpy (entry->evt_info, evt_info, sizeof(entry->evt_info) - 1); + entry->evt_info[sizeof(entry->evt_info) - 1] = '\0'; + + slr_policy_staging->hdr.size += sizeof(*entry); + ++slr_policy_staging->nr_entries; +} + +void +grub_slaunch_finish_slr_table (void) +{ + struct grub_slr_table *slr_table = slparams.slr_table_mem; + + grub_slr_add_entry (slr_table, &slr_dl_info_staging.hdr); + grub_slr_add_entry (slr_table, &slr_log_info_staging.hdr); + grub_slr_add_entry (slr_table, &slr_policy_staging->hdr); +} + +static grub_err_t +grub_cmd_slaunch (grub_command_t cmd __attribute__ ((unused)), + int argc __attribute__ ((unused)), + char *argv[] __attribute__ ((unused))) +{ + grub_uint32_t manufacturer[3]; + grub_uint32_t eax; + grub_err_t err; + + if (!grub_cpu_is_cpuid_supported ()) + return grub_error (GRUB_ERR_BAD_DEVICE, N_("CPUID is unsupported")); + + err = grub_cpu_is_msr_supported (); + + if (err != GRUB_ERR_NONE) + return grub_error (err, N_("MSRs are unsupported")); + + grub_cpuid (0, eax, manufacturer[0], manufacturer[2], manufacturer[1]); + + if (!grub_memcmp (manufacturer, "GenuineIntel", 12)) + { + err = grub_txt_init (); + + if (err != GRUB_ERR_NONE) + return err; + + slp = SLP_INTEL_TXT; + } + else + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("CPU is unsupported")); + + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_cmd_slaunch_module (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + grub_file_t file; + grub_ssize_t size; + void *new_module = NULL; + + if (argc != 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected: filename")); + + if (slp == SLP_NONE) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("secure launch not enabled")); + + if (slp != SLP_INTEL_TXT) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + N_("unknown secure launch platform type: %d"), slp); + + grub_errno = GRUB_ERR_NONE; + + file = grub_file_open (argv[0], GRUB_FILE_TYPE_SLAUNCH_MODULE); + + if (file == NULL) + return grub_errno; + + size = grub_file_size (file); + + if (!size) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, N_("file size is zero")); + goto fail; + } + + new_module = grub_malloc (size); + + if (new_module == NULL) + goto fail; + + if (grub_file_read (file, new_module, size) != size) + { + if (grub_errno == GRUB_ERR_NONE) + grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file: %s"), + argv[0]); + goto fail; + } + + if (slp == SLP_INTEL_TXT) + { + if (!grub_txt_is_sinit_acmod (new_module, size)) + { + grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("it does not look like SINIT ACM")); + goto fail; + } + + if (!grub_txt_acmod_match_platform (new_module)) + { + grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("SINIT ACM does not match platform")); + goto fail; + } + } + + grub_file_close (file); + + grub_free (slaunch_module); + slaunch_module = new_module; + + return GRUB_ERR_NONE; + +fail: + grub_error_push (); + + grub_free (new_module); + grub_file_close (file); + + grub_error_pop (); + + return grub_errno; +} + +static grub_err_t +grub_cmd_slaunch_state (grub_command_t cmd __attribute__ ((unused)), + int argc __attribute__ ((unused)), + char *argv[] __attribute__ ((unused))) +{ + if (slp == SLP_NONE) + grub_printf ("Secure launcher: Disabled\n"); + else if (slp == SLP_INTEL_TXT) + { + grub_printf ("Secure launcher: Intel TXT\n"); + grub_txt_state_show (); + } + else + return grub_error (GRUB_ERR_BAD_ARGUMENT, + N_("Unknown secure launcher platform type: %d\n"), slp); + + return GRUB_ERR_NONE; +} + +static grub_command_t cmd_slaunch, cmd_slaunch_module, cmd_slaunch_state; + +GRUB_MOD_INIT (slaunch) +{ + cmd_slaunch = grub_register_command ("slaunch", grub_cmd_slaunch, + NULL, N_("Enable secure launcher")); + cmd_slaunch_module = grub_register_command ("slaunch_module", grub_cmd_slaunch_module, + NULL, N_("Load secure launcher module from file")); + cmd_slaunch_state = grub_register_command ("slaunch_state", grub_cmd_slaunch_state, + NULL, N_("Display secure launcher state")); +} + +GRUB_MOD_FINI (slaunch) +{ + if (cmd_slaunch_state) + grub_unregister_command (cmd_slaunch_state); + + if (cmd_slaunch_module) + grub_unregister_command (cmd_slaunch_module); + + if (cmd_slaunch) + grub_unregister_command (cmd_slaunch); + + if (slp == SLP_INTEL_TXT) + grub_txt_shutdown (); +} diff --git a/grub-core/loader/i386/xnu.c b/grub-core/loader/i386/xnu.c index b91e2f840..ba73d909a 100644 --- a/grub-core/loader/i386/xnu.c +++ b/grub-core/loader/i386/xnu.c @@ -28,6 +28,7 @@ #include <grub/i386/cpuid.h> #include <grub/efi/api.h> #include <grub/i386/pit.h> +#include <grub/i386/slaunch.h> #include <grub/misc.h> #include <grub/charset.h> #include <grub/term.h> @@ -802,6 +803,7 @@ grub_xnu_boot_resume (void) { struct grub_relocator32_state state = {0}; + state.edi = SLP_NONE; state.esp = grub_xnu_stack; state.ebp = grub_xnu_stack; state.eip = grub_xnu_entry_point; @@ -1129,6 +1131,7 @@ grub_xnu_boot (void) grub_autoefi_set_virtual_address_map (memory_map_size, descriptor_size, descriptor_version, memory_map); + state.edi = SLP_NONE; state.eip = grub_xnu_entry_point; state.eax = grub_xnu_arg1; state.esp = grub_xnu_stack; diff --git a/grub-core/loader/multiboot.c b/grub-core/loader/multiboot.c index 94be512c4..efabbf611 100644 --- a/grub-core/loader/multiboot.c +++ b/grub-core/loader/multiboot.c @@ -50,6 +50,9 @@ #include <grub/video.h> #include <grub/memory.h> #include <grub/i18n.h> +#if defined (__i386__) || defined (__x86_64__) +#include <grub/i386/slaunch.h> +#endif GRUB_MOD_LICENSE ("GPLv3+"); @@ -161,6 +164,8 @@ 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; + grub_relocator32_boot (rel, state, 0); } #else diff --git a/include/grub/file.h b/include/grub/file.h index a5bf3a792..47b638a43 100644 --- a/include/grub/file.h +++ b/include/grub/file.h @@ -132,6 +132,9 @@ enum grub_file_type GRUB_FILE_TYPE_VERIFY_SIGNATURE, + /* Secure Launch module. */ + GRUB_FILE_TYPE_SLAUNCH_MODULE, + GRUB_FILE_TYPE_MASK = 0xffff, /* --skip-sig is specified. */ diff --git a/include/grub/i386/linux.h b/include/grub/i386/linux.h index d4b550869..a552f0d2a 100644 --- a/include/grub/i386/linux.h +++ b/include/grub/i386/linux.h @@ -158,6 +158,17 @@ struct linux_i386_kernel_header grub_uint64_t pref_address; grub_uint32_t init_size; grub_uint32_t handover_offset; + grub_uint32_t kernel_info_offset; +} GRUB_PACKED; + +struct linux_kernel_info +{ + grub_uint32_t header; + grub_uint32_t size; /* In bytes, excluding var_len_data[] */ + grub_uint32_t size_total; /* In bytes, including var_len_data[] */ + grub_uint32_t setup_type_max; + grub_uint32_t mle_header_offset; + grub_uint8_t var_len_data[]; } GRUB_PACKED; /* Boot parameters for Linux based on 2.6.12. This is used by the setup @@ -336,9 +347,10 @@ struct linux_kernel_params grub_uint64_t pref_address; grub_uint32_t init_size; grub_uint32_t handover_offset; + grub_uint32_t kernel_info_offset; /* Linux setup header copy - END. */ - grub_uint8_t _pad7[40]; + grub_uint8_t _pad7[36]; grub_uint32_t edd_mbr_sig_buffer[EDD_MBR_SIG_MAX]; /* 290 */ struct grub_e820_mmap e820_map[(0x400 - 0x2d0) / 20]; /* 2d0 */ } GRUB_PACKED; -- 2.46.0 _______________________________________________ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel