aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm/emulate.c
diff options
context:
space:
mode:
authorNadav Amit <namit@cs.technion.ac.il>2015-01-26 02:32:27 -0500
committerPaolo Bonzini <pbonzini@redhat.com>2015-01-26 06:17:34 -0500
commit82268083fa78452c1c8be30a82984e470d9678c7 (patch)
tree94b353219e729453843c1199c68de06eb9703d78 /arch/x86/kvm/emulate.c
parentbac155310be35e0fa64b066d47625d2a12a75122 (diff)
KVM: x86: Emulation of call may use incorrect stack size
On long-mode, when far call that changes cs.l takes place, the stack size is determined by the new mode. For instance, if we go from 32-bit mode to 64-bit mode, the stack-size if 64. KVM uses the old stack size. Fix it. Signed-off-by: Nadav Amit <namit@cs.technion.ac.il> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'arch/x86/kvm/emulate.c')
-rw-r--r--arch/x86/kvm/emulate.c25
1 files changed, 18 insertions, 7 deletions
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index c3b07574942f..81dcf7964701 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -741,19 +741,26 @@ static int assign_eip_far(struct x86_emulate_ctxt *ctxt, ulong dst,
741 const struct desc_struct *cs_desc) 741 const struct desc_struct *cs_desc)
742{ 742{
743 enum x86emul_mode mode = ctxt->mode; 743 enum x86emul_mode mode = ctxt->mode;
744 int rc;
744 745
745#ifdef CONFIG_X86_64 746#ifdef CONFIG_X86_64
746 if (ctxt->mode >= X86EMUL_MODE_PROT32 && cs_desc->l) { 747 if (ctxt->mode >= X86EMUL_MODE_PROT16) {
747 u64 efer = 0; 748 if (cs_desc->l) {
749 u64 efer = 0;
748 750
749 ctxt->ops->get_msr(ctxt, MSR_EFER, &efer); 751 ctxt->ops->get_msr(ctxt, MSR_EFER, &efer);
750 if (efer & EFER_LMA) 752 if (efer & EFER_LMA)
751 mode = X86EMUL_MODE_PROT64; 753 mode = X86EMUL_MODE_PROT64;
754 } else
755 mode = X86EMUL_MODE_PROT32; /* temporary value */
752 } 756 }
753#endif 757#endif
754 if (mode == X86EMUL_MODE_PROT16 || mode == X86EMUL_MODE_PROT32) 758 if (mode == X86EMUL_MODE_PROT16 || mode == X86EMUL_MODE_PROT32)
755 mode = cs_desc->d ? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16; 759 mode = cs_desc->d ? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16;
756 return assign_eip(ctxt, dst, mode); 760 rc = assign_eip(ctxt, dst, mode);
761 if (rc == X86EMUL_CONTINUE)
762 ctxt->mode = mode;
763 return rc;
757} 764}
758 765
759static inline int jmp_rel(struct x86_emulate_ctxt *ctxt, int rel) 766static inline int jmp_rel(struct x86_emulate_ctxt *ctxt, int rel)
@@ -3062,6 +3069,7 @@ static int em_call_far(struct x86_emulate_ctxt *ctxt)
3062 struct desc_struct old_desc, new_desc; 3069 struct desc_struct old_desc, new_desc;
3063 const struct x86_emulate_ops *ops = ctxt->ops; 3070 const struct x86_emulate_ops *ops = ctxt->ops;
3064 int cpl = ctxt->ops->cpl(ctxt); 3071 int cpl = ctxt->ops->cpl(ctxt);
3072 enum x86emul_mode prev_mode = ctxt->mode;
3065 3073
3066 old_eip = ctxt->_eip; 3074 old_eip = ctxt->_eip;
3067 ops->get_segment(ctxt, &old_cs, &old_desc, NULL, VCPU_SREG_CS); 3075 ops->get_segment(ctxt, &old_cs, &old_desc, NULL, VCPU_SREG_CS);
@@ -3085,11 +3093,14 @@ static int em_call_far(struct x86_emulate_ctxt *ctxt)
3085 rc = em_push(ctxt); 3093 rc = em_push(ctxt);
3086 /* If we failed, we tainted the memory, but the very least we should 3094 /* If we failed, we tainted the memory, but the very least we should
3087 restore cs */ 3095 restore cs */
3088 if (rc != X86EMUL_CONTINUE) 3096 if (rc != X86EMUL_CONTINUE) {
3097 pr_warn_once("faulting far call emulation tainted memory\n");
3089 goto fail; 3098 goto fail;
3099 }
3090 return rc; 3100 return rc;
3091fail: 3101fail:
3092 ops->set_segment(ctxt, old_cs, &old_desc, 0, VCPU_SREG_CS); 3102 ops->set_segment(ctxt, old_cs, &old_desc, 0, VCPU_SREG_CS);
3103 ctxt->mode = prev_mode;
3093 return rc; 3104 return rc;
3094 3105
3095} 3106}