| From foo@baz Thu Feb 1 13:58:04 CET 2018 |
| From: Wanpeng Li <wanpeng.li@hotmail.com> |
| Date: Sun, 5 Nov 2017 16:54:47 -0800 |
| Subject: KVM: X86: Fix operand/address-size during instruction decoding |
| |
| From: Wanpeng Li <wanpeng.li@hotmail.com> |
| |
| |
| [ Upstream commit 3853be2603191829b442b64dac6ae8ba0c027bf9 ] |
| |
| Pedro reported: |
| During tests that we conducted on KVM, we noticed that executing a "PUSH %ES" |
| instruction under KVM produces different results on both memory and the SP |
| register depending on whether EPT support is enabled. With EPT the SP is |
| reduced by 4 bytes (and the written value is 0-padded) but without EPT support |
| it is only reduced by 2 bytes. The difference can be observed when the CS.DB |
| field is 1 (32-bit) but not when it's 0 (16-bit). |
| |
| The internal segment descriptor cache exist even in real/vm8096 mode. The CS.D |
| also should be respected instead of just default operand/address-size/66H |
| prefix/67H prefix during instruction decoding. This patch fixes it by also |
| adjusting operand/address-size according to CS.D. |
| |
| Reported-by: Pedro Fonseca <pfonseca@cs.washington.edu> |
| Tested-by: Pedro Fonseca <pfonseca@cs.washington.edu> |
| Cc: Paolo Bonzini <pbonzini@redhat.com> |
| Cc: Radim Krčmář <rkrcmar@redhat.com> |
| Cc: Nadav Amit <nadav.amit@gmail.com> |
| Cc: Pedro Fonseca <pfonseca@cs.washington.edu> |
| Signed-off-by: Wanpeng Li <wanpeng.li@hotmail.com> |
| Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> |
| Signed-off-by: Radim Krčmář <rkrcmar@redhat.com> |
| Signed-off-by: Sasha Levin <alexander.levin@microsoft.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| arch/x86/kvm/emulate.c | 7 +++++++ |
| 1 file changed, 7 insertions(+) |
| |
| --- a/arch/x86/kvm/emulate.c |
| +++ b/arch/x86/kvm/emulate.c |
| @@ -4990,6 +4990,8 @@ int x86_decode_insn(struct x86_emulate_c |
| bool op_prefix = false; |
| bool has_seg_override = false; |
| struct opcode opcode; |
| + u16 dummy; |
| + struct desc_struct desc; |
| |
| ctxt->memop.type = OP_NONE; |
| ctxt->memopp = NULL; |
| @@ -5008,6 +5010,11 @@ int x86_decode_insn(struct x86_emulate_c |
| switch (mode) { |
| case X86EMUL_MODE_REAL: |
| case X86EMUL_MODE_VM86: |
| + def_op_bytes = def_ad_bytes = 2; |
| + ctxt->ops->get_segment(ctxt, &dummy, &desc, NULL, VCPU_SREG_CS); |
| + if (desc.d) |
| + def_op_bytes = def_ad_bytes = 4; |
| + break; |
| case X86EMUL_MODE_PROT16: |
| def_op_bytes = def_ad_bytes = 2; |
| break; |