Commit 8570f9e8 authored by Sean Christopherson's avatar Sean Christopherson Committed by Paolo Bonzini

KVM: nVMX: Apply addr size mask to effective address for VMX instructions

The address size of an instruction affects the effective address, not
the virtual/linear address.  The final address may still be truncated,
e.g. to 32-bits outside of long mode, but that happens irrespective of
the address size, e.g. a 32-bit address size can yield a 64-bit virtual
address when using FS/GS with a non-zero base.

Fixes: 064aea77 ("KVM: nVMX: Decoding memory operands of VMX instructions")
Cc: stable@vger.kernel.org
Signed-off-by: default avatarSean Christopherson <sean.j.christopherson@intel.com>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent 946c522b
...@@ -4029,20 +4029,41 @@ int get_vmx_mem_address(struct kvm_vcpu *vcpu, unsigned long exit_qualification, ...@@ -4029,20 +4029,41 @@ int get_vmx_mem_address(struct kvm_vcpu *vcpu, unsigned long exit_qualification,
if (index_is_valid) if (index_is_valid)
off += kvm_register_read(vcpu, index_reg)<<scaling; off += kvm_register_read(vcpu, index_reg)<<scaling;
vmx_get_segment(vcpu, &s, seg_reg); vmx_get_segment(vcpu, &s, seg_reg);
*ret = s.base + off;
/*
* The effective address, i.e. @off, of a memory operand is truncated
* based on the address size of the instruction. Note that this is
* the *effective address*, i.e. the address prior to accounting for
* the segment's base.
*/
if (addr_size == 1) /* 32 bit */ if (addr_size == 1) /* 32 bit */
*ret &= 0xffffffff; off &= 0xffffffff;
else if (addr_size == 0) /* 16 bit */
off &= 0xffff;
/* Checks for #GP/#SS exceptions. */ /* Checks for #GP/#SS exceptions. */
exn = false; exn = false;
if (is_long_mode(vcpu)) { if (is_long_mode(vcpu)) {
/*
* The virtual/linear address is never truncated in 64-bit
* mode, e.g. a 32-bit address size can yield a 64-bit virtual
* address when using FS/GS with a non-zero base.
*/
*ret = s.base + off;
/* Long mode: #GP(0)/#SS(0) if the memory address is in a /* Long mode: #GP(0)/#SS(0) if the memory address is in a
* non-canonical form. This is the only check on the memory * non-canonical form. This is the only check on the memory
* destination for long mode! * destination for long mode!
*/ */
exn = is_noncanonical_address(*ret, vcpu); exn = is_noncanonical_address(*ret, vcpu);
} else if (is_protmode(vcpu)) { } else if (is_protmode(vcpu)) {
/*
* When not in long mode, the virtual/linear address is
* unconditionally truncated to 32 bits regardless of the
* address size.
*/
*ret = (s.base + off) & 0xffffffff;
/* Protected mode: apply checks for segment validity in the /* Protected mode: apply checks for segment validity in the
* following order: * following order:
* - segment type check (#GP(0) may be thrown) * - segment type check (#GP(0) may be thrown)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment