Commit 43c83418 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'x86_seves_for_v5.10_rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull x86 SEV-ES fixes from Borislav Petkov:
 "A couple of changes to the SEV-ES code to perform more stringent
  hypervisor checks before enabling encryption (Joerg Roedel)"

* tag 'x86_seves_for_v5.10_rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/sev-es: Do not support MMIO to/from encrypted memory
  x86/head/64: Check SEV encryption before switching to kernel page-table
  x86/boot/compressed/64: Check SEV encryption in 64-bit boot-path
  x86/boot/compressed/64: Sanity-check CPUID results in the early #VC handler
  x86/boot/compressed/64: Introduce sev_status
parents f4c79144 2411cd82
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -164,6 +164,7 @@ void initialize_identity_maps(void *rmode)
	add_identity_map(cmdline, cmdline + COMMAND_LINE_SIZE);

	/* Load the new page-table. */
	sev_verify_cbit(top_level_pgt);
	write_cr3(top_level_pgt);
}

+19 −1
Original line number Diff line number Diff line
@@ -68,6 +68,9 @@ SYM_FUNC_START(get_sev_encryption_bit)
SYM_FUNC_END(get_sev_encryption_bit)

	.code64

#include "../../kernel/sev_verify_cbit.S"

SYM_FUNC_START(set_sev_encryption_mask)
#ifdef CONFIG_AMD_MEM_ENCRYPT
	push	%rbp
@@ -81,6 +84,19 @@ SYM_FUNC_START(set_sev_encryption_mask)

	bts	%rax, sme_me_mask(%rip)	/* Create the encryption mask */

	/*
	 * Read MSR_AMD64_SEV again and store it to sev_status. Can't do this in
	 * get_sev_encryption_bit() because this function is 32-bit code and
	 * shared between 64-bit and 32-bit boot path.
	 */
	movl	$MSR_AMD64_SEV, %ecx	/* Read the SEV MSR */
	rdmsr

	/* Store MSR value in sev_status */
	shlq	$32, %rdx
	orq	%rdx, %rax
	movq	%rax, sev_status(%rip)

.Lno_sev_mask:
	movq	%rbp, %rsp		/* Restore original stack pointer */

@@ -97,4 +113,6 @@ SYM_FUNC_END(set_sev_encryption_mask)
#ifdef CONFIG_AMD_MEM_ENCRYPT
	.balign	8
SYM_DATA(sme_me_mask,		.quad 0)
SYM_DATA(sev_status,		.quad 0)
SYM_DATA(sev_check_data,	.quad 0)
#endif
+2 −0
Original line number Diff line number Diff line
@@ -159,4 +159,6 @@ void boot_page_fault(void);
void boot_stage1_vc(void);
void boot_stage2_vc(void);

unsigned long sev_verify_cbit(unsigned long cr3);

#endif /* BOOT_COMPRESSED_MISC_H */
+16 −0
Original line number Diff line number Diff line
@@ -161,6 +161,21 @@ SYM_INNER_LABEL(secondary_startup_64_no_verify, SYM_L_GLOBAL)

	/* Setup early boot stage 4-/5-level pagetables. */
	addq	phys_base(%rip), %rax

	/*
	 * For SEV guests: Verify that the C-bit is correct. A malicious
	 * hypervisor could lie about the C-bit position to perform a ROP
	 * attack on the guest by writing to the unencrypted stack and wait for
	 * the next RET instruction.
	 * %rsi carries pointer to realmode data and is callee-clobbered. Save
	 * and restore it.
	 */
	pushq	%rsi
	movq	%rax, %rdi
	call	sev_verify_cbit
	popq	%rsi

	/* Switch to new page-table */
	movq	%rax, %cr3

	/* Ensure I am executing from virtual addresses */
@@ -279,6 +294,7 @@ SYM_INNER_LABEL(secondary_startup_64_no_verify, SYM_L_GLOBAL)
SYM_CODE_END(secondary_startup_64)

#include "verify_cpu.S"
#include "sev_verify_cbit.S"

#ifdef CONFIG_HOTPLUG_CPU
/*
+26 −0
Original line number Diff line number Diff line
@@ -178,6 +178,32 @@ void __init do_vc_no_ghcb(struct pt_regs *regs, unsigned long exit_code)
		goto fail;
	regs->dx = val >> 32;

	/*
	 * This is a VC handler and the #VC is only raised when SEV-ES is
	 * active, which means SEV must be active too. Do sanity checks on the
	 * CPUID results to make sure the hypervisor does not trick the kernel
	 * into the no-sev path. This could map sensitive data unencrypted and
	 * make it accessible to the hypervisor.
	 *
	 * In particular, check for:
	 *	- Hypervisor CPUID bit
	 *	- Availability of CPUID leaf 0x8000001f
	 *	- SEV CPUID bit.
	 *
	 * The hypervisor might still report the wrong C-bit position, but this
	 * can't be checked here.
	 */

	if ((fn == 1 && !(regs->cx & BIT(31))))
		/* Hypervisor bit */
		goto fail;
	else if (fn == 0x80000000 && (regs->ax < 0x8000001f))
		/* SEV leaf check */
		goto fail;
	else if ((fn == 0x8000001f && !(regs->ax & BIT(1))))
		/* SEV bit */
		goto fail;

	/* Skip over the CPUID two-byte opcode */
	regs->ip += 2;

Loading