mirror of
https://github.com/torvalds/linux.git
synced 2024-12-02 09:01:34 +00:00
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) <bp@alien8.de> Acked-by: Tom Lendacky <thomas.lendacky@amd.com> Link: https://lore.kernel.org/r/20240105101407.11694-1-bp@alien8.de
This commit is contained in:
parent
41bccc98fb
commit
e3ef461af3
@ -304,6 +304,10 @@ void do_boot_stage2_vc(struct pt_regs *regs, unsigned long exit_code)
|
||||
if (result != ES_OK)
|
||||
goto finish;
|
||||
|
||||
result = vc_check_opcode_bytes(&ctxt, exit_code);
|
||||
if (result != ES_OK)
|
||||
goto finish;
|
||||
|
||||
switch (exit_code) {
|
||||
case SVM_EXIT_RDTSC:
|
||||
case SVM_EXIT_RDTSCP:
|
||||
|
@ -10,11 +10,15 @@
|
||||
*/
|
||||
|
||||
#ifndef __BOOT_COMPRESSED
|
||||
#define error(v) pr_err(v)
|
||||
#define has_cpuflag(f) boot_cpu_has(f)
|
||||
#define error(v) pr_err(v)
|
||||
#define has_cpuflag(f) boot_cpu_has(f)
|
||||
#define sev_printk(fmt, ...) printk(fmt, ##__VA_ARGS__)
|
||||
#define sev_printk_rtl(fmt, ...) printk_ratelimited(fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
#undef WARN
|
||||
#define WARN(condition, format...) (!!(condition))
|
||||
#define sev_printk(fmt, ...)
|
||||
#define sev_printk_rtl(fmt, ...)
|
||||
#endif
|
||||
|
||||
/* I/O parameters for CPUID-related helpers */
|
||||
@ -574,6 +578,7 @@ void __init do_vc_no_ghcb(struct pt_regs *regs, unsigned long exit_code)
|
||||
{
|
||||
unsigned int subfn = lower_bits(regs->cx, 32);
|
||||
unsigned int fn = lower_bits(regs->ax, 32);
|
||||
u16 opcode = *(unsigned short *)regs->ip;
|
||||
struct cpuid_leaf leaf;
|
||||
int ret;
|
||||
|
||||
@ -581,6 +586,10 @@ void __init do_vc_no_ghcb(struct pt_regs *regs, unsigned long exit_code)
|
||||
if (exit_code != SVM_EXIT_CPUID)
|
||||
goto fail;
|
||||
|
||||
/* Is it really a CPUID insn? */
|
||||
if (opcode != 0xa20f)
|
||||
goto fail;
|
||||
|
||||
leaf.fn = fn;
|
||||
leaf.subfn = subfn;
|
||||
|
||||
@ -1170,3 +1179,92 @@ static int vmgexit_psc(struct ghcb *ghcb, struct snp_psc_desc *desc)
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static enum es_result vc_check_opcode_bytes(struct es_em_ctxt *ctxt,
|
||||
unsigned long exit_code)
|
||||
{
|
||||
unsigned int opcode = (unsigned int)ctxt->insn.opcode.value;
|
||||
u8 modrm = ctxt->insn.modrm.value;
|
||||
|
||||
switch (exit_code) {
|
||||
|
||||
case SVM_EXIT_IOIO:
|
||||
case SVM_EXIT_NPF:
|
||||
/* handled separately */
|
||||
return ES_OK;
|
||||
|
||||
case SVM_EXIT_CPUID:
|
||||
if (opcode == 0xa20f)
|
||||
return ES_OK;
|
||||
break;
|
||||
|
||||
case SVM_EXIT_INVD:
|
||||
if (opcode == 0x080f)
|
||||
return ES_OK;
|
||||
break;
|
||||
|
||||
case SVM_EXIT_MONITOR:
|
||||
if (opcode == 0x010f && modrm == 0xc8)
|
||||
return ES_OK;
|
||||
break;
|
||||
|
||||
case SVM_EXIT_MWAIT:
|
||||
if (opcode == 0x010f && modrm == 0xc9)
|
||||
return ES_OK;
|
||||
break;
|
||||
|
||||
case SVM_EXIT_MSR:
|
||||
/* RDMSR */
|
||||
if (opcode == 0x320f ||
|
||||
/* WRMSR */
|
||||
opcode == 0x300f)
|
||||
return ES_OK;
|
||||
break;
|
||||
|
||||
case SVM_EXIT_RDPMC:
|
||||
if (opcode == 0x330f)
|
||||
return ES_OK;
|
||||
break;
|
||||
|
||||
case SVM_EXIT_RDTSC:
|
||||
if (opcode == 0x310f)
|
||||
return ES_OK;
|
||||
break;
|
||||
|
||||
case SVM_EXIT_RDTSCP:
|
||||
if (opcode == 0x010f && modrm == 0xf9)
|
||||
return ES_OK;
|
||||
break;
|
||||
|
||||
case SVM_EXIT_READ_DR7:
|
||||
if (opcode == 0x210f &&
|
||||
X86_MODRM_REG(ctxt->insn.modrm.value) == 7)
|
||||
return ES_OK;
|
||||
break;
|
||||
|
||||
case SVM_EXIT_VMMCALL:
|
||||
if (opcode == 0x010f && modrm == 0xd9)
|
||||
return ES_OK;
|
||||
|
||||
break;
|
||||
|
||||
case SVM_EXIT_WRITE_DR7:
|
||||
if (opcode == 0x230f &&
|
||||
X86_MODRM_REG(ctxt->insn.modrm.value) == 7)
|
||||
return ES_OK;
|
||||
break;
|
||||
|
||||
case SVM_EXIT_WBINVD:
|
||||
if (opcode == 0x90f)
|
||||
return ES_OK;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
sev_printk(KERN_ERR "Wrong/unhandled opcode bytes: 0x%x, exit_code: 0x%lx, rIP: 0x%lx\n",
|
||||
opcode, exit_code, ctxt->regs->ip);
|
||||
|
||||
return ES_UNSUPPORTED;
|
||||
}
|
||||
|
@ -1752,7 +1752,10 @@ static enum es_result vc_handle_exitcode(struct es_em_ctxt *ctxt,
|
||||
struct ghcb *ghcb,
|
||||
unsigned long exit_code)
|
||||
{
|
||||
enum es_result result;
|
||||
enum es_result result = vc_check_opcode_bytes(ctxt, exit_code);
|
||||
|
||||
if (result != ES_OK)
|
||||
return result;
|
||||
|
||||
switch (exit_code) {
|
||||
case SVM_EXIT_READ_DR7:
|
||||
|
Loading…
Reference in New Issue
Block a user