Commit 7e46dddd6f6cd5dbf3c7bd04a7e75d19475ac9f2
Committed by
Paolo Bonzini
1 parent
fd56e1546a
Exists in
ti-lsk-linux-4.1.y
and in
10 other branches
KVM: x86: Fix far-jump to non-canonical check
Commit d1442d85cc30 ("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. Fixes: d1442d85cc30ea75f7d399474ca738e0bc96f715 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>
Showing 1 changed file with 5 additions and 3 deletions Side-by-side Diff
arch/x86/kvm/emulate.c
... | ... | @@ -574,12 +574,14 @@ |
574 | 574 | case 4: |
575 | 575 | ctxt->_eip = (u32)dst; |
576 | 576 | break; |
577 | +#ifdef CONFIG_X86_64 | |
577 | 578 | case 8: |
578 | 579 | if ((cs_l && is_noncanonical_address(dst)) || |
579 | - (!cs_l && (dst & ~(u32)-1))) | |
580 | + (!cs_l && (dst >> 32) != 0)) | |
580 | 581 | return emulate_gp(ctxt, 0); |
581 | 582 | ctxt->_eip = dst; |
582 | 583 | break; |
584 | +#endif | |
583 | 585 | default: |
584 | 586 | WARN(1, "unsupported eip assignment size\n"); |
585 | 587 | } |
... | ... | @@ -2035,7 +2037,7 @@ |
2035 | 2037 | |
2036 | 2038 | rc = assign_eip_far(ctxt, ctxt->src.val, new_desc.l); |
2037 | 2039 | if (rc != X86EMUL_CONTINUE) { |
2038 | - WARN_ON(!ctxt->mode != X86EMUL_MODE_PROT64); | |
2040 | + WARN_ON(ctxt->mode != X86EMUL_MODE_PROT64); | |
2039 | 2041 | /* assigning eip failed; restore the old cs */ |
2040 | 2042 | ops->set_segment(ctxt, old_sel, &old_desc, 0, VCPU_SREG_CS); |
2041 | 2043 | return rc; |
... | ... | @@ -2132,7 +2134,7 @@ |
2132 | 2134 | return rc; |
2133 | 2135 | rc = assign_eip_far(ctxt, eip, new_desc.l); |
2134 | 2136 | if (rc != X86EMUL_CONTINUE) { |
2135 | - WARN_ON(!ctxt->mode != X86EMUL_MODE_PROT64); | |
2137 | + WARN_ON(ctxt->mode != X86EMUL_MODE_PROT64); | |
2136 | 2138 | ops->set_segment(ctxt, old_cs, &old_desc, 0, VCPU_SREG_CS); |
2137 | 2139 | } |
2138 | 2140 | return rc; |