Josh Boyer 3aa57a6
From e28ba7bb020f07193bc000453c8775e9d2c0dda7 Mon Sep 17 00:00:00 2001
Josh Boyer 3aa57a6
From: =?UTF-8?q?Stephan=20B=C3=A4rwolf?= <stephan.baerwolf@tu-ilmenau.de>
Josh Boyer 3aa57a6
Date: Thu, 12 Jan 2012 16:43:04 +0100
Josh Boyer 3aa57a6
Subject: [PATCH 2/2] KVM: x86: fix missing checks in syscall emulation
Josh Boyer 3aa57a6
Josh Boyer 3aa57a6
On hosts without this patch, 32bit guests will crash (and 64bit guests
Josh Boyer 3aa57a6
may behave in a wrong way) for example by simply executing following
Josh Boyer 3aa57a6
nasm-demo-application:
Josh Boyer 3aa57a6
Josh Boyer 3aa57a6
    [bits 32]
Josh Boyer 3aa57a6
    global _start
Josh Boyer 3aa57a6
    SECTION .text
Josh Boyer 3aa57a6
    _start: syscall
Josh Boyer 3aa57a6
Josh Boyer 3aa57a6
(I tested it with winxp and linux - both always crashed)
Josh Boyer 3aa57a6
Josh Boyer 3aa57a6
    Disassembly of section .text:
Josh Boyer 3aa57a6
Josh Boyer 3aa57a6
    00000000 <_start>:
Josh Boyer 3aa57a6
       0:   0f 05                   syscall
Josh Boyer 3aa57a6
Josh Boyer 3aa57a6
The reason seems a missing "invalid opcode"-trap (int6) for the
Josh Boyer 3aa57a6
syscall opcode "0f05", which is not available on Intel CPUs
Josh Boyer 3aa57a6
within non-longmodes, as also on some AMD CPUs within legacy-mode.
Josh Boyer 3aa57a6
(depending on CPU vendor, MSR_EFER and cpuid)
Josh Boyer 3aa57a6
Josh Boyer 3aa57a6
Because previous mentioned OSs may not engage corresponding
Josh Boyer 3aa57a6
syscall target-registers (STAR, LSTAR, CSTAR), they remain
Josh Boyer 3aa57a6
NULL and (non trapping) syscalls are leading to multiple
Josh Boyer 3aa57a6
faults and finally crashs.
Josh Boyer 3aa57a6
Josh Boyer 3aa57a6
Depending on the architecture (AMD or Intel) pretended by
Josh Boyer 3aa57a6
guests, various checks according to vendor's documentation
Josh Boyer 3aa57a6
are implemented to overcome the current issue and behave
Josh Boyer 3aa57a6
like the CPUs physical counterparts.
Josh Boyer 3aa57a6
Josh Boyer 3aa57a6
[mtosatti: cleanup/beautify code]
Josh Boyer 3aa57a6
Josh Boyer 3aa57a6
Signed-off-by: Stephan Baerwolf <stephan.baerwolf@tu-ilmenau.de>
Josh Boyer 3aa57a6
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Josh Boyer 3aa57a6
---
Josh Boyer 3aa57a6
 arch/x86/include/asm/kvm_emulate.h |   13 +++++++++
Josh Boyer 3aa57a6
 arch/x86/kvm/emulate.c             |   51 ++++++++++++++++++++++++++++++++++++
Josh Boyer 3aa57a6
 2 files changed, 64 insertions(+), 0 deletions(-)
Josh Boyer 3aa57a6
Josh Boyer 3aa57a6
diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h
Josh Boyer 3aa57a6
index c8b2868..7b9cfc4 100644
Josh Boyer 3aa57a6
--- a/arch/x86/include/asm/kvm_emulate.h
Josh Boyer 3aa57a6
+++ b/arch/x86/include/asm/kvm_emulate.h
Josh Boyer 3aa57a6
@@ -301,6 +301,19 @@ struct x86_emulate_ctxt {
Josh Boyer 3aa57a6
 #define X86EMUL_MODE_PROT     (X86EMUL_MODE_PROT16|X86EMUL_MODE_PROT32| \
Josh Boyer 3aa57a6
 			       X86EMUL_MODE_PROT64)
Josh Boyer 3aa57a6
 
Josh Boyer 3aa57a6
+/* CPUID vendors */
Josh Boyer 3aa57a6
+#define X86EMUL_CPUID_VENDOR_AuthenticAMD_ebx 0x68747541
Josh Boyer 3aa57a6
+#define X86EMUL_CPUID_VENDOR_AuthenticAMD_ecx 0x444d4163
Josh Boyer 3aa57a6
+#define X86EMUL_CPUID_VENDOR_AuthenticAMD_edx 0x69746e65
Josh Boyer 3aa57a6
+
Josh Boyer 3aa57a6
+#define X86EMUL_CPUID_VENDOR_AMDisbetterI_ebx 0x69444d41
Josh Boyer 3aa57a6
+#define X86EMUL_CPUID_VENDOR_AMDisbetterI_ecx 0x21726574
Josh Boyer 3aa57a6
+#define X86EMUL_CPUID_VENDOR_AMDisbetterI_edx 0x74656273
Josh Boyer 3aa57a6
+
Josh Boyer 3aa57a6
+#define X86EMUL_CPUID_VENDOR_GenuineIntel_ebx 0x756e6547
Josh Boyer 3aa57a6
+#define X86EMUL_CPUID_VENDOR_GenuineIntel_ecx 0x6c65746e
Josh Boyer 3aa57a6
+#define X86EMUL_CPUID_VENDOR_GenuineIntel_edx 0x49656e69
Josh Boyer 3aa57a6
+
Josh Boyer 3aa57a6
 enum x86_intercept_stage {
Josh Boyer 3aa57a6
 	X86_ICTP_NONE = 0,   /* Allow zero-init to not match anything */
Josh Boyer 3aa57a6
 	X86_ICPT_PRE_EXCEPT,
Josh Boyer 3aa57a6
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
Josh Boyer 3aa57a6
index 05a562b..0982507 100644
Josh Boyer 3aa57a6
--- a/arch/x86/kvm/emulate.c
Josh Boyer 3aa57a6
+++ b/arch/x86/kvm/emulate.c
Josh Boyer 3aa57a6
@@ -1891,6 +1891,51 @@ setup_syscalls_segments(struct x86_emulate_ctxt *ctxt,
Josh Boyer 3aa57a6
 	ss->p = 1;
Josh Boyer 3aa57a6
 }
Josh Boyer 3aa57a6
 
Josh Boyer 3aa57a6
+static bool em_syscall_is_enabled(struct x86_emulate_ctxt *ctxt)
Josh Boyer 3aa57a6
+{
Josh Boyer 3aa57a6
+	struct x86_emulate_ops *ops = ctxt->ops;
Josh Boyer 3aa57a6
+	u32 eax, ebx, ecx, edx;
Josh Boyer 3aa57a6
+
Josh Boyer 3aa57a6
+	/*
Josh Boyer 3aa57a6
+	 * syscall should always be enabled in longmode - so only become
Josh Boyer 3aa57a6
+	 * vendor specific (cpuid) if other modes are active...
Josh Boyer 3aa57a6
+	 */
Josh Boyer 3aa57a6
+	if (ctxt->mode == X86EMUL_MODE_PROT64)
Josh Boyer 3aa57a6
+		return true;
Josh Boyer 3aa57a6
+
Josh Boyer 3aa57a6
+	eax = 0x00000000;
Josh Boyer 3aa57a6
+	ecx = 0x00000000;
Josh Boyer 3aa57a6
+	if (ops->get_cpuid(ctxt, &eax, &ebx, &ecx, &edx)) {
Josh Boyer 3aa57a6
+		/*
Josh Boyer 3aa57a6
+		 * Intel ("GenuineIntel")
Josh Boyer 3aa57a6
+		 * remark: Intel CPUs only support "syscall" in 64bit
Josh Boyer 3aa57a6
+		 * longmode. Also an 64bit guest with a
Josh Boyer 3aa57a6
+		 * 32bit compat-app running will #UD !! While this
Josh Boyer 3aa57a6
+		 * behaviour can be fixed (by emulating) into AMD
Josh Boyer 3aa57a6
+		 * response - CPUs of AMD can't behave like Intel.
Josh Boyer 3aa57a6
+		 */
Josh Boyer 3aa57a6
+		if (ebx == X86EMUL_CPUID_VENDOR_GenuineIntel_ebx &&
Josh Boyer 3aa57a6
+		    ecx == X86EMUL_CPUID_VENDOR_GenuineIntel_ecx &&
Josh Boyer 3aa57a6
+		    edx == X86EMUL_CPUID_VENDOR_GenuineIntel_edx)
Josh Boyer 3aa57a6
+			return false;
Josh Boyer 3aa57a6
+
Josh Boyer 3aa57a6
+		/* AMD ("AuthenticAMD") */
Josh Boyer 3aa57a6
+		if (ebx == X86EMUL_CPUID_VENDOR_AuthenticAMD_ebx &&
Josh Boyer 3aa57a6
+		    ecx == X86EMUL_CPUID_VENDOR_AuthenticAMD_ecx &&
Josh Boyer 3aa57a6
+		    edx == X86EMUL_CPUID_VENDOR_AuthenticAMD_edx)
Josh Boyer 3aa57a6
+			return true;
Josh Boyer 3aa57a6
+
Josh Boyer 3aa57a6
+		/* AMD ("AMDisbetter!") */
Josh Boyer 3aa57a6
+		if (ebx == X86EMUL_CPUID_VENDOR_AMDisbetterI_ebx &&
Josh Boyer 3aa57a6
+		    ecx == X86EMUL_CPUID_VENDOR_AMDisbetterI_ecx &&
Josh Boyer 3aa57a6
+		    edx == X86EMUL_CPUID_VENDOR_AMDisbetterI_edx)
Josh Boyer 3aa57a6
+			return true;
Josh Boyer 3aa57a6
+	}
Josh Boyer 3aa57a6
+
Josh Boyer 3aa57a6
+	/* default: (not Intel, not AMD), apply Intel's stricter rules... */
Josh Boyer 3aa57a6
+	return false;
Josh Boyer 3aa57a6
+}
Josh Boyer 3aa57a6
+
Josh Boyer 3aa57a6
 static int em_syscall(struct x86_emulate_ctxt *ctxt)
Josh Boyer 3aa57a6
 {
Josh Boyer 3aa57a6
 	struct x86_emulate_ops *ops = ctxt->ops;
Josh Boyer 3aa57a6
@@ -1904,9 +1949,15 @@ static int em_syscall(struct x86_emulate_ctxt *ctxt)
Josh Boyer 3aa57a6
 	    ctxt->mode == X86EMUL_MODE_VM86)
Josh Boyer 3aa57a6
 		return emulate_ud(ctxt);
Josh Boyer 3aa57a6
 
Josh Boyer 3aa57a6
+	if (!(em_syscall_is_enabled(ctxt)))
Josh Boyer 3aa57a6
+		return emulate_ud(ctxt);
Josh Boyer 3aa57a6
+
Josh Boyer 3aa57a6
 	ops->get_msr(ctxt, MSR_EFER, &efer);
Josh Boyer 3aa57a6
 	setup_syscalls_segments(ctxt, &cs, &ss);
Josh Boyer 3aa57a6
 
Josh Boyer 3aa57a6
+	if (!(efer & EFER_SCE))
Josh Boyer 3aa57a6
+		return emulate_ud(ctxt);
Josh Boyer 3aa57a6
+
Josh Boyer 3aa57a6
 	ops->get_msr(ctxt, MSR_STAR, &msr_data);
Josh Boyer 3aa57a6
 	msr_data >>= 32;
Josh Boyer 3aa57a6
 	cs_sel = (u16)(msr_data & 0xfffc);
Josh Boyer 3aa57a6
-- 
Josh Boyer 3aa57a6
1.7.7.5
Josh Boyer 3aa57a6