diff options
author | Nadav Amit <namit@cs.technion.ac.il> | 2015-01-01 16:11:11 -0500 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2015-01-23 07:57:15 -0500 |
commit | f3747379accba8e95d70cec0eae0582c8c182050 (patch) | |
tree | 4ec2d6f001a3eb058905a9d258c78f43b41f13a1 | |
parent | 63ea0a49ae0b145b91ff2b070c01b66fc75854b9 (diff) |
KVM: x86: SYSENTER emulation is broken
SYSENTER emulation is broken in several ways:
1. It misses the case of 16-bit code segments completely (CVE-2015-0239).
2. MSR_IA32_SYSENTER_CS is checked in 64-bit mode incorrectly (bits 0 and 1 can
still be set without causing #GP).
3. MSR_IA32_SYSENTER_EIP and MSR_IA32_SYSENTER_ESP are not masked in
legacy-mode.
4. There is some unneeded code.
Fix it.
Cc: stable@vger.linux.org
Signed-off-by: Nadav Amit <namit@cs.technion.ac.il>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r-- | arch/x86/kvm/emulate.c | 27 |
1 files changed, 8 insertions, 19 deletions
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 817c6ca2c4fb..de12c1d379f1 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c | |||
@@ -2348,7 +2348,7 @@ static int em_sysenter(struct x86_emulate_ctxt *ctxt) | |||
2348 | * Not recognized on AMD in compat mode (but is recognized in legacy | 2348 | * Not recognized on AMD in compat mode (but is recognized in legacy |
2349 | * mode). | 2349 | * mode). |
2350 | */ | 2350 | */ |
2351 | if ((ctxt->mode == X86EMUL_MODE_PROT32) && (efer & EFER_LMA) | 2351 | if ((ctxt->mode != X86EMUL_MODE_PROT64) && (efer & EFER_LMA) |
2352 | && !vendor_intel(ctxt)) | 2352 | && !vendor_intel(ctxt)) |
2353 | return emulate_ud(ctxt); | 2353 | return emulate_ud(ctxt); |
2354 | 2354 | ||
@@ -2359,25 +2359,13 @@ static int em_sysenter(struct x86_emulate_ctxt *ctxt) | |||
2359 | setup_syscalls_segments(ctxt, &cs, &ss); | 2359 | setup_syscalls_segments(ctxt, &cs, &ss); |
2360 | 2360 | ||
2361 | ops->get_msr(ctxt, MSR_IA32_SYSENTER_CS, &msr_data); | 2361 | ops->get_msr(ctxt, MSR_IA32_SYSENTER_CS, &msr_data); |
2362 | switch (ctxt->mode) { | 2362 | if ((msr_data & 0xfffc) == 0x0) |
2363 | case X86EMUL_MODE_PROT32: | 2363 | return emulate_gp(ctxt, 0); |
2364 | if ((msr_data & 0xfffc) == 0x0) | ||
2365 | return emulate_gp(ctxt, 0); | ||
2366 | break; | ||
2367 | case X86EMUL_MODE_PROT64: | ||
2368 | if (msr_data == 0x0) | ||
2369 | return emulate_gp(ctxt, 0); | ||
2370 | break; | ||
2371 | default: | ||
2372 | break; | ||
2373 | } | ||
2374 | 2364 | ||
2375 | ctxt->eflags &= ~(EFLG_VM | EFLG_IF); | 2365 | ctxt->eflags &= ~(EFLG_VM | EFLG_IF); |
2376 | cs_sel = (u16)msr_data; | 2366 | cs_sel = (u16)msr_data & ~SELECTOR_RPL_MASK; |
2377 | cs_sel &= ~SELECTOR_RPL_MASK; | ||
2378 | ss_sel = cs_sel + 8; | 2367 | ss_sel = cs_sel + 8; |
2379 | ss_sel &= ~SELECTOR_RPL_MASK; | 2368 | if (efer & EFER_LMA) { |
2380 | if (ctxt->mode == X86EMUL_MODE_PROT64 || (efer & EFER_LMA)) { | ||
2381 | cs.d = 0; | 2369 | cs.d = 0; |
2382 | cs.l = 1; | 2370 | cs.l = 1; |
2383 | } | 2371 | } |
@@ -2386,10 +2374,11 @@ static int em_sysenter(struct x86_emulate_ctxt *ctxt) | |||
2386 | ops->set_segment(ctxt, ss_sel, &ss, 0, VCPU_SREG_SS); | 2374 | ops->set_segment(ctxt, ss_sel, &ss, 0, VCPU_SREG_SS); |
2387 | 2375 | ||
2388 | ops->get_msr(ctxt, MSR_IA32_SYSENTER_EIP, &msr_data); | 2376 | ops->get_msr(ctxt, MSR_IA32_SYSENTER_EIP, &msr_data); |
2389 | ctxt->_eip = msr_data; | 2377 | ctxt->_eip = (efer & EFER_LMA) ? msr_data : (u32)msr_data; |
2390 | 2378 | ||
2391 | ops->get_msr(ctxt, MSR_IA32_SYSENTER_ESP, &msr_data); | 2379 | ops->get_msr(ctxt, MSR_IA32_SYSENTER_ESP, &msr_data); |
2392 | *reg_write(ctxt, VCPU_REGS_RSP) = msr_data; | 2380 | *reg_write(ctxt, VCPU_REGS_RSP) = (efer & EFER_LMA) ? msr_data : |
2381 | (u32)msr_data; | ||
2393 | 2382 | ||
2394 | return X86EMUL_CONTINUE; | 2383 | return X86EMUL_CONTINUE; |
2395 | } | 2384 | } |