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