From: Ard Biesheuvel <[email protected]>

Implement Secure Launch D-RTM of the decompressed kernel via a
callback interface exposed by the Secure Launch Resource Table (SLRT), a
reference to which is added to struct boot_params.

This permits a boot loader to set up the Secure Launch, allow the
decompressor to execute up to the point where it would otherwise boot the
core kernel, and at that point, perform the Dynamic Launch Event in a
architecture/vendor specific manner. This is similar to how EFI boot
achieves this, using a EFI protocol exposed by the boot loader.

This requires that the decompressor unpacks the kernel into the buffer that
it was started from itself, and so physical KASLR needs to be omitted
(although the boot loader is free to place the decompressor at any
suitably aligned locations in system memory, and so it can perform the
physical randomization itself).

It also relies on the demand paging logic in the decompressor, to ensure
that the SLRT and the entry point it describes are callable, at least to
the extent that allows the callback code to re-establish its own
execution environment.

Co-developed-by: Ross Philipson <[email protected]>
Signed-off-by: Ard Biesheuvel <[email protected]>
Signed-off-by: Ross Philipson <[email protected]>
---
 Documentation/arch/x86/zero-page.rst  |  1 +
 arch/x86/boot/compressed/misc.c       | 51 ++++++++++++++++++++++++---
 arch/x86/boot/compressed/pgtable_64.c |  7 ++++
 arch/x86/include/uapi/asm/bootparam.h |  2 +-
 4 files changed, 56 insertions(+), 5 deletions(-)

diff --git a/Documentation/arch/x86/zero-page.rst 
b/Documentation/arch/x86/zero-page.rst
index 45aa9cceb4f1..dd98b467929c 100644
--- a/Documentation/arch/x86/zero-page.rst
+++ b/Documentation/arch/x86/zero-page.rst
@@ -20,6 +20,7 @@ Offset/Size   Proto   Name                    Meaning
 060/010                ALL     ist_info                Intel SpeedStep (IST) 
BIOS support information
                                                (struct ist_info)
 070/008                ALL     acpi_rsdp_addr          Physical address of 
ACPI RSDP table
+078/008                ALL     slr_table_addr          Physical address of 
Secure Launch Resource Table
 080/010                ALL     hd0_info                hd0 disk parameter, 
OBSOLETE!!
 090/010                ALL     hd1_info                hd1 disk parameter, 
OBSOLETE!!
 0A0/010                ALL     sys_desc_table          System description 
table (struct sys_desc_table),
diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c
index e3b5177bfa6f..eaaface4cd7d 100644
--- a/arch/x86/boot/compressed/misc.c
+++ b/arch/x86/boot/compressed/misc.c
@@ -17,6 +17,7 @@
 #include "../string.h"
 #include "../voffset.h"
 #include <asm/bootparam_utils.h>
+#include <linux/slr_table.h>
 
 /*
  * WARNING!!
@@ -391,6 +392,36 @@ static void early_sev_detect(void)
                lines = cols = 0;
 }
 
+#ifdef CONFIG_SECURE_LAUNCH
+static void sl_initiate_launch(unsigned long table, unsigned long base)
+{
+       struct slr_table *slrt = (void *)table;
+       struct slr_entry_dl_info *dl_info;
+       struct slr_setup_dlme dlme;
+       dl_launch_func launch_fn;
+
+       dlme.dlme_base = base;
+       dlme.dlme_header_offset = mle_header_offset;
+       dlme.dlme_table = 0;
+
+       if (!slrt)
+               return;
+
+       dl_info = slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_DL_INFO);
+       if (!dl_info)
+               return;
+
+       launch_fn = (void *)dl_info->dl_launch;
+
+       /* Do the Dynamic Launch Event */
+       launch_fn(&dl_info->bl_context, &dlme);
+}
+#else
+static inline void sl_initiate_launch(unsigned long table, unsigned long base)
+{
+}
+#endif
+
 /*
  * The compressed kernel image (ZO), has been moved so that its position
  * is against the end of the buffer used to hold the uncompressed kernel
@@ -491,10 +522,15 @@ asmlinkage __visible void *extract_kernel(void *rmode, 
unsigned char *output)
        debug_putaddr(trampoline_32bit);
 #endif
 
-       choose_random_location((unsigned long)input_data, input_len,
-                               (unsigned long *)&output,
-                               needed_size,
-                               &virt_addr);
+       /*
+        * When doing a secure launch, the actual launch will be initiated by
+        * jumping back to the bootloader. Omit physical KASLR in that case, to
+        * avoid trampling on its code or data inadvertently.
+        */
+       if (!boot_params_ptr->slr_table_addr)
+               choose_random_location((unsigned long)input_data, input_len,
+                                      (unsigned long *)&output,
+                                      needed_size, &virt_addr);
 
        /* Validate memory location choices. */
        if ((unsigned long)output & (MIN_KERNEL_ALIGN - 1))
@@ -528,6 +564,13 @@ asmlinkage __visible void *extract_kernel(void *rmode, 
unsigned char *output)
        debug_puthex(entry_offset);
        debug_putstr(").\n");
 
+       /*
+        * Secure Launch involves calling back into the bootloader, so this
+        * needs to happen before disabling exception handling, to ensure that
+        * the entry point will be mapped on demand if needed.
+        */
+       sl_initiate_launch(boot_params_ptr->slr_table_addr, (unsigned 
long)output);
+
        /* Disable exception handling before booting the kernel */
        cleanup_exception_handling();
 
diff --git a/arch/x86/boot/compressed/pgtable_64.c 
b/arch/x86/boot/compressed/pgtable_64.c
index 3e9d651da73e..f82094669ac0 100644
--- a/arch/x86/boot/compressed/pgtable_64.c
+++ b/arch/x86/boot/compressed/pgtable_64.c
@@ -124,6 +124,13 @@ asmlinkage void configure_5level_paging(struct boot_params 
*bp, void *pgtable)
 
        l5_required = !cmdline_find_option_bool("no5lvl");
 
+       /*
+        * Don't change the number of levels when doing a Secure Launch. The
+        * Secure Launch stub will take care of that if needed.
+        */
+       if (bp->slr_table_addr)
+               l5_required = l5_enabled;
+
        if (l5_required) {
                /* Initialize variables for 5-level paging */
                __pgtable_l5_enabled = 1;
diff --git a/arch/x86/include/uapi/asm/bootparam.h 
b/arch/x86/include/uapi/asm/bootparam.h
index 8155fa899f50..bc2ef37096af 100644
--- a/arch/x86/include/uapi/asm/bootparam.h
+++ b/arch/x86/include/uapi/asm/bootparam.h
@@ -121,7 +121,7 @@ struct boot_params {
        __u64  tboot_addr;                              /* 0x058 */
        struct ist_info ist_info;                       /* 0x060 */
        __u64 acpi_rsdp_addr;                           /* 0x070 */
-       __u8  _pad3[8];                                 /* 0x078 */
+       __u64 slr_table_addr;                           /* 0x078 */
        __u8  hd0_info[16];     /* obsolete! */         /* 0x080 */
        __u8  hd1_info[16];     /* obsolete! */         /* 0x090 */
        struct sys_desc_table sys_desc_table; /* obsolete! */   /* 0x0a0 */
-- 
2.47.3


Reply via email to