Skip to content

Commit 30b7655

Browse files
bp3tk0vpvts-mat
authored andcommitted
x86/sev: Harden #VC instruction emulation somewhat
jira VULN-756 cve CVE-2024-25742 commit-author Borislav Petkov (AMD) <[email protected]> commit e3ef461 upstream-diff Added `#else' case for the `#ifndef __BOOT_COMPRESSED' which was modified in upstream but not present in `ciqlts9_2'. 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]
1 parent 31adcfc commit 30b7655

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
@@ -227,6 +227,10 @@ void do_boot_stage2_vc(struct pt_regs *regs, unsigned long exit_code)
227227
if (result != ES_OK)
228228
goto finish;
229229

230+
result = vc_check_opcode_bytes(&ctxt, exit_code);
231+
if (result != ES_OK)
232+
goto finish;
233+
230234
switch (exit_code) {
231235
case SVM_EXIT_RDTSC:
232236
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
/* I/O parameters for CPUID-related helpers */
@@ -531,13 +536,18 @@ void __init do_vc_no_ghcb(struct pt_regs *regs, unsigned long exit_code)
531536
{
532537
unsigned int subfn = lower_bits(regs->cx, 32);
533538
unsigned int fn = lower_bits(regs->ax, 32);
539+
u16 opcode = *(unsigned short *)regs->ip;
534540
struct cpuid_leaf leaf;
535541
int ret;
536542

537543
/* Only CPUID is supported via MSR protocol */
538544
if (exit_code != SVM_EXIT_CPUID)
539545
goto fail;
540546

547+
/* Is it really a CPUID insn? */
548+
if (opcode != 0xa20f)
549+
goto fail;
550+
541551
leaf.fn = fn;
542552
leaf.subfn = subfn;
543553

@@ -991,3 +1001,92 @@ static void __init setup_cpuid_table(const struct cc_blob_sev_info *cc_info)
9911001
cpuid_ext_range_max = fn->eax;
9921002
}
9931003
}
1004+
1005+
static enum es_result vc_check_opcode_bytes(struct es_em_ctxt *ctxt,
1006+
unsigned long exit_code)
1007+
{
1008+
unsigned int opcode = (unsigned int)ctxt->insn.opcode.value;
1009+
u8 modrm = ctxt->insn.modrm.value;
1010+
1011+
switch (exit_code) {
1012+
1013+
case SVM_EXIT_IOIO:
1014+
case SVM_EXIT_NPF:
1015+
/* handled separately */
1016+
return ES_OK;
1017+
1018+
case SVM_EXIT_CPUID:
1019+
if (opcode == 0xa20f)
1020+
return ES_OK;
1021+
break;
1022+
1023+
case SVM_EXIT_INVD:
1024+
if (opcode == 0x080f)
1025+
return ES_OK;
1026+
break;
1027+
1028+
case SVM_EXIT_MONITOR:
1029+
if (opcode == 0x010f && modrm == 0xc8)
1030+
return ES_OK;
1031+
break;
1032+
1033+
case SVM_EXIT_MWAIT:
1034+
if (opcode == 0x010f && modrm == 0xc9)
1035+
return ES_OK;
1036+
break;
1037+
1038+
case SVM_EXIT_MSR:
1039+
/* RDMSR */
1040+
if (opcode == 0x320f ||
1041+
/* WRMSR */
1042+
opcode == 0x300f)
1043+
return ES_OK;
1044+
break;
1045+
1046+
case SVM_EXIT_RDPMC:
1047+
if (opcode == 0x330f)
1048+
return ES_OK;
1049+
break;
1050+
1051+
case SVM_EXIT_RDTSC:
1052+
if (opcode == 0x310f)
1053+
return ES_OK;
1054+
break;
1055+
1056+
case SVM_EXIT_RDTSCP:
1057+
if (opcode == 0x010f && modrm == 0xf9)
1058+
return ES_OK;
1059+
break;
1060+
1061+
case SVM_EXIT_READ_DR7:
1062+
if (opcode == 0x210f &&
1063+
X86_MODRM_REG(ctxt->insn.modrm.value) == 7)
1064+
return ES_OK;
1065+
break;
1066+
1067+
case SVM_EXIT_VMMCALL:
1068+
if (opcode == 0x010f && modrm == 0xd9)
1069+
return ES_OK;
1070+
1071+
break;
1072+
1073+
case SVM_EXIT_WRITE_DR7:
1074+
if (opcode == 0x230f &&
1075+
X86_MODRM_REG(ctxt->insn.modrm.value) == 7)
1076+
return ES_OK;
1077+
break;
1078+
1079+
case SVM_EXIT_WBINVD:
1080+
if (opcode == 0x90f)
1081+
return ES_OK;
1082+
break;
1083+
1084+
default:
1085+
break;
1086+
}
1087+
1088+
sev_printk(KERN_ERR "Wrong/unhandled opcode bytes: 0x%x, exit_code: 0x%lx, rIP: 0x%lx\n",
1089+
opcode, exit_code, ctxt->regs->ip);
1090+
1091+
return ES_UNSUPPORTED;
1092+
}

arch/x86/kernel/sev.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1738,7 +1738,10 @@ static enum es_result vc_handle_exitcode(struct es_em_ctxt *ctxt,
17381738
struct ghcb *ghcb,
17391739
unsigned long exit_code)
17401740
{
1741-
enum es_result result;
1741+
enum es_result result = vc_check_opcode_bytes(ctxt, exit_code);
1742+
1743+
if (result != ES_OK)
1744+
return result;
17421745

17431746
switch (exit_code) {
17441747
case SVM_EXIT_READ_DR7:

0 commit comments

Comments
 (0)