Skip to content

Commit

Permalink
x86/boot: Move mem_encrypt= parsing to the decompressor
Browse files Browse the repository at this point in the history
commit cd0d9d9 upstream.

The early SME/SEV code parses the command line very early, in order to
decide whether or not memory encryption should be enabled, which needs
to occur even before the initial page tables are created.

This is problematic for a number of reasons:
- this early code runs from the 1:1 mapping provided by the decompressor
  or firmware, which uses a different translation than the one assumed by
  the linker, and so the code needs to be built in a special way;
- parsing external input while the entire kernel image is still mapped
  writable is a bad idea in general, and really does not belong in
  security minded code;
- the current code ignores the built-in command line entirely (although
  this appears to be the case for the entire decompressor)

Given that the decompressor/EFI stub is an intrinsic part of the x86
bootable kernel image, move the command line parsing there and out of
the core kernel. This removes the need to build lib/cmdline.o in a
special way, or to use RIP-relative LEA instructions in inline asm
blocks.

This involves a new xloadflag in the setup header to indicate
that mem_encrypt=on appeared on the kernel command line.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Tested-by: Tom Lendacky <thomas.lendacky@amd.com>
Link: https://lore.kernel.org/r/20240227151907.387873-17-ardb+git@google.com
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
ardbiesheuvel authored and gregkh committed Apr 10, 2024
1 parent 7596a37 commit 2ff01ae
Show file tree
Hide file tree
Showing 5 changed files with 22 additions and 42 deletions.
15 changes: 15 additions & 0 deletions arch/x86/boot/compressed/misc.c
Expand Up @@ -357,6 +357,19 @@ unsigned long decompress_kernel(unsigned char *outbuf, unsigned long virt_addr,
return entry;
}

/*
* Set the memory encryption xloadflag based on the mem_encrypt= command line
* parameter, if provided.
*/
static void parse_mem_encrypt(struct setup_header *hdr)
{
int on = cmdline_find_option_bool("mem_encrypt=on");
int off = cmdline_find_option_bool("mem_encrypt=off");

if (on > off)
hdr->xloadflags |= XLF_MEM_ENCRYPTION;
}

/*
* 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
Expand Down Expand Up @@ -387,6 +400,8 @@ asmlinkage __visible void *extract_kernel(void *rmode, unsigned char *output)
/* Clear flags intended for solely in-kernel use. */
boot_params_ptr->hdr.loadflags &= ~KASLR_FLAG;

parse_mem_encrypt(&boot_params_ptr->hdr);

sanitize_boot_params(boot_params_ptr);

if (boot_params_ptr->screen_info.orig_video_mode == 7) {
Expand Down
1 change: 1 addition & 0 deletions arch/x86/include/uapi/asm/bootparam.h
Expand Up @@ -38,6 +38,7 @@
#define XLF_EFI_KEXEC (1<<4)
#define XLF_5LEVEL (1<<5)
#define XLF_5LEVEL_ENABLED (1<<6)
#define XLF_MEM_ENCRYPTION (1<<7)

#ifndef __ASSEMBLY__

Expand Down
13 changes: 0 additions & 13 deletions arch/x86/lib/Makefile
Expand Up @@ -14,19 +14,6 @@ ifdef CONFIG_KCSAN
CFLAGS_REMOVE_delay.o = $(CC_FLAGS_FTRACE)
endif

# Early boot use of cmdline; don't instrument it
ifdef CONFIG_AMD_MEM_ENCRYPT
KCOV_INSTRUMENT_cmdline.o := n
KASAN_SANITIZE_cmdline.o := n
KCSAN_SANITIZE_cmdline.o := n

ifdef CONFIG_FUNCTION_TRACER
CFLAGS_REMOVE_cmdline.o = -pg
endif

CFLAGS_cmdline.o := -fno-stack-protector -fno-jump-tables
endif

inat_tables_script = $(srctree)/arch/x86/tools/gen-insn-attr-x86.awk
inat_tables_maps = $(srctree)/arch/x86/lib/x86-opcode-map.txt
quiet_cmd_inat_tables = GEN $@
Expand Down
32 changes: 3 additions & 29 deletions arch/x86/mm/mem_encrypt_identity.c
Expand Up @@ -43,7 +43,6 @@

#include <asm/setup.h>
#include <asm/sections.h>
#include <asm/cmdline.h>
#include <asm/coco.h>
#include <asm/sev.h>

Expand Down Expand Up @@ -95,9 +94,6 @@ struct sme_populate_pgd_data {
*/
static char sme_workarea[2 * PMD_SIZE] __section(".init.scratch");

static char sme_cmdline_arg[] __initdata = "mem_encrypt";
static char sme_cmdline_on[] __initdata = "on";

static void __init sme_clear_pgd(struct sme_populate_pgd_data *ppd)
{
unsigned long pgd_start, pgd_end, pgd_size;
Expand Down Expand Up @@ -504,11 +500,9 @@ void __init sme_encrypt_kernel(struct boot_params *bp)

void __init sme_enable(struct boot_params *bp)
{
const char *cmdline_ptr, *cmdline_arg, *cmdline_on;
unsigned int eax, ebx, ecx, edx;
unsigned long feature_mask;
unsigned long me_mask;
char buffer[16];
bool snp;
u64 msr;

Expand Down Expand Up @@ -551,6 +545,9 @@ void __init sme_enable(struct boot_params *bp)

/* Check if memory encryption is enabled */
if (feature_mask == AMD_SME_BIT) {
if (!(bp->hdr.xloadflags & XLF_MEM_ENCRYPTION))
return;

/*
* No SME if Hypervisor bit is set. This check is here to
* prevent a guest from trying to enable SME. For running as a
Expand All @@ -570,31 +567,8 @@ void __init sme_enable(struct boot_params *bp)
msr = __rdmsr(MSR_AMD64_SYSCFG);
if (!(msr & MSR_AMD64_SYSCFG_MEM_ENCRYPT))
return;
} else {
/* SEV state cannot be controlled by a command line option */
goto out;
}

/*
* Fixups have not been applied to phys_base yet and we're running
* identity mapped, so we must obtain the address to the SME command
* line argument data using rip-relative addressing.
*/
asm ("lea sme_cmdline_arg(%%rip), %0"
: "=r" (cmdline_arg)
: "p" (sme_cmdline_arg));
asm ("lea sme_cmdline_on(%%rip), %0"
: "=r" (cmdline_on)
: "p" (sme_cmdline_on));

cmdline_ptr = (const char *)((u64)bp->hdr.cmd_line_ptr |
((u64)bp->ext_cmd_line_ptr << 32));

if (cmdline_find_option(cmdline_ptr, cmdline_arg, buffer, sizeof(buffer)) < 0 ||
strncmp(buffer, cmdline_on, sizeof(buffer)))
return;

out:
RIP_REL_REF(sme_me_mask) = me_mask;
physical_mask &= ~me_mask;
cc_vendor = CC_VENDOR_AMD;
Expand Down
3 changes: 3 additions & 0 deletions drivers/firmware/efi/libstub/x86-stub.c
Expand Up @@ -890,6 +890,9 @@ void __noreturn efi_stub_entry(efi_handle_t handle,
}
}

if (efi_mem_encrypt > 0)
hdr->xloadflags |= XLF_MEM_ENCRYPTION;

status = efi_decompress_kernel(&kernel_entry);
if (status != EFI_SUCCESS) {
efi_err("Failed to decompress kernel\n");
Expand Down

0 comments on commit 2ff01ae

Please sign in to comment.