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