Skip to content

Commit 424478a

Browse files
kerneltoastPlaidCat
authored andcommitted
x86/sev: Harden #VC instruction emulation somewhat
jira VULN-751 cve CVE-2024-25742 commit-author Borislav Petkov (AMD) <[email protected]> commit e3ef461 upstream-diff Conflicts are just a matter of placing the code correctly in this older version of the driver, no compatibility issues. Compare the opcode bytes at rIP for each #VC exit reason to verify the instruction which raised the #VC exception is actually the right one. Signed-off-by: Borislav Petkov (AMD) <[email protected]> Acked-by: Tom Lendacky <[email protected]> Link: https://lore.kernel.org/r/[email protected] (cherry picked from commit e3ef461) Signed-off-by: Sultan Alsawaf <[email protected]> # Conflicts: # arch/x86/kernel/sev-shared.c
1 parent 2195729 commit 424478a

File tree

3 files changed

+109
-3
lines changed

3 files changed

+109
-3
lines changed

arch/x86/boot/compressed/sev.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,10 @@ void do_boot_stage2_vc(struct pt_regs *regs, unsigned long exit_code)
183183
if (result != ES_OK)
184184
goto finish;
185185

186+
result = vc_check_opcode_bytes(&ctxt, exit_code);
187+
if (result != ES_OK)
188+
goto finish;
189+
186190
switch (exit_code) {
187191
case SVM_EXIT_RDTSC:
188192
case SVM_EXIT_RDTSCP:

arch/x86/kernel/sev-shared.c

Lines changed: 101 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,13 @@
1010
*/
1111

1212
#ifndef __BOOT_COMPRESSED
13-
#define error(v) pr_err(v)
14-
#define has_cpuflag(f) boot_cpu_has(f)
13+
#define error(v) pr_err(v)
14+
#define has_cpuflag(f) boot_cpu_has(f)
15+
#define sev_printk(fmt, ...) printk(fmt, ##__VA_ARGS__)
16+
#define sev_printk_rtl(fmt, ...) printk_ratelimited(fmt, ##__VA_ARGS__)
17+
#else
18+
#define sev_printk(fmt, ...)
19+
#define sev_printk_rtl(fmt, ...)
1520
#endif
1621

1722
static bool __init sev_es_check_cpu_features(void)
@@ -144,12 +149,17 @@ static enum es_result sev_es_ghcb_hv_call(struct ghcb *ghcb,
144149
void __init do_vc_no_ghcb(struct pt_regs *regs, unsigned long exit_code)
145150
{
146151
unsigned int fn = lower_bits(regs->ax, 32);
152+
u16 opcode = *(unsigned short *)regs->ip;
147153
unsigned long val;
148154

149155
/* Only CPUID is supported via MSR protocol */
150156
if (exit_code != SVM_EXIT_CPUID)
151157
goto fail;
152158

159+
/* Is it really a CPUID insn? */
160+
if (opcode != 0xa20f)
161+
goto fail;
162+
153163
sev_es_wr_ghcb_msr(GHCB_CPUID_REQ(fn, GHCB_CPUID_REQ_EAX));
154164
VMGEXIT();
155165
val = sev_es_rd_ghcb_msr();
@@ -527,3 +537,92 @@ static enum es_result vc_handle_rdtsc(struct ghcb *ghcb,
527537

528538
return ES_OK;
529539
}
540+
541+
static enum es_result vc_check_opcode_bytes(struct es_em_ctxt *ctxt,
542+
unsigned long exit_code)
543+
{
544+
unsigned int opcode = (unsigned int)ctxt->insn.opcode.value;
545+
u8 modrm = ctxt->insn.modrm.value;
546+
547+
switch (exit_code) {
548+
549+
case SVM_EXIT_IOIO:
550+
case SVM_EXIT_NPF:
551+
/* handled separately */
552+
return ES_OK;
553+
554+
case SVM_EXIT_CPUID:
555+
if (opcode == 0xa20f)
556+
return ES_OK;
557+
break;
558+
559+
case SVM_EXIT_INVD:
560+
if (opcode == 0x080f)
561+
return ES_OK;
562+
break;
563+
564+
case SVM_EXIT_MONITOR:
565+
if (opcode == 0x010f && modrm == 0xc8)
566+
return ES_OK;
567+
break;
568+
569+
case SVM_EXIT_MWAIT:
570+
if (opcode == 0x010f && modrm == 0xc9)
571+
return ES_OK;
572+
break;
573+
574+
case SVM_EXIT_MSR:
575+
/* RDMSR */
576+
if (opcode == 0x320f ||
577+
/* WRMSR */
578+
opcode == 0x300f)
579+
return ES_OK;
580+
break;
581+
582+
case SVM_EXIT_RDPMC:
583+
if (opcode == 0x330f)
584+
return ES_OK;
585+
break;
586+
587+
case SVM_EXIT_RDTSC:
588+
if (opcode == 0x310f)
589+
return ES_OK;
590+
break;
591+
592+
case SVM_EXIT_RDTSCP:
593+
if (opcode == 0x010f && modrm == 0xf9)
594+
return ES_OK;
595+
break;
596+
597+
case SVM_EXIT_READ_DR7:
598+
if (opcode == 0x210f &&
599+
X86_MODRM_REG(ctxt->insn.modrm.value) == 7)
600+
return ES_OK;
601+
break;
602+
603+
case SVM_EXIT_VMMCALL:
604+
if (opcode == 0x010f && modrm == 0xd9)
605+
return ES_OK;
606+
607+
break;
608+
609+
case SVM_EXIT_WRITE_DR7:
610+
if (opcode == 0x230f &&
611+
X86_MODRM_REG(ctxt->insn.modrm.value) == 7)
612+
return ES_OK;
613+
break;
614+
615+
case SVM_EXIT_WBINVD:
616+
if (opcode == 0x90f)
617+
return ES_OK;
618+
break;
619+
620+
default:
621+
break;
622+
}
623+
624+
sev_printk(KERN_ERR "Wrong/unhandled opcode bytes: 0x%x, exit_code: 0x%lx, rIP: 0x%lx\n",
625+
opcode, exit_code, ctxt->regs->ip);
626+
627+
return ES_UNSUPPORTED;
628+
}

arch/x86/kernel/sev.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1155,7 +1155,10 @@ static enum es_result vc_handle_exitcode(struct es_em_ctxt *ctxt,
11551155
struct ghcb *ghcb,
11561156
unsigned long exit_code)
11571157
{
1158-
enum es_result result;
1158+
enum es_result result = vc_check_opcode_bytes(ctxt, exit_code);
1159+
1160+
if (result != ES_OK)
1161+
return result;
11591162

11601163
switch (exit_code) {
11611164
case SVM_EXIT_READ_DR7:

0 commit comments

Comments
 (0)