diff mbox series

[v6,2/7] KVM: VMX: Use is_64_bit_mode() to check 64-bit mode

Message ID 20230319084927.29607-3-binbin.wu@linux.intel.com (mailing list archive)
State New, archived
Headers show
Series Linear Address Masking (LAM) KVM Enabling | expand

Commit Message

Binbin Wu March 19, 2023, 8:49 a.m. UTC
get_vmx_mem_address() and sgx_get_encls_gva() use is_long_mode()
to check 64-bit mode. Should use is_64_bit_mode() instead.

Fixes: f9eb4af67c9d ("KVM: nVMX: VMX instructions: add checks for #GP/#SS exceptions")
Fixes: 70210c044b4e ("KVM: VMX: Add SGX ENCLS[ECREATE] handler to enforce CPUID restrictions")
Signed-off-by: Binbin Wu <binbin.wu@linux.intel.com>
---
 arch/x86/kvm/vmx/nested.c | 2 +-
 arch/x86/kvm/vmx/sgx.c    | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

Comments

Chao Gao March 20, 2023, 12:36 p.m. UTC | #1
On Sun, Mar 19, 2023 at 04:49:22PM +0800, Binbin Wu wrote:
>get_vmx_mem_address() and sgx_get_encls_gva() use is_long_mode()
>to check 64-bit mode. Should use is_64_bit_mode() instead.
>
>Fixes: f9eb4af67c9d ("KVM: nVMX: VMX instructions: add checks for #GP/#SS exceptions")
>Fixes: 70210c044b4e ("KVM: VMX: Add SGX ENCLS[ECREATE] handler to enforce CPUID restrictions")

It is better to split this patch into two: one for nested and one for
SGX.

It is possible that there is a kernel release which has just one of
above two flawed commits, then this fix patch cannot be applied cleanly
to the release.

>Signed-off-by: Binbin Wu <binbin.wu@linux.intel.com>
>---
> arch/x86/kvm/vmx/nested.c | 2 +-
> arch/x86/kvm/vmx/sgx.c    | 4 ++--
> 2 files changed, 3 insertions(+), 3 deletions(-)
>
>diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
>index 557b9c468734..0f84cc05f57c 100644
>--- a/arch/x86/kvm/vmx/nested.c
>+++ b/arch/x86/kvm/vmx/nested.c
>@@ -4959,7 +4959,7 @@ int get_vmx_mem_address(struct kvm_vcpu *vcpu, unsigned long exit_qualification,
> 
> 	/* Checks for #GP/#SS exceptions. */
> 	exn = false;
>-	if (is_long_mode(vcpu)) {
>+	if (is_64_bit_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
>diff --git a/arch/x86/kvm/vmx/sgx.c b/arch/x86/kvm/vmx/sgx.c
>index aa53c98034bf..0574030b071f 100644
>--- a/arch/x86/kvm/vmx/sgx.c
>+++ b/arch/x86/kvm/vmx/sgx.c
>@@ -29,14 +29,14 @@ static int sgx_get_encls_gva(struct kvm_vcpu *vcpu, unsigned long offset,
> 
> 	/* Skip vmcs.GUEST_DS retrieval for 64-bit mode to avoid VMREADs. */
> 	*gva = offset;
>-	if (!is_long_mode(vcpu)) {
>+	if (!is_64_bit_mode(vcpu)) {
> 		vmx_get_segment(vcpu, &s, VCPU_SREG_DS);
> 		*gva += s.base;
> 	}
> 
> 	if (!IS_ALIGNED(*gva, alignment)) {
> 		fault = true;
>-	} else if (likely(is_long_mode(vcpu))) {
>+	} else if (likely(is_64_bit_mode(vcpu))) {
> 		fault = is_noncanonical_address(*gva, vcpu);
> 	} else {
> 		*gva &= 0xffffffff;
>-- 
>2.25.1
>
Binbin Wu March 20, 2023, 12:51 p.m. UTC | #2
On 3/20/2023 8:36 PM, Chao Gao wrote:
> On Sun, Mar 19, 2023 at 04:49:22PM +0800, Binbin Wu wrote:
>> get_vmx_mem_address() and sgx_get_encls_gva() use is_long_mode()
>> to check 64-bit mode. Should use is_64_bit_mode() instead.
>>
>> Fixes: f9eb4af67c9d ("KVM: nVMX: VMX instructions: add checks for #GP/#SS exceptions")
>> Fixes: 70210c044b4e ("KVM: VMX: Add SGX ENCLS[ECREATE] handler to enforce CPUID restrictions")
> It is better to split this patch into two: one for nested and one for
> SGX.
>
> It is possible that there is a kernel release which has just one of
> above two flawed commits, then this fix patch cannot be applied cleanly
> to the release.


OK.

>
>> Signed-off-by: Binbin Wu <binbin.wu@linux.intel.com>
>> ---
>> arch/x86/kvm/vmx/nested.c | 2 +-
>> arch/x86/kvm/vmx/sgx.c    | 4 ++--
>> 2 files changed, 3 insertions(+), 3 deletions(-)
>>
>> diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
>> index 557b9c468734..0f84cc05f57c 100644
>> --- a/arch/x86/kvm/vmx/nested.c
>> +++ b/arch/x86/kvm/vmx/nested.c
>> @@ -4959,7 +4959,7 @@ int get_vmx_mem_address(struct kvm_vcpu *vcpu, unsigned long exit_qualification,
>>
>> 	/* Checks for #GP/#SS exceptions. */
>> 	exn = false;
>> -	if (is_long_mode(vcpu)) {
>> +	if (is_64_bit_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
>> diff --git a/arch/x86/kvm/vmx/sgx.c b/arch/x86/kvm/vmx/sgx.c
>> index aa53c98034bf..0574030b071f 100644
>> --- a/arch/x86/kvm/vmx/sgx.c
>> +++ b/arch/x86/kvm/vmx/sgx.c
>> @@ -29,14 +29,14 @@ static int sgx_get_encls_gva(struct kvm_vcpu *vcpu, unsigned long offset,
>>
>> 	/* Skip vmcs.GUEST_DS retrieval for 64-bit mode to avoid VMREADs. */
>> 	*gva = offset;
>> -	if (!is_long_mode(vcpu)) {
>> +	if (!is_64_bit_mode(vcpu)) {
>> 		vmx_get_segment(vcpu, &s, VCPU_SREG_DS);
>> 		*gva += s.base;
>> 	}
>>
>> 	if (!IS_ALIGNED(*gva, alignment)) {
>> 		fault = true;
>> -	} else if (likely(is_long_mode(vcpu))) {
>> +	} else if (likely(is_64_bit_mode(vcpu))) {
>> 		fault = is_noncanonical_address(*gva, vcpu);
>> 	} else {
>> 		*gva &= 0xffffffff;
>> -- 
>> 2.25.1
>>
Huang, Kai March 20, 2023, 10:36 p.m. UTC | #3
On Sun, 2023-03-19 at 16:49 +0800, Binbin Wu wrote:
> get_vmx_mem_address() and sgx_get_encls_gva() use is_long_mode()
> to check 64-bit mode. Should use is_64_bit_mode() instead.
> 
> Fixes: f9eb4af67c9d ("KVM: nVMX: VMX instructions: add checks for #GP/#SS exceptions")
> Fixes: 70210c044b4e ("KVM: VMX: Add SGX ENCLS[ECREATE] handler to enforce CPUID restrictions")
> Signed-off-by: Binbin Wu <binbin.wu@linux.intel.com>
> ---
>  arch/x86/kvm/vmx/nested.c | 2 +-
>  arch/x86/kvm/vmx/sgx.c    | 4 ++--
>  2 files changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
> index 557b9c468734..0f84cc05f57c 100644
> --- a/arch/x86/kvm/vmx/nested.c
> +++ b/arch/x86/kvm/vmx/nested.c
> @@ -4959,7 +4959,7 @@ int get_vmx_mem_address(struct kvm_vcpu *vcpu, unsigned long exit_qualification,
>  
>  	/* Checks for #GP/#SS exceptions. */
>  	exn = false;
> -	if (is_long_mode(vcpu)) {
> +	if (is_64_bit_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
> diff --git a/arch/x86/kvm/vmx/sgx.c b/arch/x86/kvm/vmx/sgx.c
> index aa53c98034bf..0574030b071f 100644
> --- a/arch/x86/kvm/vmx/sgx.c
> +++ b/arch/x86/kvm/vmx/sgx.c
> @@ -29,14 +29,14 @@ static int sgx_get_encls_gva(struct kvm_vcpu *vcpu, unsigned long offset,
>  
>  	/* Skip vmcs.GUEST_DS retrieval for 64-bit mode to avoid VMREADs. */
>  	*gva = offset;
> -	if (!is_long_mode(vcpu)) {
> +	if (!is_64_bit_mode(vcpu)) {
>  		vmx_get_segment(vcpu, &s, VCPU_SREG_DS);
>  		*gva += s.base;
>  	}
>  
>  	if (!IS_ALIGNED(*gva, alignment)) {
>  		fault = true;
> -	} else if (likely(is_long_mode(vcpu))) {
> +	} else if (likely(is_64_bit_mode(vcpu))) {
>  		fault = is_noncanonical_address(*gva, vcpu);
>  	} else {
>  		*gva &= 0xffffffff;

For SGX part,

Reviewed-by: Kai Huang <kai.huang@intel.com>
Sean Christopherson March 21, 2023, 9:35 p.m. UTC | #4
On Mon, Mar 20, 2023, Chao Gao wrote:
> On Sun, Mar 19, 2023 at 04:49:22PM +0800, Binbin Wu wrote:
> >get_vmx_mem_address() and sgx_get_encls_gva() use is_long_mode()
> >to check 64-bit mode. Should use is_64_bit_mode() instead.
> >
> >Fixes: f9eb4af67c9d ("KVM: nVMX: VMX instructions: add checks for #GP/#SS exceptions")
> >Fixes: 70210c044b4e ("KVM: VMX: Add SGX ENCLS[ECREATE] handler to enforce CPUID restrictions")
> 
> It is better to split this patch into two: one for nested and one for
> SGX.
> 
> It is possible that there is a kernel release which has just one of
> above two flawed commits, then this fix patch cannot be applied cleanly
> to the release.

The nVMX code isn't buggy, VMX instructions #UD in compatibility mode, and except
for VMCALL, that #UD has higher priority than VM-Exit interception.  So I'd say
just drop the nVMX side of things.

I could have sworn ENCLS had the same behavior, but the SDM disagrees.  Though why
on earth ENCLS is allowed in compatibility mode is beyond me.  ENCLU I can kinda
sorta understand, but ENCLS?!?!!
Binbin Wu March 22, 2023, 1:09 a.m. UTC | #5
On 3/22/2023 5:35 AM, Sean Christopherson wrote:
> On Mon, Mar 20, 2023, Chao Gao wrote:
>> On Sun, Mar 19, 2023 at 04:49:22PM +0800, Binbin Wu wrote:
>>> get_vmx_mem_address() and sgx_get_encls_gva() use is_long_mode()
>>> to check 64-bit mode. Should use is_64_bit_mode() instead.
>>>
>>> Fixes: f9eb4af67c9d ("KVM: nVMX: VMX instructions: add checks for #GP/#SS exceptions")
>>> Fixes: 70210c044b4e ("KVM: VMX: Add SGX ENCLS[ECREATE] handler to enforce CPUID restrictions")
>> It is better to split this patch into two: one for nested and one for
>> SGX.
>>
>> It is possible that there is a kernel release which has just one of
>> above two flawed commits, then this fix patch cannot be applied cleanly
>> to the release.
> The nVMX code isn't buggy, VMX instructions #UD in compatibility mode, and except
> for VMCALL, that #UD has higher priority than VM-Exit interception.  So I'd say
> just drop the nVMX side of things.

Got it.
Do you mind if I add a comment about it in code?


>
> I could have sworn ENCLS had the same behavior, but the SDM disagrees.  Though why
> on earth ENCLS is allowed in compatibility mode is beyond me.  ENCLU I can kinda
> sorta understand, but ENCLS?!?!!

Yes, the SDM does have definition about the behavior "outside 64-bit 
mode (IA32_EFER.LAM = 0 || CS.L = 0)".

IMO, the change has very little impact on performance since the two 
intercepted ENCLS leaf EINIT & ECREATE will
only be called once per lifecycle of a SGX Enclave.
Huang, Kai March 28, 2023, 11:33 p.m. UTC | #6
On Tue, 2023-03-21 at 14:35 -0700, Sean Christopherson wrote:
> On Mon, Mar 20, 2023, Chao Gao wrote:
> > On Sun, Mar 19, 2023 at 04:49:22PM +0800, Binbin Wu wrote:
> > > get_vmx_mem_address() and sgx_get_encls_gva() use is_long_mode()
> > > to check 64-bit mode. Should use is_64_bit_mode() instead.
> > > 
> > > Fixes: f9eb4af67c9d ("KVM: nVMX: VMX instructions: add checks for #GP/#SS exceptions")
> > > Fixes: 70210c044b4e ("KVM: VMX: Add SGX ENCLS[ECREATE] handler to enforce CPUID restrictions")
> > 
> > It is better to split this patch into two: one for nested and one for
> > SGX.
> > 
> > It is possible that there is a kernel release which has just one of
> > above two flawed commits, then this fix patch cannot be applied cleanly
> > to the release.
> 
> The nVMX code isn't buggy, VMX instructions #UD in compatibility mode, and except
> for VMCALL, that #UD has higher priority than VM-Exit interception.  So I'd say
> just drop the nVMX side of things.

But it looks the old code doesn't unconditionally inject #UD when in
compatibility mode?

        /* Checks for #GP/#SS exceptions. */                                   
        exn = false;                                                           
        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.              
                 */                                                            
                if (seg_reg == VCPU_SREG_FS || seg_reg == VCPU_SREG_GS)        
                        *ret = s.base + off;                                   
                else                                                           
                        *ret = off;                                            
                                                                                                                                                   
                /* Long mode: #GP(0)/#SS(0) if the memory address is in a      
                 * non-canonical form. This is the only check on the memory    
                 * destination for long mode!                                  
                 */                                                            
                exn = is_noncanonical_address(*ret, vcpu); 
	}
	...

The logic of only adding seg.base for FS/GS to linear address (and ignoring
seg.base for all other segs) only applies to 64 bit mode, but the code only
checks _long_ mode.

Am I missing something?
 
> 
> I could have sworn ENCLS had the same behavior, but the SDM disagrees.  Though why
> on earth ENCLS is allowed in compatibility mode is beyond me.  ENCLU I can kinda
> sorta understand, but ENCLS?!?!!

I can reach out to Intel guys to (try to) find the answer if you want me to? :)
Binbin Wu March 29, 2023, 1:27 a.m. UTC | #7
On 3/29/2023 7:33 AM, Huang, Kai wrote:
> On Tue, 2023-03-21 at 14:35 -0700, Sean Christopherson wrote:
>> On Mon, Mar 20, 2023, Chao Gao wrote:
>>> On Sun, Mar 19, 2023 at 04:49:22PM +0800, Binbin Wu wrote:
>>>> get_vmx_mem_address() and sgx_get_encls_gva() use is_long_mode()
>>>> to check 64-bit mode. Should use is_64_bit_mode() instead.
>>>>
>>>> Fixes: f9eb4af67c9d ("KVM: nVMX: VMX instructions: add checks for #GP/#SS exceptions")
>>>> Fixes: 70210c044b4e ("KVM: VMX: Add SGX ENCLS[ECREATE] handler to enforce CPUID restrictions")
>>> It is better to split this patch into two: one for nested and one for
>>> SGX.
>>>
>>> It is possible that there is a kernel release which has just one of
>>> above two flawed commits, then this fix patch cannot be applied cleanly
>>> to the release.
>> The nVMX code isn't buggy, VMX instructions #UD in compatibility mode, and except
>> for VMCALL, that #UD has higher priority than VM-Exit interception.  So I'd say
>> just drop the nVMX side of things.
> But it looks the old code doesn't unconditionally inject #UD when in
> compatibility mode?

I think Sean means VMX instructions is not valid in compatibility mode 
and it triggers #UD, which has higher priority than VM-Exit, by the 
processor in non-root mode.

So if there is a VM-Exit due to VMX instruction , it is in 64-bit mode 
for sure if it is in long mode.


>
>          /* Checks for #GP/#SS exceptions. */
>          exn = false;
>          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.
>                   */
>                  if (seg_reg == VCPU_SREG_FS || seg_reg == VCPU_SREG_GS)
>                          *ret = s.base + off;
>                  else
>                          *ret = off;
>                                                                                                                                                     
>                  /* Long mode: #GP(0)/#SS(0) if the memory address is in a
>                   * non-canonical form. This is the only check on the memory
>                   * destination for long mode!
>                   */
>                  exn = is_noncanonical_address(*ret, vcpu);
> 	}
> 	...
>
> The logic of only adding seg.base for FS/GS to linear address (and ignoring
> seg.base for all other segs) only applies to 64 bit mode, but the code only
> checks _long_ mode.
>
> Am I missing something?
>   
>> I could have sworn ENCLS had the same behavior, but the SDM disagrees.  Though why
>> on earth ENCLS is allowed in compatibility mode is beyond me.  ENCLU I can kinda
>> sorta understand, but ENCLS?!?!!
> I can reach out to Intel guys to (try to) find the answer if you want me to? :)
Huang, Kai March 29, 2023, 2:04 a.m. UTC | #8
On Wed, 2023-03-29 at 09:27 +0800, Binbin Wu wrote:
> On 3/29/2023 7:33 AM, Huang, Kai wrote:
> > On Tue, 2023-03-21 at 14:35 -0700, Sean Christopherson wrote:
> > > On Mon, Mar 20, 2023, Chao Gao wrote:
> > > > On Sun, Mar 19, 2023 at 04:49:22PM +0800, Binbin Wu wrote:
> > > > > get_vmx_mem_address() and sgx_get_encls_gva() use is_long_mode()
> > > > > to check 64-bit mode. Should use is_64_bit_mode() instead.
> > > > > 
> > > > > Fixes: f9eb4af67c9d ("KVM: nVMX: VMX instructions: add checks for #GP/#SS exceptions")
> > > > > Fixes: 70210c044b4e ("KVM: VMX: Add SGX ENCLS[ECREATE] handler to enforce CPUID restrictions")
> > > > It is better to split this patch into two: one for nested and one for
> > > > SGX.
> > > > 
> > > > It is possible that there is a kernel release which has just one of
> > > > above two flawed commits, then this fix patch cannot be applied cleanly
> > > > to the release.
> > > The nVMX code isn't buggy, VMX instructions #UD in compatibility mode, and except
> > > for VMCALL, that #UD has higher priority than VM-Exit interception.  So I'd say
> > > just drop the nVMX side of things.
> > But it looks the old code doesn't unconditionally inject #UD when in
> > compatibility mode?
> 
> I think Sean means VMX instructions is not valid in compatibility mode 
> and it triggers #UD, which has higher priority than VM-Exit, by the 
> processor in non-root mode.
> 
> So if there is a VM-Exit due to VMX instruction , it is in 64-bit mode 
> for sure if it is in long mode.

Oh I see thanks.

Then is it better to add some comment to explain, or add a WARN() if it's not in
64-bit mode?
Binbin Wu March 29, 2023, 2:08 a.m. UTC | #9
On 3/29/2023 10:04 AM, Huang, Kai wrote:
> On Wed, 2023-03-29 at 09:27 +0800, Binbin Wu wrote:
>> On 3/29/2023 7:33 AM, Huang, Kai wrote:
>>> On Tue, 2023-03-21 at 14:35 -0700, Sean Christopherson wrote:
>>>> On Mon, Mar 20, 2023, Chao Gao wrote:
>>>>> On Sun, Mar 19, 2023 at 04:49:22PM +0800, Binbin Wu wrote:
>>>>>> get_vmx_mem_address() and sgx_get_encls_gva() use is_long_mode()
>>>>>> to check 64-bit mode. Should use is_64_bit_mode() instead.
>>>>>>
>>>>>> Fixes: f9eb4af67c9d ("KVM: nVMX: VMX instructions: add checks for #GP/#SS exceptions")
>>>>>> Fixes: 70210c044b4e ("KVM: VMX: Add SGX ENCLS[ECREATE] handler to enforce CPUID restrictions")
>>>>> It is better to split this patch into two: one for nested and one for
>>>>> SGX.
>>>>>
>>>>> It is possible that there is a kernel release which has just one of
>>>>> above two flawed commits, then this fix patch cannot be applied cleanly
>>>>> to the release.
>>>> The nVMX code isn't buggy, VMX instructions #UD in compatibility mode, and except
>>>> for VMCALL, that #UD has higher priority than VM-Exit interception.  So I'd say
>>>> just drop the nVMX side of things.
>>> But it looks the old code doesn't unconditionally inject #UD when in
>>> compatibility mode?
>> I think Sean means VMX instructions is not valid in compatibility mode
>> and it triggers #UD, which has higher priority than VM-Exit, by the
>> processor in non-root mode.
>>
>> So if there is a VM-Exit due to VMX instruction , it is in 64-bit mode
>> for sure if it is in long mode.
> Oh I see thanks.
>
> Then is it better to add some comment to explain, or add a WARN() if it's not in
> 64-bit mode?

I also prefer to add a comment if no objection.

Seems I am not the only one who didn't get it  : )

>
Sean Christopherson March 29, 2023, 5:34 p.m. UTC | #10
On Wed, Mar 29, 2023, Binbin Wu wrote:
> 
> On 3/29/2023 10:04 AM, Huang, Kai wrote:
> > On Wed, 2023-03-29 at 09:27 +0800, Binbin Wu wrote:
> > > On 3/29/2023 7:33 AM, Huang, Kai wrote:
> > > > On Tue, 2023-03-21 at 14:35 -0700, Sean Christopherson wrote:
> > > > > On Mon, Mar 20, 2023, Chao Gao wrote:
> > > > > > On Sun, Mar 19, 2023 at 04:49:22PM +0800, Binbin Wu wrote:
> > > > > > > get_vmx_mem_address() and sgx_get_encls_gva() use is_long_mode()
> > > > > > > to check 64-bit mode. Should use is_64_bit_mode() instead.
> > > > > > > 
> > > > > > > Fixes: f9eb4af67c9d ("KVM: nVMX: VMX instructions: add checks for #GP/#SS exceptions")
> > > > > > > Fixes: 70210c044b4e ("KVM: VMX: Add SGX ENCLS[ECREATE] handler to enforce CPUID restrictions")
> > > > > > It is better to split this patch into two: one for nested and one for
> > > > > > SGX.
> > > > > > 
> > > > > > It is possible that there is a kernel release which has just one of
> > > > > > above two flawed commits, then this fix patch cannot be applied cleanly
> > > > > > to the release.
> > > > > The nVMX code isn't buggy, VMX instructions #UD in compatibility mode, and except
> > > > > for VMCALL, that #UD has higher priority than VM-Exit interception.  So I'd say
> > > > > just drop the nVMX side of things.
> > > > But it looks the old code doesn't unconditionally inject #UD when in
> > > > compatibility mode?
> > > I think Sean means VMX instructions is not valid in compatibility mode
> > > and it triggers #UD, which has higher priority than VM-Exit, by the
> > > processor in non-root mode.
> > > 
> > > So if there is a VM-Exit due to VMX instruction , it is in 64-bit mode
> > > for sure if it is in long mode.
> > Oh I see thanks.
> > 
> > Then is it better to add some comment to explain, or add a WARN() if it's not in
> > 64-bit mode?
> 
> I also prefer to add a comment if no objection.
> 
> Seems I am not the only one who didn't get it� : )

I would rather have a code change than a comment, e.g. 

diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
index f63b28f46a71..0460ca219f96 100644
--- a/arch/x86/kvm/vmx/nested.c
+++ b/arch/x86/kvm/vmx/nested.c
@@ -4931,7 +4931,8 @@ int get_vmx_mem_address(struct kvm_vcpu *vcpu, unsigned long exit_qualification,
        int  base_reg       = (vmx_instruction_info >> 23) & 0xf;
        bool base_is_valid  = !(vmx_instruction_info & (1u << 27));
 
-       if (is_reg) {
+       if (is_reg ||
+           WARN_ON_ONCE(is_long_mode(vcpu) && !is_64_bit_mode(vcpu))) {
                kvm_queue_exception(vcpu, UD_VECTOR);
                return 1;
        }


The only downside is that querying is_64_bit_mode() could unnecessarily trigger a
VMREAD to get the current CS.L bit, but a measurable performance regressions is
extremely unlikely because is_64_bit_mode() all but guaranteed to be called in
these paths anyways (and KVM caches segment info), e.g. by kvm_register_read().

And then in a follow-up, we should also be able to do:

@@ -5402,7 +5403,7 @@ static int handle_vmread(struct kvm_vcpu *vcpu)
        if (instr_info & BIT(10)) {
                kvm_register_write(vcpu, (((instr_info) >> 3) & 0xf), value);
        } else {
-               len = is_64_bit_mode(vcpu) ? 8 : 4;
+               len = is_long_mode(vcpu) ? 8 : 4;
                if (get_vmx_mem_address(vcpu, exit_qualification,
                                        instr_info, true, len, &gva))
                        return 1;
@@ -5476,7 +5477,7 @@ static int handle_vmwrite(struct kvm_vcpu *vcpu)
        if (instr_info & BIT(10))
                value = kvm_register_read(vcpu, (((instr_info) >> 3) & 0xf));
        else {
-               len = is_64_bit_mode(vcpu) ? 8 : 4;
+               len = is_long_mode(vcpu) ? 8 : 4;
                if (get_vmx_mem_address(vcpu, exit_qualification,
                                        instr_info, false, len, &gva))
                        return 1;
Huang, Kai March 29, 2023, 10:46 p.m. UTC | #11
On Wed, 2023-03-29 at 10:34 -0700, Sean Christopherson wrote:
> On Wed, Mar 29, 2023, Binbin Wu wrote:
> > 
> > On 3/29/2023 10:04 AM, Huang, Kai wrote:
> > > On Wed, 2023-03-29 at 09:27 +0800, Binbin Wu wrote:
> > > > On 3/29/2023 7:33 AM, Huang, Kai wrote:
> > > > > On Tue, 2023-03-21 at 14:35 -0700, Sean Christopherson wrote:
> > > > > > On Mon, Mar 20, 2023, Chao Gao wrote:
> > > > > > > On Sun, Mar 19, 2023 at 04:49:22PM +0800, Binbin Wu wrote:
> > > > > > > > get_vmx_mem_address() and sgx_get_encls_gva() use is_long_mode()
> > > > > > > > to check 64-bit mode. Should use is_64_bit_mode() instead.
> > > > > > > > 
> > > > > > > > Fixes: f9eb4af67c9d ("KVM: nVMX: VMX instructions: add checks for #GP/#SS exceptions")
> > > > > > > > Fixes: 70210c044b4e ("KVM: VMX: Add SGX ENCLS[ECREATE] handler to enforce CPUID restrictions")
> > > > > > > It is better to split this patch into two: one for nested and one for
> > > > > > > SGX.
> > > > > > > 
> > > > > > > It is possible that there is a kernel release which has just one of
> > > > > > > above two flawed commits, then this fix patch cannot be applied cleanly
> > > > > > > to the release.
> > > > > > The nVMX code isn't buggy, VMX instructions #UD in compatibility mode, and except
> > > > > > for VMCALL, that #UD has higher priority than VM-Exit interception.  So I'd say
> > > > > > just drop the nVMX side of things.
> > > > > But it looks the old code doesn't unconditionally inject #UD when in
> > > > > compatibility mode?
> > > > I think Sean means VMX instructions is not valid in compatibility mode
> > > > and it triggers #UD, which has higher priority than VM-Exit, by the
> > > > processor in non-root mode.
> > > > 
> > > > So if there is a VM-Exit due to VMX instruction , it is in 64-bit mode
> > > > for sure if it is in long mode.
> > > Oh I see thanks.
> > > 
> > > Then is it better to add some comment to explain, or add a WARN() if it's not in
> > > 64-bit mode?
> > 
> > I also prefer to add a comment if no objection.
> > 
> > Seems I am not the only one who didn't get it� : )
> 
> I would rather have a code change than a comment, e.g. 
> 
> diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
> index f63b28f46a71..0460ca219f96 100644
> --- a/arch/x86/kvm/vmx/nested.c
> +++ b/arch/x86/kvm/vmx/nested.c
> @@ -4931,7 +4931,8 @@ int get_vmx_mem_address(struct kvm_vcpu *vcpu, unsigned long exit_qualification,
>         int  base_reg       = (vmx_instruction_info >> 23) & 0xf;
>         bool base_is_valid  = !(vmx_instruction_info & (1u << 27));
>  
> -       if (is_reg) {
> +       if (is_reg ||
> +           WARN_ON_ONCE(is_long_mode(vcpu) && !is_64_bit_mode(vcpu))) {
>                 kvm_queue_exception(vcpu, UD_VECTOR);
>                 return 1;
>         }
> 
> 

Looks good to me.

> The only downside is that querying is_64_bit_mode() could unnecessarily trigger a
> VMREAD to get the current CS.L bit, but a measurable performance regressions is
> extremely unlikely because is_64_bit_mode() all but guaranteed to be called in
> these paths anyways (and KVM caches segment info), e.g. by kvm_register_read().

Agreed.

> 
> And then in a follow-up, we should also be able to do:
> 
> @@ -5402,7 +5403,7 @@ static int handle_vmread(struct kvm_vcpu *vcpu)
>         if (instr_info & BIT(10)) {
>                 kvm_register_write(vcpu, (((instr_info) >> 3) & 0xf), value);
>         } else {
> -               len = is_64_bit_mode(vcpu) ? 8 : 4;
> +               len = is_long_mode(vcpu) ? 8 : 4;
>                 if (get_vmx_mem_address(vcpu, exit_qualification,
>                                         instr_info, true, len, &gva))
>                         return 1;
> @@ -5476,7 +5477,7 @@ static int handle_vmwrite(struct kvm_vcpu *vcpu)
>         if (instr_info & BIT(10))
>                 value = kvm_register_read(vcpu, (((instr_info) >> 3) & 0xf));
>         else {
> -               len = is_64_bit_mode(vcpu) ? 8 : 4;
> +               len = is_long_mode(vcpu) ? 8 : 4;
>                 if (get_vmx_mem_address(vcpu, exit_qualification,
>                                         instr_info, false, len, &gva))
>                         return 1;
> 

Yeah, although it's a little bit wired the actual WARN() happens after above
code change.  But I don't know how to make the code better.  Maybe we should put
the WARN() at the very beginning but this would require duplicated code in each
handle_xxx() for VMX instructions.
Binbin Wu April 3, 2023, 3:37 a.m. UTC | #12
On 3/30/2023 6:46 AM, Huang, Kai wrote:
> On Wed, 2023-03-29 at 10:34 -0700, Sean Christopherson wrote:
>> On Wed, Mar 29, 2023, Binbin Wu wrote:
>>> On 3/29/2023 10:04 AM, Huang, Kai wrote:
>>>> On Wed, 2023-03-29 at 09:27 +0800, Binbin Wu wrote:
>>>>> On 3/29/2023 7:33 AM, Huang, Kai wrote:
>>>>>> On Tue, 2023-03-21 at 14:35 -0700, Sean Christopherson wrote:
>>>>>>> On Mon, Mar 20, 2023, Chao Gao wrote:
>>>>>>>> On Sun, Mar 19, 2023 at 04:49:22PM +0800, Binbin Wu wrote:
>>>>>>>>> get_vmx_mem_address() and sgx_get_encls_gva() use is_long_mode()
>>>>>>>>> to check 64-bit mode. Should use is_64_bit_mode() instead.
>>>>>>>>>
>>>>>>>>> Fixes: f9eb4af67c9d ("KVM: nVMX: VMX instructions: add checks for #GP/#SS exceptions")
>>>>>>>>> Fixes: 70210c044b4e ("KVM: VMX: Add SGX ENCLS[ECREATE] handler to enforce CPUID restrictions")
>>>>>>>> It is better to split this patch into two: one for nested and one for
>>>>>>>> SGX.
>>>>>>>>
>>>>>>>> It is possible that there is a kernel release which has just one of
>>>>>>>> above two flawed commits, then this fix patch cannot be applied cleanly
>>>>>>>> to the release.
>>>>>>> The nVMX code isn't buggy, VMX instructions #UD in compatibility mode, and except
>>>>>>> for VMCALL, that #UD has higher priority than VM-Exit interception.  So I'd say
>>>>>>> just drop the nVMX side of things.
>>>>>> But it looks the old code doesn't unconditionally inject #UD when in
>>>>>> compatibility mode?
>>>>> I think Sean means VMX instructions is not valid in compatibility mode
>>>>> and it triggers #UD, which has higher priority than VM-Exit, by the
>>>>> processor in non-root mode.
>>>>>
>>>>> So if there is a VM-Exit due to VMX instruction , it is in 64-bit mode
>>>>> for sure if it is in long mode.
>>>> Oh I see thanks.
>>>>
>>>> Then is it better to add some comment to explain, or add a WARN() if it's not in
>>>> 64-bit mode?
>>> I also prefer to add a comment if no objection.
>>>
>>> Seems I am not the only one who didn't get it� : )
>> I would rather have a code change than a comment, e.g.
>>
>> diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
>> index f63b28f46a71..0460ca219f96 100644
>> --- a/arch/x86/kvm/vmx/nested.c
>> +++ b/arch/x86/kvm/vmx/nested.c
>> @@ -4931,7 +4931,8 @@ int get_vmx_mem_address(struct kvm_vcpu *vcpu, unsigned long exit_qualification,
>>          int  base_reg       = (vmx_instruction_info >> 23) & 0xf;
>>          bool base_is_valid  = !(vmx_instruction_info & (1u << 27));
>>   
>> -       if (is_reg) {
>> +       if (is_reg ||
>> +           WARN_ON_ONCE(is_long_mode(vcpu) && !is_64_bit_mode(vcpu))) {
>>                  kvm_queue_exception(vcpu, UD_VECTOR);
>>                  return 1;
>>          }
>>
>>
> Looks good to me.
>
>> The only downside is that querying is_64_bit_mode() could unnecessarily trigger a
>> VMREAD to get the current CS.L bit, but a measurable performance regressions is
>> extremely unlikely because is_64_bit_mode() all but guaranteed to be called in
>> these paths anyways (and KVM caches segment info), e.g. by kvm_register_read().
> Agreed.
>
>> And then in a follow-up, we should also be able to do:
>>
>> @@ -5402,7 +5403,7 @@ static int handle_vmread(struct kvm_vcpu *vcpu)
>>          if (instr_info & BIT(10)) {
>>                  kvm_register_write(vcpu, (((instr_info) >> 3) & 0xf), value);
>>          } else {
>> -               len = is_64_bit_mode(vcpu) ? 8 : 4;
>> +               len = is_long_mode(vcpu) ? 8 : 4;
>>                  if (get_vmx_mem_address(vcpu, exit_qualification,
>>                                          instr_info, true, len, &gva))
>>                          return 1;
>> @@ -5476,7 +5477,7 @@ static int handle_vmwrite(struct kvm_vcpu *vcpu)
>>          if (instr_info & BIT(10))
>>                  value = kvm_register_read(vcpu, (((instr_info) >> 3) & 0xf));
>>          else {
>> -               len = is_64_bit_mode(vcpu) ? 8 : 4;
>> +               len = is_long_mode(vcpu) ? 8 : 4;
>>                  if (get_vmx_mem_address(vcpu, exit_qualification,
>>                                          instr_info, false, len, &gva))
>>                          return 1;
>>
> Yeah, although it's a little bit wired the actual WARN() happens after above
> code change.  But I don't know how to make the code better.  Maybe we should put
> the WARN() at the very beginning but this would require duplicated code in each
> handle_xxx() for VMX instructions.

I checked the code again and find the comment of 
nested_vmx_check_permission().

"/*
  * Intel's VMX Instruction Reference specifies a common set of 
prerequisites
  * for running VMX instructions (except VMXON, whose prerequisites are
  * slightly different). It also specifies what exception to inject 
otherwise.
  * Note that many of these exceptions have priority over VM exits, so they
  * don't have to be checked again here.
  */"

I think the Note part in the comment has tried to callout why the check 
for compatibility mode is unnecessary.

But I have a question here, nested_vmx_check_permission() checks that 
the vcpu is vmxon,
otherwise it will inject a #UD. Why this #UD is handled in the VMExit 
handler specifically?
Not all #UDs have higher priority than VM exits?

According to SDM Section "Relative Priority of Faults and VM Exits":
"Certain exceptions have priority over VM exits. These include 
invalid-opcode exceptions, ..."
Seems not further classifications of #UDs.

Anyway, I will seperate this patch from the LAM KVM enabling patch. And 
send a patch seperately if
needed later.
Huang, Kai April 3, 2023, 11:24 a.m. UTC | #13
> 
> I checked the code again and find the comment of 
> nested_vmx_check_permission().
> 
> "/*
>   * Intel's VMX Instruction Reference specifies a common set of 
> prerequisites
>   * for running VMX instructions (except VMXON, whose prerequisites are
>   * slightly different). It also specifies what exception to inject 
> otherwise.
>   * Note that many of these exceptions have priority over VM exits, so they
>   * don't have to be checked again here.
>   */"
> 
> I think the Note part in the comment has tried to callout why the check 
> for compatibility mode is unnecessary.
> 
> But I have a question here, nested_vmx_check_permission() checks that 
> the vcpu is vmxon,
> otherwise it will inject a #UD. Why this #UD is handled in the VMExit 
> handler specifically?
> Not all #UDs have higher priority than VM exits?
> 
> According to SDM Section "Relative Priority of Faults and VM Exits":
> "Certain exceptions have priority over VM exits. These include 
> invalid-opcode exceptions, ..."
> Seems not further classifications of #UDs.

This is clarified in the pseudo code of VMX instructions in the SDM.  If you
look at the pseudo code, all VMX instructions except VMXON (obviously) have
something like below:

	IF (not in VMX operation) ...
		THEN #UD;
	ELSIF in VMX non-root operation
		THEN VMexit;

So to me "this particular" #UD has higher priority over VM exits (while other
#UDs may not).

But IIUC above #UD won't happen when running VMX instruction in the guest,
because if there's any live guest, the CPU must already have been in VMX
operation.  So below check in nested_vmx_check_permission():

	if (!to_vmx(vcpu)->nested.vmxon) {                                            
                kvm_queue_exception(vcpu, UD_VECTOR);                          
                return 0;                                                      
        }

is needed to emulate the case that guest runs any other VMX instructions before
VMXON.

> 
> Anyway, I will seperate this patch from the LAM KVM enabling patch. And 
> send a patch seperately if
> needed later.
> 

I think your change for SGX is still needed based on the pseudo code of ENCLS.
Sean Christopherson April 3, 2023, 3:02 p.m. UTC | #14
On Mon, Apr 03, 2023, Huang, Kai wrote:
> > 
> > I checked the code again and find the comment of 
> > nested_vmx_check_permission().
> > 
> > "/*
> >  �* Intel's VMX Instruction Reference specifies a common set of 
> > prerequisites
> >  �* for running VMX instructions (except VMXON, whose prerequisites are
> >  �* slightly different). It also specifies what exception to inject 
> > otherwise.
> >  �* Note that many of these exceptions have priority over VM exits, so they
> >  �* don't have to be checked again here.
> >  �*/"
> > 
> > I think the Note part in the comment has tried to callout why the check 
> > for compatibility mode is unnecessary.
> > 
> > But I have a question here, nested_vmx_check_permission() checks that the
> > vcpu is vmxon, otherwise it will inject a #UD. Why this #UD is handled in
> > the VMExit handler specifically?  Not all #UDs have higher priority than VM
> > exits?
> > 
> > According to SDM Section "Relative Priority of Faults and VM Exits":
> > "Certain exceptions have priority over VM exits. These include 
> > invalid-opcode exceptions, ..."
> > Seems not further classifications of #UDs.
> 
> This is clarified in the pseudo code of VMX instructions in the SDM.  If you
> look at the pseudo code, all VMX instructions except VMXON (obviously) have
> something like below:
> 
> 	IF (not in VMX operation) ...
> 		THEN #UD;
> 	ELSIF in VMX non-root operation
> 		THEN VMexit;
> 
> So to me "this particular" #UD has higher priority over VM exits (while other
> #UDs may not).

> But IIUC above #UD won't happen when running VMX instruction in the guest,
> because if there's any live guest, the CPU must already have been in VMX
> operation.  So below check in nested_vmx_check_permission():
> 
> 	if (!to_vmx(vcpu)->nested.vmxon) {                                            
>                 kvm_queue_exception(vcpu, UD_VECTOR);                          
>                 return 0;                                                      
>         }
> 
> is needed to emulate the case that guest runs any other VMX instructions before
> VMXON.

Yep.  IMO, the pseucode is misleading/confusing, the "in VMX non-root operation"
check should really come first.  The VMXON pseudocode has the same awkward
sequence:

    IF (register operand) or (CR0.PE = 0) or (CR4.VMXE = 0) or ...
        THEN #UD;
    ELSIF not in VMX operation
        THEN
            IF (CPL > 0) or (in A20M mode) or
            (the values of CR0 and CR4 are not supported in VMX operation)
                THEN #GP(0);
    ELSIF in VMX non-root operation
        THEN VMexit;
    ELSIF CPL > 0
        THEN #GP(0);
    ELSE VMfail("VMXON executed in VMX root operation");
    FI;


whereas I find this sequence for VMXON more representative of what actually happens:

    IF (register operand) or (CR0.PE = 0) or (CR4.VMXE = 0) or ...
        THEN #UD

    IF in VMX non-root operation
        THEN VMexit;

    IF CPL > 0
        THEN #GP(0)

    IF in VMX operation
        THEN VMfail("VMXON executed in VMX root operation");

    IF (in A20M mode) or
       (the values of CR0 and CR4 are not supported in VMX operation)
        THEN #GP(0);

> > Anyway, I will seperate this patch from the LAM KVM enabling patch. And 
> > send a patch seperately if needed later.
> 
> I think your change for SGX is still needed based on the pseudo code of ENCLS.

Agreed.
Huang, Kai April 3, 2023, 11:13 p.m. UTC | #15
On Mon, 2023-04-03 at 08:02 -0700, Sean Christopherson wrote:
> On Mon, Apr 03, 2023, Huang, Kai wrote:
> > > 
> > > I checked the code again and find the comment of 
> > > nested_vmx_check_permission().
> > > 
> > > "/*
> > >  �* Intel's VMX Instruction Reference specifies a common set of 
> > > prerequisites
> > >  �* for running VMX instructions (except VMXON, whose prerequisites are
> > >  �* slightly different). It also specifies what exception to inject 
> > > otherwise.
> > >  �* Note that many of these exceptions have priority over VM exits, so they
> > >  �* don't have to be checked again here.
> > >  �*/"
> > > 
> > > I think the Note part in the comment has tried to callout why the check 
> > > for compatibility mode is unnecessary.
> > > 
> > > But I have a question here, nested_vmx_check_permission() checks that the
> > > vcpu is vmxon, otherwise it will inject a #UD. Why this #UD is handled in
> > > the VMExit handler specifically?  Not all #UDs have higher priority than VM
> > > exits?
> > > 
> > > According to SDM Section "Relative Priority of Faults and VM Exits":
> > > "Certain exceptions have priority over VM exits. These include 
> > > invalid-opcode exceptions, ..."
> > > Seems not further classifications of #UDs.
> > 
> > This is clarified in the pseudo code of VMX instructions in the SDM.  If you
> > look at the pseudo code, all VMX instructions except VMXON (obviously) have
> > something like below:
> > 
> > 	IF (not in VMX operation) ...
> > 		THEN #UD;
> > 	ELSIF in VMX non-root operation
> > 		THEN VMexit;
> > 
> > So to me "this particular" #UD has higher priority over VM exits (while other
> > #UDs may not).
> 
> > But IIUC above #UD won't happen when running VMX instruction in the guest,
> > because if there's any live guest, the CPU must already have been in VMX
> > operation.  So below check in nested_vmx_check_permission():
> > 
> > 	if (!to_vmx(vcpu)->nested.vmxon) {                                            
> >                 kvm_queue_exception(vcpu, UD_VECTOR);                          
> >                 return 0;                                                      
> >         }
> > 
> > is needed to emulate the case that guest runs any other VMX instructions before
> > VMXON.
> 
> Yep.  IMO, the pseucode is misleading/confusing, the "in VMX non-root operation"
> check should really come first.  The VMXON pseudocode has the same awkward
> sequence:
> 
>     IF (register operand) or (CR0.PE = 0) or (CR4.VMXE = 0) or ...
>         THEN #UD;
>     ELSIF not in VMX operation
>         THEN
>             IF (CPL > 0) or (in A20M mode) or
>             (the values of CR0 and CR4 are not supported in VMX operation)
>                 THEN #GP(0);
>     ELSIF in VMX non-root operation
>         THEN VMexit;
>     ELSIF CPL > 0
>         THEN #GP(0);
>     ELSE VMfail("VMXON executed in VMX root operation");
>     FI;
> 
> 
> whereas I find this sequence for VMXON more representative of what actually happens:
> 
>     IF (register operand) or (CR0.PE = 0) or (CR4.VMXE = 0) or ...
>         THEN #UD
> 
>     IF in VMX non-root operation
>         THEN VMexit;
> 
>     IF CPL > 0
>         THEN #GP(0)
> 
>     IF in VMX operation
>         THEN VMfail("VMXON executed in VMX root operation");
> 
>     IF (in A20M mode) or
>        (the values of CR0 and CR4 are not supported in VMX operation)
>         THEN #GP(0);

Perhaps we need to live with the fact that the pseudo code in the SDM can be
buggy :)
Binbin Wu April 4, 2023, 1:21 a.m. UTC | #16
On 4/3/2023 7:24 PM, Huang, Kai wrote:
>>
>>
>> Anyway, I will seperate this patch from the LAM KVM enabling patch. And
>> send a patch seperately if
>> needed later.
>>
> I think your change for SGX is still needed based on the pseudo code of ENCLS.

Yes, I meant I would seperate VMX part since it is not a bug after all, 
SGX will still be in the patchset.


>
Binbin Wu April 4, 2023, 1:31 a.m. UTC | #17
On 4/3/2023 7:24 PM, Huang, Kai wrote:
>> I checked the code again and find the comment of
>> nested_vmx_check_permission().
>>
>> "/*
>>    * Intel's VMX Instruction Reference specifies a common set of
>> prerequisites
>>    * for running VMX instructions (except VMXON, whose prerequisites are
>>    * slightly different). It also specifies what exception to inject
>> otherwise.
>>    * Note that many of these exceptions have priority over VM exits, so they
>>    * don't have to be checked again here.
>>    */"
>>
>> I think the Note part in the comment has tried to callout why the check
>> for compatibility mode is unnecessary.
>>
>> But I have a question here, nested_vmx_check_permission() checks that
>> the vcpu is vmxon,
>> otherwise it will inject a #UD. Why this #UD is handled in the VMExit
>> handler specifically?
>> Not all #UDs have higher priority than VM exits?
>>
>> According to SDM Section "Relative Priority of Faults and VM Exits":
>> "Certain exceptions have priority over VM exits. These include
>> invalid-opcode exceptions, ..."
>> Seems not further classifications of #UDs.
> This is clarified in the pseudo code of VMX instructions in the SDM.  If you
> look at the pseudo code, all VMX instructions except VMXON (obviously) have
> something like below:
>
> 	IF (not in VMX operation) ...
> 		THEN #UD;
> 	ELSIF in VMX non-root operation
> 		THEN VMexit;
>
> So to me "this particular" #UD has higher priority over VM exits (while other
> #UDs may not).
>
> But IIUC above #UD won't happen when running VMX instruction in the guest,
> because if there's any live guest, the CPU must already have been in VMX
> operation.  So below check in nested_vmx_check_permission():
>
> 	if (!to_vmx(vcpu)->nested.vmxon) {
>                  kvm_queue_exception(vcpu, UD_VECTOR);
>                  return 0;
>          }
>
> is needed to emulate the case that guest runs any other VMX instructions before
> VMXON.
>
Yes, you are right. Get the point now, thanks.
Huang, Kai April 4, 2023, 1:53 a.m. UTC | #18
On Tue, 2023-04-04 at 09:21 +0800, Binbin Wu wrote:
> On 4/3/2023 7:24 PM, Huang, Kai wrote:
> > > 
> > > 
> > > Anyway, I will seperate this patch from the LAM KVM enabling patch. And
> > > send a patch seperately if
> > > needed later.
> > > 
> > I think your change for SGX is still needed based on the pseudo code of ENCLS.
> 
> Yes, I meant I would seperate VMX part since it is not a bug after all, 
> SGX will still be in the patchset.
> 
> 

Shouldn't SGX part be also split out as a bug fix patch?

Does it have anything to do with this LAM support series?
Binbin Wu April 4, 2023, 2:45 a.m. UTC | #19
On 4/4/2023 9:53 AM, Huang, Kai wrote:
> On Tue, 2023-04-04 at 09:21 +0800, Binbin Wu wrote:
>> On 4/3/2023 7:24 PM, Huang, Kai wrote:
>>>>
>>>> Anyway, I will seperate this patch from the LAM KVM enabling patch. And
>>>> send a patch seperately if
>>>> needed later.
>>>>
>>> I think your change for SGX is still needed based on the pseudo code of ENCLS.
>> Yes, I meant I would seperate VMX part since it is not a bug after all,
>> SGX will still be in the patchset.
>>
>>
> Shouldn't SGX part be also split out as a bug fix patch?
>
> Does it have anything to do with this LAM support series?

It is related to LAM support because LAM only effective in 64-bit mode,
so the untag action should only be done in 64-bit mode.

If the SGX fix patch is not included, that means LAM untag could be 
called in compatiblity mode in SGX ENCLS handler.
Huang, Kai April 4, 2023, 3:09 a.m. UTC | #20
On Tue, 2023-04-04 at 10:45 +0800, Binbin Wu wrote:
> On 4/4/2023 9:53 AM, Huang, Kai wrote:
> > On Tue, 2023-04-04 at 09:21 +0800, Binbin Wu wrote:
> > > On 4/3/2023 7:24 PM, Huang, Kai wrote:
> > > > > 
> > > > > Anyway, I will seperate this patch from the LAM KVM enabling patch. And
> > > > > send a patch seperately if
> > > > > needed later.
> > > > > 
> > > > I think your change for SGX is still needed based on the pseudo code of ENCLS.
> > > Yes, I meant I would seperate VMX part since it is not a bug after all,
> > > SGX will still be in the patchset.
> > > 
> > > 
> > Shouldn't SGX part be also split out as a bug fix patch?
> > 
> > Does it have anything to do with this LAM support series?
> 
> It is related to LAM support because LAM only effective in 64-bit mode,
> so the untag action should only be done in 64-bit mode.
> 
> If the SGX fix patch is not included, that means LAM untag could be 
> called in compatiblity mode in SGX ENCLS handler.
> 
> 

Yes I got this point, and your patch 6/7 depends on it.

But my point is this fix is needed anyway regardless the LAM support, and it
should be merged, for instance, asap as a bug fix (and CC stable perhaps) --
while the LAM support is a feature, and can be merged at a different time frame.

Of course just my 2cents and this is up to maintainers.
Binbin Wu April 4, 2023, 3:15 a.m. UTC | #21
On 4/4/2023 11:09 AM, Huang, Kai wrote:
> On Tue, 2023-04-04 at 10:45 +0800, Binbin Wu wrote:
>> On 4/4/2023 9:53 AM, Huang, Kai wrote:
>>> On Tue, 2023-04-04 at 09:21 +0800, Binbin Wu wrote:
>>>> On 4/3/2023 7:24 PM, Huang, Kai wrote:
>>>>>> Anyway, I will seperate this patch from the LAM KVM enabling patch. And
>>>>>> send a patch seperately if
>>>>>> needed later.
>>>>>>
>>>>> I think your change for SGX is still needed based on the pseudo code of ENCLS.
>>>> Yes, I meant I would seperate VMX part since it is not a bug after all,
>>>> SGX will still be in the patchset.
>>>>
>>>>
>>> Shouldn't SGX part be also split out as a bug fix patch?
>>>
>>> Does it have anything to do with this LAM support series?
>> It is related to LAM support because LAM only effective in 64-bit mode,
>> so the untag action should only be done in 64-bit mode.
>>
>> If the SGX fix patch is not included, that means LAM untag could be
>> called in compatiblity mode in SGX ENCLS handler.
>>
>>
> Yes I got this point, and your patch 6/7 depends on it.
>
> But my point is this fix is needed anyway regardless the LAM support, and it
> should be merged, for instance, asap as a bug fix (and CC stable perhaps) --
> while the LAM support is a feature, and can be merged at a different time frame.

OK, I can seperate the patch.


>
> Of course just my 2cents and this is up to maintainers.
Binbin Wu April 4, 2023, 3:27 a.m. UTC | #22
On 4/4/2023 11:15 AM, Binbin Wu wrote:
>
> On 4/4/2023 11:09 AM, Huang, Kai wrote:
>> On Tue, 2023-04-04 at 10:45 +0800, Binbin Wu wrote:
>>> On 4/4/2023 9:53 AM, Huang, Kai wrote:
>>>> On Tue, 2023-04-04 at 09:21 +0800, Binbin Wu wrote:
>>>>> On 4/3/2023 7:24 PM, Huang, Kai wrote:
>>>>>>> Anyway, I will seperate this patch from the LAM KVM enabling 
>>>>>>> patch. And
>>>>>>> send a patch seperately if
>>>>>>> needed later.
>>>>>>>
>>>>>> I think your change for SGX is still needed based on the pseudo 
>>>>>> code of ENCLS.
>>>>> Yes, I meant I would seperate VMX part since it is not a bug after 
>>>>> all,
>>>>> SGX will still be in the patchset.
>>>>>
>>>>>
>>>> Shouldn't SGX part be also split out as a bug fix patch?
>>>>
>>>> Does it have anything to do with this LAM support series?
>>> It is related to LAM support because LAM only effective in 64-bit mode,
>>> so the untag action should only be done in 64-bit mode.
>>>
>>> If the SGX fix patch is not included, that means LAM untag could be
>>> called in compatiblity mode in SGX ENCLS handler.
>>>
>>>
>> Yes I got this point, and your patch 6/7 depends on it.
>>
>> But my point is this fix is needed anyway regardless the LAM support, 
>> and it
>> should be merged, for instance, asap as a bug fix (and CC stable 
>> perhaps) --
>> while the LAM support is a feature, and can be merged at a different 
>> time frame.
>
> OK, I can seperate the patch.

Kai,

I sent the patch seperately and added your reivewed-by from the previous 
review.
https://lore.kernel.org/kvm/20230404032502.27798-1-binbin.wu@linux.intel.com/T/#u


>
>
>>
>> Of course just my 2cents and this is up to maintainers.
Binbin Wu April 4, 2023, 6:14 a.m. UTC | #23
On 3/30/2023 1:34 AM, Sean Christopherson wrote:
> On Wed, Mar 29, 2023, Binbin Wu wrote:
>> On 3/29/2023 10:04 AM, Huang, Kai wrote:
>>> On Wed, 2023-03-29 at 09:27 +0800, Binbin Wu wrote:
>>>> On 3/29/2023 7:33 AM, Huang, Kai wrote:
>>>>> On Tue, 2023-03-21 at 14:35 -0700, Sean Christopherson wrote:
>>>>>> On Mon, Mar 20, 2023, Chao Gao wrote:
>>>>>>> On Sun, Mar 19, 2023 at 04:49:22PM +0800, Binbin Wu wrote:
>>>>>>>> get_vmx_mem_address() and sgx_get_encls_gva() use is_long_mode()
>>>>>>>> to check 64-bit mode. Should use is_64_bit_mode() instead.
>>>>>>>>
>>>>>>>> Fixes: f9eb4af67c9d ("KVM: nVMX: VMX instructions: add checks for #GP/#SS exceptions")
>>>>>>>> Fixes: 70210c044b4e ("KVM: VMX: Add SGX ENCLS[ECREATE] handler to enforce CPUID restrictions")
>>>>>>> It is better to split this patch into two: one for nested and one for
>>>>>>> SGX.
>>>>>>>
>>>>>>> It is possible that there is a kernel release which has just one of
>>>>>>> above two flawed commits, then this fix patch cannot be applied cleanly
>>>>>>> to the release.
>>>>>> The nVMX code isn't buggy, VMX instructions #UD in compatibility mode, and except
>>>>>> for VMCALL, that #UD has higher priority than VM-Exit interception.  So I'd say
>>>>>> just drop the nVMX side of things.
>>>>> But it looks the old code doesn't unconditionally inject #UD when in
>>>>> compatibility mode?
>>>> I think Sean means VMX instructions is not valid in compatibility mode
>>>> and it triggers #UD, which has higher priority than VM-Exit, by the
>>>> processor in non-root mode.
>>>>
>>>> So if there is a VM-Exit due to VMX instruction , it is in 64-bit mode
>>>> for sure if it is in long mode.
>>> Oh I see thanks.
>>>
>>> Then is it better to add some comment to explain, or add a WARN() if it's not in
>>> 64-bit mode?
>> I also prefer to add a comment if no objection.
>>
>> Seems I am not the only one who didn't get it� : )
> I would rather have a code change than a comment, e.g.
>
> diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
> index f63b28f46a71..0460ca219f96 100644
> --- a/arch/x86/kvm/vmx/nested.c
> +++ b/arch/x86/kvm/vmx/nested.c
> @@ -4931,7 +4931,8 @@ int get_vmx_mem_address(struct kvm_vcpu *vcpu, unsigned long exit_qualification,
>          int  base_reg       = (vmx_instruction_info >> 23) & 0xf;
>          bool base_is_valid  = !(vmx_instruction_info & (1u << 27));
>   
> -       if (is_reg) {
> +       if (is_reg ||
> +           WARN_ON_ONCE(is_long_mode(vcpu) && !is_64_bit_mode(vcpu))) {
>                  kvm_queue_exception(vcpu, UD_VECTOR);
>                  return 1;
>          }
>
>
> The only downside is that querying is_64_bit_mode() could unnecessarily trigger a
> VMREAD to get the current CS.L bit, but a measurable performance regressions is
> extremely unlikely because is_64_bit_mode() all but guaranteed to be called in
> these paths anyways (and KVM caches segment info), e.g. by kvm_register_read().
>
> And then in a follow-up, we should also be able to do:
>
> @@ -5402,7 +5403,7 @@ static int handle_vmread(struct kvm_vcpu *vcpu)
>          if (instr_info & BIT(10)) {
>                  kvm_register_write(vcpu, (((instr_info) >> 3) & 0xf), value);
>          } else {
> -               len = is_64_bit_mode(vcpu) ? 8 : 4;
> +               len = is_long_mode(vcpu) ? 8 : 4;
>                  if (get_vmx_mem_address(vcpu, exit_qualification,
>                                          instr_info, true, len, &gva))
>                          return 1;
> @@ -5476,7 +5477,7 @@ static int handle_vmwrite(struct kvm_vcpu *vcpu)
>          if (instr_info & BIT(10))
>                  value = kvm_register_read(vcpu, (((instr_info) >> 3) & 0xf));
>          else {
> -               len = is_64_bit_mode(vcpu) ? 8 : 4;
> +               len = is_long_mode(vcpu) ? 8 : 4;
>                  if (get_vmx_mem_address(vcpu, exit_qualification,
>                                          instr_info, false, len, &gva))
>                          return 1;

Agree to replace is_64_bit_mode() with is_long_mode().
But, based on the implementation and comment of 
nested_vmx_check_permission(),
do you think it still needs to add the check for compatibility mode?
diff mbox series

Patch

diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
index 557b9c468734..0f84cc05f57c 100644
--- a/arch/x86/kvm/vmx/nested.c
+++ b/arch/x86/kvm/vmx/nested.c
@@ -4959,7 +4959,7 @@  int get_vmx_mem_address(struct kvm_vcpu *vcpu, unsigned long exit_qualification,
 
 	/* Checks for #GP/#SS exceptions. */
 	exn = false;
-	if (is_long_mode(vcpu)) {
+	if (is_64_bit_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
diff --git a/arch/x86/kvm/vmx/sgx.c b/arch/x86/kvm/vmx/sgx.c
index aa53c98034bf..0574030b071f 100644
--- a/arch/x86/kvm/vmx/sgx.c
+++ b/arch/x86/kvm/vmx/sgx.c
@@ -29,14 +29,14 @@  static int sgx_get_encls_gva(struct kvm_vcpu *vcpu, unsigned long offset,
 
 	/* Skip vmcs.GUEST_DS retrieval for 64-bit mode to avoid VMREADs. */
 	*gva = offset;
-	if (!is_long_mode(vcpu)) {
+	if (!is_64_bit_mode(vcpu)) {
 		vmx_get_segment(vcpu, &s, VCPU_SREG_DS);
 		*gva += s.base;
 	}
 
 	if (!IS_ALIGNED(*gva, alignment)) {
 		fault = true;
-	} else if (likely(is_long_mode(vcpu))) {
+	} else if (likely(is_64_bit_mode(vcpu))) {
 		fault = is_noncanonical_address(*gva, vcpu);
 	} else {
 		*gva &= 0xffffffff;