diff options
author | Nadav Amit <namit@cs.technion.ac.il> | 2015-01-26 02:32:27 -0500 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2015-01-26 06:17:34 -0500 |
commit | 82268083fa78452c1c8be30a82984e470d9678c7 (patch) | |
tree | 94b353219e729453843c1199c68de06eb9703d78 /arch/x86/kvm/emulate.c | |
parent | bac155310be35e0fa64b066d47625d2a12a75122 (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.c | 25 |
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 | ||
759 | static inline int jmp_rel(struct x86_emulate_ctxt *ctxt, int rel) | 766 | static 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; |
3091 | fail: | 3101 | fail: |
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 | } |