[1/2] KVM nVMX: Check Host Segment Registers and Descriptor Tables on vmentry of nested guests
diff mbox series

Message ID 20190628221447.23498-2-krish.sadhukhan@oracle.com
State New
Headers show
Series
  • nVMX: Check Host Segment Registers and Descriptor Tables on vmentry of nested guests
Related show

Commit Message

Krish Sadhukhan June 28, 2019, 10:14 p.m. UTC
According to section "Checks on Host Segment and Descriptor-Table
Registers" in Intel SDM vol 3C, the following checks are performed on
vmentry of nested guests:

   - In the selector field for each of CS, SS, DS, ES, FS, GS and TR, the
     RPL (bits 1:0) and the TI flag (bit 2) must be 0.
   - The selector fields for CS and TR cannot be 0000H.
   - The selector field for SS cannot be 0000H if the "host address-space
     size" VM-exit control is 0.
   - On processors that support Intel 64 architecture, the base-address
     fields for FS, GS and TR must contain canonical addresses.

Signed-off-by: Krish Sadhukhan <krish.sadhukhan@oracle.com>
Reviewed-by: Karl Heubaum <karl.heubaum@oracle.com>
---
 arch/x86/kvm/vmx/nested.c | 26 ++++++++++++++++++++++++--
 1 file changed, 24 insertions(+), 2 deletions(-)

Comments

Paolo Bonzini July 2, 2019, 4:25 p.m. UTC | #1
On 29/06/19 00:14, Krish Sadhukhan wrote:
> According to section "Checks on Host Segment and Descriptor-Table
> Registers" in Intel SDM vol 3C, the following checks are performed on
> vmentry of nested guests:
> 
>    - In the selector field for each of CS, SS, DS, ES, FS, GS and TR, the
>      RPL (bits 1:0) and the TI flag (bit 2) must be 0.
>    - The selector fields for CS and TR cannot be 0000H.
>    - The selector field for SS cannot be 0000H if the "host address-space
>      size" VM-exit control is 0.
>    - On processors that support Intel 64 architecture, the base-address
>      fields for FS, GS and TR must contain canonical addresses.
> 
> Signed-off-by: Krish Sadhukhan <krish.sadhukhan@oracle.com>
> Reviewed-by: Karl Heubaum <karl.heubaum@oracle.com>

All these tests are getting expensive.  Can you look into skipping them
whenever dirty_vmcs12 is clear?

Thanks,

Paolo

> ---
>  arch/x86/kvm/vmx/nested.c | 26 ++++++++++++++++++++++++--
>  1 file changed, 24 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
> index f1a69117ac0f..856a83aa42f5 100644
> --- a/arch/x86/kvm/vmx/nested.c
> +++ b/arch/x86/kvm/vmx/nested.c
> @@ -2609,6 +2609,30 @@ static int nested_vmx_check_host_state(struct kvm_vcpu *vcpu,
>  	    !kvm_pat_valid(vmcs12->host_ia32_pat))
>  		return -EINVAL;
>  
> +	ia32e = (vmcs12->vm_exit_controls &
> +		 VM_EXIT_HOST_ADDR_SPACE_SIZE) != 0;
> +
> +	if (vmcs12->host_cs_selector & (SEGMENT_RPL_MASK | SEGMENT_TI_MASK) ||
> +	    vmcs12->host_ss_selector & (SEGMENT_RPL_MASK | SEGMENT_TI_MASK) ||
> +	    vmcs12->host_ds_selector & (SEGMENT_RPL_MASK | SEGMENT_TI_MASK) ||
> +	    vmcs12->host_es_selector & (SEGMENT_RPL_MASK | SEGMENT_TI_MASK) ||
> +	    vmcs12->host_fs_selector & (SEGMENT_RPL_MASK | SEGMENT_TI_MASK) ||
> +	    vmcs12->host_gs_selector & (SEGMENT_RPL_MASK | SEGMENT_TI_MASK) ||
> +	    vmcs12->host_tr_selector & (SEGMENT_RPL_MASK | SEGMENT_TI_MASK) ||
> +	    vmcs12->host_cs_selector == 0 ||
> +	    vmcs12->host_tr_selector == 0 ||
> +	    (vmcs12->host_ss_selector == 0 && !ia32e))
> +		return -EINVAL;
> +
> +#ifdef CONFIG_X86_64
> +	if (is_noncanonical_address(vmcs12->host_fs_base, vcpu) ||
> +	    is_noncanonical_address(vmcs12->host_gs_base, vcpu) ||
> +	    is_noncanonical_address(vmcs12->host_gdtr_base, vcpu) ||
> +	    is_noncanonical_address(vmcs12->host_idtr_base, vcpu) ||
> +	    is_noncanonical_address(vmcs12->host_tr_base, vcpu))
> +		return -EINVAL;
> +#endif
> +
>  	/*
>  	 * If the load IA32_EFER VM-exit control is 1, bits reserved in the
>  	 * IA32_EFER MSR must be 0 in the field for that register. In addition,
> @@ -2616,8 +2640,6 @@ static int nested_vmx_check_host_state(struct kvm_vcpu *vcpu,
>  	 * the host address-space size VM-exit control.
>  	 */
>  	if (vmcs12->vm_exit_controls & VM_EXIT_LOAD_IA32_EFER) {
> -		ia32e = (vmcs12->vm_exit_controls &
> -			 VM_EXIT_HOST_ADDR_SPACE_SIZE) != 0;
>  		if (!kvm_valid_efer(vcpu, vmcs12->host_ia32_efer) ||
>  		    ia32e != !!(vmcs12->host_ia32_efer & EFER_LMA) ||
>  		    ia32e != !!(vmcs12->host_ia32_efer & EFER_LME))
>
Krish Sadhukhan July 3, 2019, 11:57 p.m. UTC | #2
On 07/02/2019 09:25 AM, Paolo Bonzini wrote:
> On 29/06/19 00:14, Krish Sadhukhan wrote:
>> According to section "Checks on Host Segment and Descriptor-Table
>> Registers" in Intel SDM vol 3C, the following checks are performed on
>> vmentry of nested guests:
>>
>>     - In the selector field for each of CS, SS, DS, ES, FS, GS and TR, the
>>       RPL (bits 1:0) and the TI flag (bit 2) must be 0.
>>     - The selector fields for CS and TR cannot be 0000H.
>>     - The selector field for SS cannot be 0000H if the "host address-space
>>       size" VM-exit control is 0.
>>     - On processors that support Intel 64 architecture, the base-address
>>       fields for FS, GS and TR must contain canonical addresses.
>>
>> Signed-off-by: Krish Sadhukhan <krish.sadhukhan@oracle.com>
>> Reviewed-by: Karl Heubaum <karl.heubaum@oracle.com>
> All these tests are getting expensive.  Can you look into skipping them
> whenever dirty_vmcs12 is clear?

OK. I am working on it and will send a separate patch-set for that. In 
the meantime, I will send v2 of this patchset containing a fix for a 
compilation error.

Thanks.

> Thanks,
>
> Paolo
>
>> ---
>>   arch/x86/kvm/vmx/nested.c | 26 ++++++++++++++++++++++++--
>>   1 file changed, 24 insertions(+), 2 deletions(-)
>>
>> diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
>> index f1a69117ac0f..856a83aa42f5 100644
>> --- a/arch/x86/kvm/vmx/nested.c
>> +++ b/arch/x86/kvm/vmx/nested.c
>> @@ -2609,6 +2609,30 @@ static int nested_vmx_check_host_state(struct kvm_vcpu *vcpu,
>>   	    !kvm_pat_valid(vmcs12->host_ia32_pat))
>>   		return -EINVAL;
>>   
>> +	ia32e = (vmcs12->vm_exit_controls &
>> +		 VM_EXIT_HOST_ADDR_SPACE_SIZE) != 0;
>> +
>> +	if (vmcs12->host_cs_selector & (SEGMENT_RPL_MASK | SEGMENT_TI_MASK) ||
>> +	    vmcs12->host_ss_selector & (SEGMENT_RPL_MASK | SEGMENT_TI_MASK) ||
>> +	    vmcs12->host_ds_selector & (SEGMENT_RPL_MASK | SEGMENT_TI_MASK) ||
>> +	    vmcs12->host_es_selector & (SEGMENT_RPL_MASK | SEGMENT_TI_MASK) ||
>> +	    vmcs12->host_fs_selector & (SEGMENT_RPL_MASK | SEGMENT_TI_MASK) ||
>> +	    vmcs12->host_gs_selector & (SEGMENT_RPL_MASK | SEGMENT_TI_MASK) ||
>> +	    vmcs12->host_tr_selector & (SEGMENT_RPL_MASK | SEGMENT_TI_MASK) ||
>> +	    vmcs12->host_cs_selector == 0 ||
>> +	    vmcs12->host_tr_selector == 0 ||
>> +	    (vmcs12->host_ss_selector == 0 && !ia32e))
>> +		return -EINVAL;
>> +
>> +#ifdef CONFIG_X86_64
>> +	if (is_noncanonical_address(vmcs12->host_fs_base, vcpu) ||
>> +	    is_noncanonical_address(vmcs12->host_gs_base, vcpu) ||
>> +	    is_noncanonical_address(vmcs12->host_gdtr_base, vcpu) ||
>> +	    is_noncanonical_address(vmcs12->host_idtr_base, vcpu) ||
>> +	    is_noncanonical_address(vmcs12->host_tr_base, vcpu))
>> +		return -EINVAL;
>> +#endif
>> +
>>   	/*
>>   	 * If the load IA32_EFER VM-exit control is 1, bits reserved in the
>>   	 * IA32_EFER MSR must be 0 in the field for that register. In addition,
>> @@ -2616,8 +2640,6 @@ static int nested_vmx_check_host_state(struct kvm_vcpu *vcpu,
>>   	 * the host address-space size VM-exit control.
>>   	 */
>>   	if (vmcs12->vm_exit_controls & VM_EXIT_LOAD_IA32_EFER) {
>> -		ia32e = (vmcs12->vm_exit_controls &
>> -			 VM_EXIT_HOST_ADDR_SPACE_SIZE) != 0;
>>   		if (!kvm_valid_efer(vcpu, vmcs12->host_ia32_efer) ||
>>   		    ia32e != !!(vmcs12->host_ia32_efer & EFER_LMA) ||
>>   		    ia32e != !!(vmcs12->host_ia32_efer & EFER_LME))
>>

Patch
diff mbox series

diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
index f1a69117ac0f..856a83aa42f5 100644
--- a/arch/x86/kvm/vmx/nested.c
+++ b/arch/x86/kvm/vmx/nested.c
@@ -2609,6 +2609,30 @@  static int nested_vmx_check_host_state(struct kvm_vcpu *vcpu,
 	    !kvm_pat_valid(vmcs12->host_ia32_pat))
 		return -EINVAL;
 
+	ia32e = (vmcs12->vm_exit_controls &
+		 VM_EXIT_HOST_ADDR_SPACE_SIZE) != 0;
+
+	if (vmcs12->host_cs_selector & (SEGMENT_RPL_MASK | SEGMENT_TI_MASK) ||
+	    vmcs12->host_ss_selector & (SEGMENT_RPL_MASK | SEGMENT_TI_MASK) ||
+	    vmcs12->host_ds_selector & (SEGMENT_RPL_MASK | SEGMENT_TI_MASK) ||
+	    vmcs12->host_es_selector & (SEGMENT_RPL_MASK | SEGMENT_TI_MASK) ||
+	    vmcs12->host_fs_selector & (SEGMENT_RPL_MASK | SEGMENT_TI_MASK) ||
+	    vmcs12->host_gs_selector & (SEGMENT_RPL_MASK | SEGMENT_TI_MASK) ||
+	    vmcs12->host_tr_selector & (SEGMENT_RPL_MASK | SEGMENT_TI_MASK) ||
+	    vmcs12->host_cs_selector == 0 ||
+	    vmcs12->host_tr_selector == 0 ||
+	    (vmcs12->host_ss_selector == 0 && !ia32e))
+		return -EINVAL;
+
+#ifdef CONFIG_X86_64
+	if (is_noncanonical_address(vmcs12->host_fs_base, vcpu) ||
+	    is_noncanonical_address(vmcs12->host_gs_base, vcpu) ||
+	    is_noncanonical_address(vmcs12->host_gdtr_base, vcpu) ||
+	    is_noncanonical_address(vmcs12->host_idtr_base, vcpu) ||
+	    is_noncanonical_address(vmcs12->host_tr_base, vcpu))
+		return -EINVAL;
+#endif
+
 	/*
 	 * If the load IA32_EFER VM-exit control is 1, bits reserved in the
 	 * IA32_EFER MSR must be 0 in the field for that register. In addition,
@@ -2616,8 +2640,6 @@  static int nested_vmx_check_host_state(struct kvm_vcpu *vcpu,
 	 * the host address-space size VM-exit control.
 	 */
 	if (vmcs12->vm_exit_controls & VM_EXIT_LOAD_IA32_EFER) {
-		ia32e = (vmcs12->vm_exit_controls &
-			 VM_EXIT_HOST_ADDR_SPACE_SIZE) != 0;
 		if (!kvm_valid_efer(vcpu, vmcs12->host_ia32_efer) ||
 		    ia32e != !!(vmcs12->host_ia32_efer & EFER_LMA) ||
 		    ia32e != !!(vmcs12->host_ia32_efer & EFER_LME))