forked from Minki/linux
KVM: x86: Fix far-jump to non-canonical check
Commit d1442d85cc
("KVM: x86: Handle errors when RIP is set during far
jumps") introduced a bug that caused the fix to be incomplete. Due to
incorrect evaluation, far jump to segment with L bit cleared (i.e., 32-bit
segment) and RIP with any of the high bits set (i.e, RIP[63:32] != 0) set may
not trigger #GP. As we know, this imposes a security problem.
In addition, the condition for two warnings was incorrect.
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: Nadav Amit <namit@cs.technion.ac.il>
[Add #ifdef CONFIG_X86_64 to avoid complaints of undefined behavior. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
fd56e1546a
commit
cd9b8e2c48
@ -574,12 +574,14 @@ static inline int assign_eip_far(struct x86_emulate_ctxt *ctxt, ulong dst,
|
|||||||
case 4:
|
case 4:
|
||||||
ctxt->_eip = (u32)dst;
|
ctxt->_eip = (u32)dst;
|
||||||
break;
|
break;
|
||||||
|
#ifdef CONFIG_X86_64
|
||||||
case 8:
|
case 8:
|
||||||
if ((cs_l && is_noncanonical_address(dst)) ||
|
if ((cs_l && is_noncanonical_address(dst)) ||
|
||||||
(!cs_l && (dst & ~(u32)-1)))
|
(!cs_l && (dst >> 32) != 0))
|
||||||
return emulate_gp(ctxt, 0);
|
return emulate_gp(ctxt, 0);
|
||||||
ctxt->_eip = dst;
|
ctxt->_eip = dst;
|
||||||
break;
|
break;
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
WARN(1, "unsupported eip assignment size\n");
|
WARN(1, "unsupported eip assignment size\n");
|
||||||
}
|
}
|
||||||
@ -2035,7 +2037,7 @@ static int em_jmp_far(struct x86_emulate_ctxt *ctxt)
|
|||||||
|
|
||||||
rc = assign_eip_far(ctxt, ctxt->src.val, new_desc.l);
|
rc = assign_eip_far(ctxt, ctxt->src.val, new_desc.l);
|
||||||
if (rc != X86EMUL_CONTINUE) {
|
if (rc != X86EMUL_CONTINUE) {
|
||||||
WARN_ON(!ctxt->mode != X86EMUL_MODE_PROT64);
|
WARN_ON(ctxt->mode != X86EMUL_MODE_PROT64);
|
||||||
/* assigning eip failed; restore the old cs */
|
/* assigning eip failed; restore the old cs */
|
||||||
ops->set_segment(ctxt, old_sel, &old_desc, 0, VCPU_SREG_CS);
|
ops->set_segment(ctxt, old_sel, &old_desc, 0, VCPU_SREG_CS);
|
||||||
return rc;
|
return rc;
|
||||||
@ -2132,7 +2134,7 @@ static int em_ret_far(struct x86_emulate_ctxt *ctxt)
|
|||||||
return rc;
|
return rc;
|
||||||
rc = assign_eip_far(ctxt, eip, new_desc.l);
|
rc = assign_eip_far(ctxt, eip, new_desc.l);
|
||||||
if (rc != X86EMUL_CONTINUE) {
|
if (rc != X86EMUL_CONTINUE) {
|
||||||
WARN_ON(!ctxt->mode != X86EMUL_MODE_PROT64);
|
WARN_ON(ctxt->mode != X86EMUL_MODE_PROT64);
|
||||||
ops->set_segment(ctxt, old_cs, &old_desc, 0, VCPU_SREG_CS);
|
ops->set_segment(ctxt, old_cs, &old_desc, 0, VCPU_SREG_CS);
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
|
Loading…
Reference in New Issue
Block a user