Skip to content

Commit e3ef461

Browse files
committed
x86/sev: Harden #VC instruction emulation somewhat
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 41bccc9 commit e3ef461

File tree

3 files changed

+108
-3
lines changed

3 files changed

+108
-3
lines changed

arch/x86/boot/compressed/sev.c

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

307+
result = vc_check_opcode_bytes(&ctxt, exit_code);
308+
if (result != ES_OK)
309+
goto finish;
310+
307311
switch (exit_code) {
308312
case SVM_EXIT_RDTSC:
309313
case SVM_EXIT_RDTSCP:

arch/x86/kernel/sev-shared.c

Lines changed: 100 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,15 @@
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__)
1517
#else
1618
#undef WARN
1719
#define WARN(condition, format...) (!!(condition))
20+
#define sev_printk(fmt, ...)
21+
#define sev_printk_rtl(fmt, ...)
1822
#endif
1923

2024
/* I/O parameters for CPUID-related helpers */
@@ -574,13 +578,18 @@ void __init do_vc_no_ghcb(struct pt_regs *regs, unsigned long exit_code)
574578
{
575579
unsigned int subfn = lower_bits(regs->cx, 32);
576580
unsigned int fn = lower_bits(regs->ax, 32);
581+
u16 opcode = *(unsigned short *)regs->ip;
577582
struct cpuid_leaf leaf;
578583
int ret;
579584

580585
/* Only CPUID is supported via MSR protocol */
581586
if (exit_code != SVM_EXIT_CPUID)
582587
goto fail;
583588

589+
/* Is it really a CPUID insn? */
590+
if (opcode != 0xa20f)
591+
goto fail;
592+
584593
leaf.fn = fn;
585594
leaf.subfn = subfn;
586595

@@ -1170,3 +1179,92 @@ static int vmgexit_psc(struct ghcb *ghcb, struct snp_psc_desc *desc)
11701179
out:
11711180
return ret;
11721181
}
1182+
1183+
static enum es_result vc_check_opcode_bytes(struct es_em_ctxt *ctxt,
1184+
unsigned long exit_code)
1185+
{
1186+
unsigned int opcode = (unsigned int)ctxt->insn.opcode.value;
1187+
u8 modrm = ctxt->insn.modrm.value;
1188+
1189+
switch (exit_code) {
1190+
1191+
case SVM_EXIT_IOIO:
1192+
case SVM_EXIT_NPF:
1193+
/* handled separately */
1194+
return ES_OK;
1195+
1196+
case SVM_EXIT_CPUID:
1197+
if (opcode == 0xa20f)
1198+
return ES_OK;
1199+
break;
1200+
1201+
case SVM_EXIT_INVD:
1202+
if (opcode == 0x080f)
1203+
return ES_OK;
1204+
break;
1205+
1206+
case SVM_EXIT_MONITOR:
1207+
if (opcode == 0x010f && modrm == 0xc8)
1208+
return ES_OK;
1209+
break;
1210+
1211+
case SVM_EXIT_MWAIT:
1212+
if (opcode == 0x010f && modrm == 0xc9)
1213+
return ES_OK;
1214+
break;
1215+
1216+
case SVM_EXIT_MSR:
1217+
/* RDMSR */
1218+
if (opcode == 0x320f ||
1219+
/* WRMSR */
1220+
opcode == 0x300f)
1221+
return ES_OK;
1222+
break;
1223+
1224+
case SVM_EXIT_RDPMC:
1225+
if (opcode == 0x330f)
1226+
return ES_OK;
1227+
break;
1228+
1229+
case SVM_EXIT_RDTSC:
1230+
if (opcode == 0x310f)
1231+
return ES_OK;
1232+
break;
1233+
1234+
case SVM_EXIT_RDTSCP:
1235+
if (opcode == 0x010f && modrm == 0xf9)
1236+
return ES_OK;
1237+
break;
1238+
1239+
case SVM_EXIT_READ_DR7:
1240+
if (opcode == 0x210f &&
1241+
X86_MODRM_REG(ctxt->insn.modrm.value) == 7)
1242+
return ES_OK;
1243+
break;
1244+
1245+
case SVM_EXIT_VMMCALL:
1246+
if (opcode == 0x010f && modrm == 0xd9)
1247+
return ES_OK;
1248+
1249+
break;
1250+
1251+
case SVM_EXIT_WRITE_DR7:
1252+
if (opcode == 0x230f &&
1253+
X86_MODRM_REG(ctxt->insn.modrm.value) == 7)
1254+
return ES_OK;
1255+
break;
1256+
1257+
case SVM_EXIT_WBINVD:
1258+
if (opcode == 0x90f)
1259+
return ES_OK;
1260+
break;
1261+
1262+
default:
1263+
break;
1264+
}
1265+
1266+
sev_printk(KERN_ERR "Wrong/unhandled opcode bytes: 0x%x, exit_code: 0x%lx, rIP: 0x%lx\n",
1267+
opcode, exit_code, ctxt->regs->ip);
1268+
1269+
return ES_UNSUPPORTED;
1270+
}

arch/x86/kernel/sev.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1752,7 +1752,10 @@ static enum es_result vc_handle_exitcode(struct es_em_ctxt *ctxt,
17521752
struct ghcb *ghcb,
17531753
unsigned long exit_code)
17541754
{
1755-
enum es_result result;
1755+
enum es_result result = vc_check_opcode_bytes(ctxt, exit_code);
1756+
1757+
if (result != ES_OK)
1758+
return result;
17561759

17571760
switch (exit_code) {
17581761
case SVM_EXIT_READ_DR7:

0 commit comments

Comments
 (0)