grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH v3 14/19] slaunch: Add Secure Launch framework and commands


From: Sergii Dmytruk
Subject: [PATCH v3 14/19] slaunch: Add Secure Launch framework and commands
Date: Thu, 12 Dec 2024 15:41:42 +0200

From: Fedora Ninjas <grub2-owner@fedoraproject.org>

The usage looks as follows:

  # Enable secure launch (required and must come before other slaunch
  # commands).
  slaunch

  # Specify the startup binary for DRTM.  This is optional on Intel if
  # BIOS has already loaded ACM.  There can be multiple such commands
  # with the last valid one taking effect (the invalid files print an
  # error message but are otherwise ignored).
  slaunch_module /some/file

  # Prints current status of ACM for debugging purposes.
  slaunch_state

  # Specify kernel/initrd and boot as usual.

Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
Signed-off-by: Daniel Kiper <daniel.kiper@oracle.com>
Signed-off-by: Sergii Dmytruk <sergii.dmytruk@3mdeb.com>
---
 docs/grub.texi                        |   9 ++
 grub-core/Makefile.core.def           |  13 ++
 grub-core/lib/i386/relocator32.S      |   8 +
 grub-core/loader/i386/bsd.c           |   3 +
 grub-core/loader/i386/linux.c         |  87 +++++++++-
 grub-core/loader/i386/xnu.c           |   2 +
 grub-core/loader/multiboot.c          |   2 +
 grub-core/loader/slaunch/i386_linux.c | 220 ++++++++++++++++++++++++++
 grub-core/loader/slaunch/slaunch.c    | 204 ++++++++++++++++++++++++
 include/grub/file.h                   |   3 +
 include/grub/i386/linux.h             |  14 +-
 include/grub/slaunch.h                |  15 ++
 12 files changed, 573 insertions(+), 7 deletions(-)
 create mode 100644 grub-core/loader/slaunch/i386_linux.c
 create mode 100644 grub-core/loader/slaunch/slaunch.c

diff --git a/docs/grub.texi b/docs/grub.texi
index c0984e585..a2ae57cea 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -4118,6 +4118,7 @@ Modules can be loaded via the @command{insmod} 
(@pxref{insmod}) command.
 * sfs_module::
 * shift_test_module::
 * signature_test_module::
+* slaunch_module::
 * sleep_module::
 * sleep_test_module::
 * smbios_module::
@@ -5603,6 +5604,11 @@ operations in GRUB.
 This module is intended for performing a functional test of the digital
 signature verification functions in GRUB.
 
+@node slaunch_module
+@section slaunch
+This module provides support for Secure Launch boot in a form of three 
commands:
+@command{slaunch}, @command{slaunch_module} and @command{slaunch_state}.
+
 @node sleep_module
 @section sleep
 This module provides support for the @command{sleep} command to wait a 
specified
@@ -8426,6 +8432,9 @@ GRUB shell may provide more information on parameters and 
usage.
 @item @command{read_dword} - Read 32-bit value from ADDR.
 @item @command{read_word} - Read 16-bit value from ADDR.
 @item @command{setpci} - Manipulate PCI devices.
+@item @command{slaunch} - Enable secure launcher.
+@item @command{slaunch_module} - Load secure launcher module from file.
+@item @command{slaunch_state} - Display secure launcher state.
 @item @command{suspend} - Return to IEEE1275 prompt.
 @item @command{syslinux_configfile} - Execute syslinux config in new context
 @item @command{syslinux_source} - Execute syslinux config in same context
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 4bc2df614..327a8391b 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -1875,6 +1875,19 @@ module = {
   common = lib/cmdline.c;
 };
 
+module = {
+  name = slaunch;
+  x86 = loader/slaunch/slaunch.c;
+  x86 = loader/slaunch/slrt.c;
+  x86 = loader/slaunch/txt.c;
+  x86 = loader/slaunch/acmod.c;
+  x86 = loader/slaunch/verify.c;
+  x86 = loader/slaunch/i386_linux.c;
+  x86 = loader/slaunch/dlstub.c;
+  x86 = loader/efi/dltrampoline.S;
+  enable = x86;
+};
+
 module = {
   name = fdt;
   efi = loader/efi/fdt.c;
diff --git a/grub-core/lib/i386/relocator32.S b/grub-core/lib/i386/relocator32.S
index 09ce56ad0..25f162b0e 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/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..41d768418 100644
--- a/grub-core/loader/i386/bsd.c
+++ b/grub-core/loader/i386/bsd.c
@@ -792,6 +792,7 @@ grub_freebsd_boot (void)
 #endif
 
       grub_memcpy (&stack[9], &bi, sizeof (bi));
+      state.edi = 0; /* Secure Launch not in progress */
       state.eip = entry;
       state.esp = stack_target;
       state.ebp = stack_target;
@@ -907,6 +908,7 @@ grub_openbsd_boot (void)
     return err;
 #endif
 
+  state.edi = 0; /* Secure Launch not in progress */
   state.eip = entry;
   state.ebp = state.esp
     = ((grub_uint8_t *) stack - (grub_uint8_t *) buf0) + buf_target;
@@ -1229,6 +1231,7 @@ grub_netbsd_boot (void)
     return err;
 #endif
 
+  state.edi = 0; /* Secure Launch not in progress */
   state.eip = entry;
   state.esp = stack_target;
   state.ebp = stack_target;
diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c
index 26ed25427..2a74881fb 100644
--- a/grub-core/loader/i386/linux.c
+++ b/grub-core/loader/i386/linux.c
@@ -31,9 +31,13 @@
 #include <grub/video.h>
 #include <grub/video_fb.h>
 #include <grub/command.h>
+#include <grub/slr_table.h>
+#include <grub/slaunch.h>
 #include <grub/i386/relocator.h>
 #include <grub/i18n.h>
 #include <grub/lib/cmdline.h>
+#include <grub/i386/mmio.h>
+#include <grub/i386/txt.h>
 #include <grub/linux.h>
 #include <grub/machine/kernel.h>
 #include <grub/safemath.h>
@@ -69,6 +73,7 @@ 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;
@@ -82,6 +87,7 @@ static grub_efi_uintn_t efi_mmap_size;
 #else
 static const grub_size_t efi_mmap_size = 0;
 #endif
+static struct grub_slaunch_params slparams = {0};
 
 /* FIXME */
 #if 0
@@ -150,11 +156,25 @@ 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;
 
   if (prot_size == 0)
     prot_size = 1;
 
-  prot_size = page_align (prot_size);
+  if (grub_slaunch_platform_type () == SLP_INTEL_TXT)
+    {
+      err = grub_sl_txt_prepare_mle_ptab (&slparams, &prot_size, 
&preferred_address);
+      if (err)
+        goto fail;
+    }
+  else
+    {
+      prot_size = page_align (prot_size);
+      slparams.mle_ptab_size = 0;
+    }
+
+  total_size = prot_size + slparams.mle_ptab_size;
+
 
   /* Initialize the memory pointers with NULL for convenience.  */
   free_pages ();
@@ -176,15 +196,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,13 +214,21 @@ 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)
+    {
+      err = grub_sl_txt_setup_linux (&slparams, relocator, total_size, 
prot_size,
+                                     &prot_mode_mem, &prot_mode_target);
+      if (err)
+        goto fail;
+    }
+
   grub_dprintf ("linux", "prot_mode_mem = %p, prot_mode_target = %lx, 
prot_size = %x\n",
                 prot_mode_mem, (unsigned long) prot_mode_target,
                (unsigned) prot_size);
@@ -558,6 +586,12 @@ grub_linux_boot (void)
     if (err)
      return err;
     real_mode_mem = get_virtual_current_address (ch);
+
+    if (grub_slaunch_platform_type () != SLP_NONE)
+      {
+        slparams.boot_params = real_mode_mem;
+        slparams.boot_params_base = get_physical_target_address (ch);
+      }
   }
   efi_mmap_buf = (grub_uint8_t *) real_mode_mem + ctx.real_size;
 
@@ -587,6 +621,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)
@@ -624,6 +660,24 @@ grub_linux_boot (void)
   }
 #endif
 
+  if (grub_slaunch_platform_type () == SLP_INTEL_TXT)
+    {
+      struct grub_slr_table *slrt = (struct grub_slr_table 
*)slparams.slr_table_mem;
+      struct grub_slr_entry_dl_info *dlinfo;
+
+      slparams.platform_type = grub_slaunch_platform_type();
+
+      err = grub_txt_boot_prepare (&slparams);
+      if (err != GRUB_ERR_NONE)
+        return err;
+
+      dlinfo = grub_slr_next_entry_by_tag (slrt, NULL, GRUB_SLR_ENTRY_DL_INFO);
+      dl_entry ((grub_uint64_t)(grub_addr_t)&dlinfo->bl_context);
+
+      /* If this returns, something failed miserably */
+      return GRUB_ERR_BAD_DEVICE;
+    }
+
 #if defined (__x86_64__) && defined (GRUB_MACHINE_EFI)
   if (grub_le_to_cpu16 (ctx.params->version) >= 0x020c &&
       (linux_params.xloadflags & LINUX_X86_XLF_KERNEL_64) != 0)
@@ -642,6 +696,7 @@ grub_linux_boot (void)
   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,7 +717,7 @@ 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;
@@ -772,6 +827,19 @@ grub_cmd_linux (grub_command_t cmd __attribute__ 
((unused)),
       prot_init_space = page_align (prot_size) * 3;
     }
 
+  grub_dprintf ("linux", "before align=%d, min_align=%d\n",
+                (int)align, (int)min_align);
+
+  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);
+    }
+
+  grub_dprintf ("linux", "after align=%d, min_align=%d\n",
+                (int)align, (int)min_align);
+
   if (allocate_pages (prot_size, &align,
                      min_align, relocatable,
                      preferred_address))
@@ -779,6 +847,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 +876,10 @@ grub_cmd_linux (grub_command_t cmd __attribute__ 
((unused)),
       goto fail;
     }
 
+  /* Read the kernel_info struct. */
+  if (grub_sl_find_kernel_info (&slparams, file, &lh, real_size))
+    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/xnu.c b/grub-core/loader/i386/xnu.c
index b91e2f840..b04c1931d 100644
--- a/grub-core/loader/i386/xnu.c
+++ b/grub-core/loader/i386/xnu.c
@@ -802,6 +802,7 @@ grub_xnu_boot_resume (void)
 {
   struct grub_relocator32_state state = {0};
 
+  state.edi = 0; /* Secure Launch not in progress */
   state.esp = grub_xnu_stack;
   state.ebp = grub_xnu_stack;
   state.eip = grub_xnu_entry_point;
@@ -1129,6 +1130,7 @@ grub_xnu_boot (void)
   grub_autoefi_set_virtual_address_map (memory_map_size, descriptor_size,
                                        descriptor_version, memory_map);
 
+  state.edi = 0; /* Secure Launch not in progress */
   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 36b27a906..ec29f1b58 100644
--- a/grub-core/loader/multiboot.c
+++ b/grub-core/loader/multiboot.c
@@ -161,6 +161,8 @@ efi_boot (struct grub_relocator *rel __attribute__ 
((unused)),
 static void
 normal_boot (struct grub_relocator *rel, struct grub_relocator32_state state)
 {
+  state.edi = 0; /* Secure Launch not in progress */
+
   grub_relocator32_boot (rel, state, 0);
 }
 #else
diff --git a/grub-core/loader/slaunch/i386_linux.c 
b/grub-core/loader/slaunch/i386_linux.c
new file mode 100644
index 000000000..770888f63
--- /dev/null
+++ b/grub-core/loader/slaunch/i386_linux.c
@@ -0,0 +1,220 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2024, 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/slaunch.h>
+#include <grub/cpu/relocator.h>
+#include <grub/i386/msr.h>
+#include <grub/i386/mmio.h>
+#include <grub/i386/linux.h>
+#include <grub/i386/txt.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+#define OFFSET_OF(x, y) ((grub_size_t)((grub_uint8_t *)(&(y)->x) - 
(grub_uint8_t *)(y)))
+
+grub_err_t
+grub_sl_find_kernel_info (struct grub_slaunch_params *slparams, grub_file_t 
kernel_file,
+                          struct linux_i386_kernel_header *lh, grub_size_t 
real_size)
+
+{
+  struct linux_kernel_info *linux_info;
+
+  /* Not a Secure Launch, do nothing */
+  if (grub_slaunch_platform_type () == SLP_NONE)
+    return GRUB_ERR_NONE;
+
+  if (grub_le_to_cpu16 (lh->version) < 0x020f)
+    {
+      grub_error (GRUB_ERR_BAD_OS, N_("not slaunch kernel: boot protocol too 
old"));
+      goto fail;
+    }
+
+
+  if (grub_file_seek (kernel_file, grub_le_to_cpu32 (lh->kernel_info_offset) +
+                      real_size + GRUB_DISK_SECTOR_SIZE) == ((grub_off_t) -1))
+    goto fail;
+
+  linux_info = grub_malloc (GRUB_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 (kernel_file, linux_info,
+                      GRUB_KERNEL_INFO_MIN_SIZE_TOTAL) != 
GRUB_KERNEL_INFO_MIN_SIZE_TOTAL)
+    {
+      if (!grub_errno)
+        grub_error (GRUB_ERR_BAD_OS, N_("premature end of kernel file"));
+      goto fail;
+    }
+
+  if (grub_memcmp (&linux_info->header, GRUB_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);
+
+  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 (kernel_file, &linux_info->setup_type_max,
+                      linux_info->size_total - 
GRUB_KERNEL_INFO_MIN_SIZE_TOTAL) !=
+                      (grub_ssize_t)(linux_info->size_total - 
GRUB_KERNEL_INFO_MIN_SIZE_TOTAL))
+    {
+      if (!grub_errno)
+        grub_error (GRUB_ERR_BAD_OS, N_("premature end of kernel file"));
+      goto fail;
+    }
+
+  /* Fetch the MLE header offset so Secure Launch can locate it */
+  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);
+
+  return GRUB_ERR_NONE;
+
+fail:
+  return grub_errno;
+}
+
+grub_err_t
+grub_sl_txt_prepare_mle_ptab (struct grub_slaunch_params *slparams, 
grub_size_t *prot_size,
+                              grub_uint64_t *preferred_address)
+{
+  *prot_size = ALIGN_UP (*prot_size, GRUB_TXT_PMR_ALIGN);
+
+  if (*prot_size > GRUB_TXT_MLE_MAX_SIZE)
+    {
+      grub_error (GRUB_ERR_OUT_OF_RANGE,
+                  N_("slaunch kernel: protected size out of range"));
+      return GRUB_ERR_OUT_OF_RANGE;
+    }
+
+  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);
+
+  return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_sl_txt_setup_linux (struct grub_slaunch_params *slparams, struct 
grub_relocator *relocator,
+                         grub_size_t total_size, grub_size_t prot_size,
+                         void **prot_mode_mem, grub_addr_t *prot_mode_target)
+{
+  grub_relocator_chunk_t ch;
+
+  slparams->boot_type = GRUB_SL_BOOT_TYPE_LINUX;
+  slparams->relocator = relocator;
+
+  /* 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_mem = *prot_mode_mem;
+  slparams->mle_start = *prot_mode_target;
+  slparams->mle_size = prot_size;
+
+  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);
+
+  if (grub_relocator_alloc_chunk_align (relocator, &ch, 0x1000000,
+                                        0xffffffff - GRUB_PAGE_SIZE,
+                                        GRUB_PAGE_SIZE, GRUB_PAGE_SIZE,
+                                        GRUB_RELOCATOR_PREFERENCE_NONE, 1))
+    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);
+
+  if (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))
+    goto fail;
+
+  slparams->tpm_evt_log_base = get_physical_target_address (ch);
+  slparams->tpm_evt_log_size = GRUB_SLAUNCH_TPM_EVT_LOG_SIZE;
+
+  grub_memset (get_virtual_current_address (ch), 0, 
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);
+
+  return GRUB_ERR_NONE;
+
+fail:
+  return grub_errno;
+}
diff --git a/grub-core/loader/slaunch/slaunch.c 
b/grub-core/loader/slaunch/slaunch.c
new file mode 100644
index 000000000..8079bae7a
--- /dev/null
+++ b/grub-core/loader/slaunch/slaunch.c
@@ -0,0 +1,204 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2024, 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/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/slaunch.h>
+#include <grub/i386/cpuid.h>
+#include <grub/i386/msr.h>
+#include <grub/i386/mmio.h>
+#include <grub/i386/txt.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static grub_uint32_t slp = SLP_NONE;
+
+static void *slaunch_module = NULL;
+
+grub_uint32_t
+grub_slaunch_platform_type (void)
+{
+  return slp;
+}
+
+void *
+grub_slaunch_module (void)
+{
+  return slaunch_module;
+}
+
+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 ();
+    }
+
+  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/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 ace28f8c2..0de9eccfc 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;
+  grub_uint32_t size_total;
+  grub_uint32_t setup_type_max;
+  grub_uint32_t mle_header_offset;
+  grub_uint8_t  var_len_data[0];
 } GRUB_PACKED;
 
 /* Boot parameters for Linux based on 2.6.12. This is used by the setup
@@ -339,9 +350,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;
diff --git a/include/grub/slaunch.h b/include/grub/slaunch.h
index ba6516981..061d8e439 100644
--- a/include/grub/slaunch.h
+++ b/include/grub/slaunch.h
@@ -33,6 +33,9 @@
 #define GRUB_SL_BOOT_TYPE_LINUX                1
 #define GRUB_SL_BOOT_TYPE_EFI          2
 
+#define GRUB_KERNEL_INFO_HEADER                "LToP"
+#define GRUB_KERNEL_INFO_MIN_SIZE_TOTAL        12
+
 struct linux_kernel_params;
 struct linux_i386_kernel_header;
 struct grub_relocator;
@@ -91,6 +94,18 @@ void grub_setup_slr_table (struct grub_slaunch_params 
*slparams,
                            struct grub_slr_entry_hdr *platform_info);
 void grub_update_slrt_policy (struct grub_slaunch_params *slparams);
 
+/* Linux i386 functions */
+grub_err_t grub_sl_find_kernel_info (struct grub_slaunch_params *slparams,
+                                     grub_file_t kernel_file,
+                                     struct linux_i386_kernel_header *lh,
+                                     grub_size_t real_size);
+grub_err_t grub_sl_txt_prepare_mle_ptab (struct grub_slaunch_params *slparams,
+                                         grub_size_t *prot_size,
+                                         grub_uint64_t *preferred_address);
+grub_err_t grub_sl_txt_setup_linux (struct grub_slaunch_params *slparams,
+                                    struct grub_relocator *relocator,
+                                    grub_size_t total_size, grub_size_t 
prot_size,
+                                    void **prot_mode_mem, grub_addr_t 
*prot_mode_target);
 #endif /* ASM_FILE */
 
 #endif /* GRUB_I386_SLAUNCH_H */
-- 
2.47.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]