KVM: nVMX: Ignore segment base for VMX memory operand when segment not FS or GS
diff mbox series

Message ID 20190715154744.36134-1-liran.alon@oracle.com
State New
Headers show
Series
  • KVM: nVMX: Ignore segment base for VMX memory operand when segment not FS or GS
Related show

Commit Message

Liran Alon July 15, 2019, 3:47 p.m. UTC
As reported by Maxime at
https://bugzilla.kernel.org/show_bug.cgi?id=204175:

In vmx/nested.c::get_vmx_mem_address(), when the guest runs in long mode,
the base address of the memory operand is computed with a simple:
    *ret = s.base + off;

This is incorrect, the base applies only to FS and GS, not to the others.
Because of that, if the guest uses a VMX instruction based on DS and has
a DS.base that is non-zero, KVM wrongfully adds the base to the
resulting address.

Reported-by: Maxime Villard <max@m00nbsd.net>
Reviewed-by: Joao Martins <joao.m.martins@oracle.com>
Signed-off-by: Liran Alon <liran.alon@oracle.com>
---
 arch/x86/kvm/vmx/nested.c | 2 ++
 1 file changed, 2 insertions(+)

Comments

Vitaly Kuznetsov July 15, 2019, 4:22 p.m. UTC | #1
Liran Alon <liran.alon@oracle.com> writes:

> As reported by Maxime at
> https://bugzilla.kernel.org/show_bug.cgi?id=204175:
>
> In vmx/nested.c::get_vmx_mem_address(), when the guest runs in long mode,
> the base address of the memory operand is computed with a simple:
>     *ret = s.base + off;
>
> This is incorrect, the base applies only to FS and GS, not to the others.
> Because of that, if the guest uses a VMX instruction based on DS and has
> a DS.base that is non-zero, KVM wrongfully adds the base to the
> resulting address.
>
> Reported-by: Maxime Villard <max@m00nbsd.net>
> Reviewed-by: Joao Martins <joao.m.martins@oracle.com>
> Signed-off-by: Liran Alon <liran.alon@oracle.com>
> ---
>  arch/x86/kvm/vmx/nested.c | 2 ++
>  1 file changed, 2 insertions(+)
>
> diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
> index 18efb338ed8a..e01e1b6b8167 100644
> --- a/arch/x86/kvm/vmx/nested.c
> +++ b/arch/x86/kvm/vmx/nested.c
> @@ -4068,6 +4068,8 @@ int get_vmx_mem_address(struct kvm_vcpu *vcpu, unsigned long exit_qualification,
>  		 * mode, e.g. a 32-bit address size can yield a 64-bit virtual
>  		 * address when using FS/GS with a non-zero base.
>  		 */
> +		if ((seg_reg != VCPU_SREG_FS) && (seg_reg != VCPU_SREG_GS))
> +			s.base = 0;

(personal preference)
 
 I'd rather write this as

    /* In long mode only FS and GS bases are considered */
    if (seg_reg == VCPU_SREG_FS || seg_reg == VCPU_SREG_GS)
       *ret = s.base + off;
    else 
       *ret = off;

>  		*ret = s.base + off;
>  
>  		/* Long mode: #GP(0)/#SS(0) if the memory address is in a

As-is or rewritten with my suggestion,

Reviewed-by: Vitaly Kuznetsov <vkuznets@redhat.com>
Sean Christopherson July 15, 2019, 5:21 p.m. UTC | #2
On Mon, Jul 15, 2019 at 06:22:52PM +0200, Vitaly Kuznetsov wrote:
> Liran Alon <liran.alon@oracle.com> writes:
> 
> > As reported by Maxime at
> > https://bugzilla.kernel.org/show_bug.cgi?id=204175:
> >
> > In vmx/nested.c::get_vmx_mem_address(), when the guest runs in long mode,
> > the base address of the memory operand is computed with a simple:
> >     *ret = s.base + off;
> >
> > This is incorrect, the base applies only to FS and GS, not to the others.
> > Because of that, if the guest uses a VMX instruction based on DS and has
> > a DS.base that is non-zero, KVM wrongfully adds the base to the
> > resulting address.
> >
> > Reported-by: Maxime Villard <max@m00nbsd.net>
> > Reviewed-by: Joao Martins <joao.m.martins@oracle.com>
> > Signed-off-by: Liran Alon <liran.alon@oracle.com>
> > ---
> >  arch/x86/kvm/vmx/nested.c | 2 ++
> >  1 file changed, 2 insertions(+)
> >
> > diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
> > index 18efb338ed8a..e01e1b6b8167 100644
> > --- a/arch/x86/kvm/vmx/nested.c
> > +++ b/arch/x86/kvm/vmx/nested.c
> > @@ -4068,6 +4068,8 @@ int get_vmx_mem_address(struct kvm_vcpu *vcpu, unsigned long exit_qualification,
> >  		 * mode, e.g. a 32-bit address size can yield a 64-bit virtual
> >  		 * address when using FS/GS with a non-zero base.
> >  		 */
> > +		if ((seg_reg != VCPU_SREG_FS) && (seg_reg != VCPU_SREG_GS))

I'm pretty sure the internal parantheses are unnecessary.

> > +			s.base = 0;
> 
> (personal preference)
>  
>  I'd rather write this as
> 
>     /* In long mode only FS and GS bases are considered */
>     if (seg_reg == VCPU_SREG_FS || seg_reg == VCPU_SREG_GS)
>        *ret = s.base + off;
>     else 
>        *ret = off;
> 
> >  		*ret = s.base + off;
> >  
> >  		/* Long mode: #GP(0)/#SS(0) if the memory address is in a
> 
> As-is or rewritten with my suggestion,

Likewise,

Reviewed-by: Sean Christopherson <sean.j.christopherson@intel.com>

> 
> Reviewed-by: Vitaly Kuznetsov <vkuznets@redhat.com>
> 
> -- 
> Vitaly
Paolo Bonzini July 15, 2019, 6:28 p.m. UTC | #3
On 15/07/19 19:21, Sean Christopherson wrote:
>>> +		if ((seg_reg != VCPU_SREG_FS) && (seg_reg != VCPU_SREG_GS))
> I'm pretty sure the internal parantheses are unnecessary.
> 

Indeed, that's so Pascal! :)  I'll apply Vitaly's suggestion and queue it.

Paolo
Liran Alon July 15, 2019, 6:30 p.m. UTC | #4
> On 15 Jul 2019, at 21:28, Paolo Bonzini <pbonzini@redhat.com> wrote:
> 
> On 15/07/19 19:21, Sean Christopherson wrote:
>>>> +		if ((seg_reg != VCPU_SREG_FS) && (seg_reg != VCPU_SREG_GS))
>> I'm pretty sure the internal parantheses are unnecessary.
>> 
> 
> Indeed, that's so Pascal! :)  I'll apply Vitaly's suggestion and queue it.
> 
> Paolo

I like parentheses as it makes ordering of expression a no-brainer. But that’s just a matter of taste I guess.
I don’t mind you will change it according to given suggestions. :)

-Liran
Sean Christopherson July 15, 2019, 6:44 p.m. UTC | #5
On Mon, Jul 15, 2019 at 09:30:48PM +0300, Liran Alon wrote:
> I like parentheses as it makes ordering of expression a no-brainer.

Matching parantheses is not my forte :-)

Patch
diff mbox series

diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
index 18efb338ed8a..e01e1b6b8167 100644
--- a/arch/x86/kvm/vmx/nested.c
+++ b/arch/x86/kvm/vmx/nested.c
@@ -4068,6 +4068,8 @@  int get_vmx_mem_address(struct kvm_vcpu *vcpu, unsigned long exit_qualification,
 		 * mode, e.g. a 32-bit address size can yield a 64-bit virtual
 		 * address when using FS/GS with a non-zero base.
 		 */
+		if ((seg_reg != VCPU_SREG_FS) && (seg_reg != VCPU_SREG_GS))
+			s.base = 0;
 		*ret = s.base + off;
 
 		/* Long mode: #GP(0)/#SS(0) if the memory address is in a