From 3aa57a610543086ee7c7bf9f0c455b49d6b2f0b0 Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Fri, 13 Jan 2012 11:18:16 -0500 Subject: [PATCH] CVE-2012-0045 kvm: syscall instruction induced guest panic (rhbz 773392) --- ...truct-x86_emulate_ops-with-get_cpuid.patch | 78 ++++++++++ ...-missing-checks-in-syscall-emulation.patch | 144 ++++++++++++++++++ kernel.spec | 13 +- 3 files changed, 234 insertions(+), 1 deletion(-) create mode 100644 KVM-x86-extend-struct-x86_emulate_ops-with-get_cpuid.patch create mode 100644 KVM-x86-fix-missing-checks-in-syscall-emulation.patch diff --git a/KVM-x86-extend-struct-x86_emulate_ops-with-get_cpuid.patch b/KVM-x86-extend-struct-x86_emulate_ops-with-get_cpuid.patch new file mode 100644 index 000000000..f9dbaa014 --- /dev/null +++ b/KVM-x86-extend-struct-x86_emulate_ops-with-get_cpuid.patch @@ -0,0 +1,78 @@ +From 0769c5de24621141c953fbe1f943582d37cb4244 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Stephan=20B=C3=A4rwolf?= +Date: Thu, 12 Jan 2012 16:43:03 +0100 +Subject: [PATCH 1/2] KVM: x86: extend "struct x86_emulate_ops" with + "get_cpuid" + +In order to be able to proceed checks on CPU-specific properties +within the emulator, function "get_cpuid" is introduced. +With "get_cpuid" it is possible to virtually call the guests +"cpuid"-opcode without changing the VM's context. + +[mtosatti: cleanup/beautify code] + +Signed-off-by: Stephan Baerwolf +Signed-off-by: Marcelo Tosatti +--- + arch/x86/include/asm/kvm_emulate.h | 3 +++ + arch/x86/kvm/x86.c | 23 +++++++++++++++++++++++ + 2 files changed, 26 insertions(+), 0 deletions(-) + +diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h +index ab4092e..c8b2868 100644 +--- a/arch/x86/include/asm/kvm_emulate.h ++++ b/arch/x86/include/asm/kvm_emulate.h +@@ -190,6 +190,9 @@ struct x86_emulate_ops { + int (*intercept)(struct x86_emulate_ctxt *ctxt, + struct x86_instruction_info *info, + enum x86_intercept_stage stage); ++ ++ bool (*get_cpuid)(struct x86_emulate_ctxt *ctxt, ++ u32 *eax, u32 *ebx, u32 *ecx, u32 *edx); + }; + + typedef u32 __attribute__((vector_size(16))) sse128_t; +diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c +index f0fa3fb..c95ca2d 100644 +--- a/arch/x86/kvm/x86.c ++++ b/arch/x86/kvm/x86.c +@@ -4205,6 +4205,28 @@ static int emulator_intercept(struct x86_emulate_ctxt *ctxt, + return kvm_x86_ops->check_intercept(emul_to_vcpu(ctxt), info, stage); + } + ++static bool emulator_get_cpuid(struct x86_emulate_ctxt *ctxt, ++ u32 *eax, u32 *ebx, u32 *ecx, u32 *edx) ++{ ++ struct kvm_cpuid_entry2 *cpuid = NULL; ++ ++ if (eax && ecx) ++ cpuid = kvm_find_cpuid_entry(emul_to_vcpu(ctxt), ++ *eax, *ecx); ++ ++ if (cpuid) { ++ *eax = cpuid->eax; ++ *ecx = cpuid->ecx; ++ if (ebx) ++ *ebx = cpuid->ebx; ++ if (edx) ++ *edx = cpuid->edx; ++ return true; ++ } ++ ++ return false; ++} ++ + static struct x86_emulate_ops emulate_ops = { + .read_std = kvm_read_guest_virt_system, + .write_std = kvm_write_guest_virt_system, +@@ -4236,6 +4258,7 @@ static struct x86_emulate_ops emulate_ops = { + .get_fpu = emulator_get_fpu, + .put_fpu = emulator_put_fpu, + .intercept = emulator_intercept, ++ .get_cpuid = emulator_get_cpuid, + }; + + static void cache_all_regs(struct kvm_vcpu *vcpu) +-- +1.7.7.5 + 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?= +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 +Signed-off-by: Marcelo Tosatti +--- + 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 + diff --git a/kernel.spec b/kernel.spec index cf203e387..4dc251b6e 100644 --- a/kernel.spec +++ b/kernel.spec @@ -54,7 +54,7 @@ Summary: The Linux kernel # For non-released -rc kernels, this will be appended after the rcX and # gitX tags, so a 3 here would become part of release "0.rcX.gitX.3" # -%global baserelease 1 +%global baserelease 2 %global fedora_build %{baserelease} # base_sublevel is the kernel version we're starting with and patching @@ -757,6 +757,10 @@ Patch21071: ext4-Fix-error-handling-on-inode-bitmap-corruption.patch #rhbz 769766 Patch21072: mac80211-fix-rx-key-NULL-ptr-deref-in-promiscuous-mode.patch +#rhbz 773392 +Patch21073: KVM-x86-extend-struct-x86_emulate_ops-with-get_cpuid.patch +Patch21074: KVM-x86-fix-missing-checks-in-syscall-emulation.patch + # compat-wireless patches Patch50000: compat-wireless-config-fixups.patch Patch50001: compat-wireless-pr_fmt-warning-avoidance.patch @@ -1467,6 +1471,10 @@ ApplyPatch ext4-Fix-error-handling-on-inode-bitmap-corruption.patch ApplyPatch mac80211-fix-rx-key-NULL-ptr-deref-in-promiscuous-mode.patch +#rhbz 773392 +ApplyPatch KVM-x86-extend-struct-x86_emulate_ops-with-get_cpuid.patch +ApplyPatch KVM-x86-fix-missing-checks-in-syscall-emulation.patch + # END OF PATCH APPLICATIONS %endif @@ -2301,6 +2309,9 @@ fi # ||----w | # || || %changelog +* Fri Jan 13 2012 Josh Boyer 3.2.1-2 +- CVE-2012-0045 kvm: syscall instruction induced guest panic (rhbz 773392) + * Fri Jan 13 2012 Josh Boyer 3.2.1-1 - Linux 3.1.2 - Change stable patch compression format to xz