From: Ross Philipson <[email protected]>
Signed-off-by: Ross Philipson <[email protected]>
Signed-off-by: Daniel Kiper <[email protected]>
Signed-off-by: Krystian Hebel <[email protected]>
Signed-off-by: Sergii Dmytruk <[email protected]>
---
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
[email protected]
https://lists.gnu.org/mailman/listinfo/grub-devel