Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cb2567bf authored by Nadav Amit's avatar Nadav Amit Committed by Greg Kroah-Hartman
Browse files

KVM: x86: SYSENTER emulation is broken



commit f3747379accba8e95d70cec0eae0582c8c182050 upstream.

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.

Signed-off-by: default avatarNadav Amit <namit@cs.technion.ac.il>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent c546e475
Loading
Loading
Loading
Loading
+8 −19
Original line number Original line Diff line number Diff line
@@ -2345,7 +2345,7 @@ static int em_sysenter(struct x86_emulate_ctxt *ctxt)
	 * Not recognized on AMD in compat mode (but is recognized in legacy
	 * Not recognized on AMD in compat mode (but is recognized in legacy
	 * mode).
	 * mode).
	 */
	 */
	if ((ctxt->mode == X86EMUL_MODE_PROT32) && (efer & EFER_LMA)
	if ((ctxt->mode != X86EMUL_MODE_PROT64) && (efer & EFER_LMA)
	    && !vendor_intel(ctxt))
	    && !vendor_intel(ctxt))
		return emulate_ud(ctxt);
		return emulate_ud(ctxt);


@@ -2358,25 +2358,13 @@ static int em_sysenter(struct x86_emulate_ctxt *ctxt)
	setup_syscalls_segments(ctxt, &cs, &ss);
	setup_syscalls_segments(ctxt, &cs, &ss);


	ops->get_msr(ctxt, MSR_IA32_SYSENTER_CS, &msr_data);
	ops->get_msr(ctxt, MSR_IA32_SYSENTER_CS, &msr_data);
	switch (ctxt->mode) {
	case X86EMUL_MODE_PROT32:
	if ((msr_data & 0xfffc) == 0x0)
	if ((msr_data & 0xfffc) == 0x0)
		return emulate_gp(ctxt, 0);
		return emulate_gp(ctxt, 0);
		break;
	case X86EMUL_MODE_PROT64:
		if (msr_data == 0x0)
			return emulate_gp(ctxt, 0);
		break;
	default:
		break;
	}


	ctxt->eflags &= ~(EFLG_VM | EFLG_IF);
	ctxt->eflags &= ~(EFLG_VM | EFLG_IF);
	cs_sel = (u16)msr_data;
	cs_sel = (u16)msr_data & ~SELECTOR_RPL_MASK;
	cs_sel &= ~SELECTOR_RPL_MASK;
	ss_sel = cs_sel + 8;
	ss_sel = cs_sel + 8;
	ss_sel &= ~SELECTOR_RPL_MASK;
	if (efer & EFER_LMA) {
	if (ctxt->mode == X86EMUL_MODE_PROT64 || (efer & EFER_LMA)) {
		cs.d = 0;
		cs.d = 0;
		cs.l = 1;
		cs.l = 1;
	}
	}
@@ -2385,10 +2373,11 @@ static int em_sysenter(struct x86_emulate_ctxt *ctxt)
	ops->set_segment(ctxt, ss_sel, &ss, 0, VCPU_SREG_SS);
	ops->set_segment(ctxt, ss_sel, &ss, 0, VCPU_SREG_SS);


	ops->get_msr(ctxt, MSR_IA32_SYSENTER_EIP, &msr_data);
	ops->get_msr(ctxt, MSR_IA32_SYSENTER_EIP, &msr_data);
	ctxt->_eip = msr_data;
	ctxt->_eip = (efer & EFER_LMA) ? msr_data : (u32)msr_data;


	ops->get_msr(ctxt, MSR_IA32_SYSENTER_ESP, &msr_data);
	ops->get_msr(ctxt, MSR_IA32_SYSENTER_ESP, &msr_data);
	*reg_write(ctxt, VCPU_REGS_RSP) = msr_data;
	*reg_write(ctxt, VCPU_REGS_RSP) = (efer & EFER_LMA) ? msr_data :
							      (u32)msr_data;


	return X86EMUL_CONTINUE;
	return X86EMUL_CONTINUE;
}
}