kvm: nVMX: VMWRITE checks VMCS-link pointer before VMCS field
authorJim Mattson <jmattson@google.com>
Fri, 6 Dec 2019 23:46:35 +0000 (15:46 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 5 Mar 2020 15:43:52 +0000 (16:43 +0100)
commit dd2d6042b7f4a5440705b4ffc6c4c2dba81a43b7 upstream.

According to the SDM, a VMWRITE in VMX non-root operation with an
invalid VMCS-link pointer results in VMfailInvalid before the validity
of the VMCS field in the secondary source operand is checked.

For consistency, modify both handle_vmwrite and handle_vmread, even
though there was no problem with the latter.

Fixes: 6d894f498f5d1 ("KVM: nVMX: vmread/vmwrite: Use shadow vmcs12 if running L2")
Signed-off-by: Jim Mattson <jmattson@google.com>
Cc: Liran Alon <liran.alon@oracle.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Vitaly Kuznetsov <vkuznets@redhat.com>
Reviewed-by: Peter Shier <pshier@google.com>
Reviewed-by: Oliver Upton <oupton@google.com>
Reviewed-by: Jon Cargille <jcargill@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
arch/x86/kvm/vmx/nested.c

index 802ef71..f59b342 100644 (file)
@@ -4609,32 +4609,28 @@ static int handle_vmread(struct kvm_vcpu *vcpu)
 {
        unsigned long field;
        u64 field_value;
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
        unsigned long exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
        u32 vmx_instruction_info = vmcs_read32(VMX_INSTRUCTION_INFO);
        int len;
        gva_t gva = 0;
-       struct vmcs12 *vmcs12;
+       struct vmcs12 *vmcs12 = is_guest_mode(vcpu) ? get_shadow_vmcs12(vcpu)
+                                                   : get_vmcs12(vcpu);
        struct x86_exception e;
        short offset;
 
        if (!nested_vmx_check_permission(vcpu))
                return 1;
 
-       if (to_vmx(vcpu)->nested.current_vmptr == -1ull)
+       /*
+        * In VMX non-root operation, when the VMCS-link pointer is -1ull,
+        * any VMREAD sets the ALU flags for VMfailInvalid.
+        */
+       if (vmx->nested.current_vmptr == -1ull ||
+           (is_guest_mode(vcpu) &&
+            get_vmcs12(vcpu)->vmcs_link_pointer == -1ull))
                return nested_vmx_failInvalid(vcpu);
 
-       if (!is_guest_mode(vcpu))
-               vmcs12 = get_vmcs12(vcpu);
-       else {
-               /*
-                * When vmcs->vmcs_link_pointer is -1ull, any VMREAD
-                * to shadowed-field sets the ALU flags for VMfailInvalid.
-                */
-               if (get_vmcs12(vcpu)->vmcs_link_pointer == -1ull)
-                       return nested_vmx_failInvalid(vcpu);
-               vmcs12 = get_shadow_vmcs12(vcpu);
-       }
-
        /* Decode instruction info and find the field to read */
        field = kvm_register_readl(vcpu, (((vmx_instruction_info) >> 28) & 0xf));
 
@@ -4713,13 +4709,20 @@ static int handle_vmwrite(struct kvm_vcpu *vcpu)
         */
        u64 field_value = 0;
        struct x86_exception e;
-       struct vmcs12 *vmcs12;
+       struct vmcs12 *vmcs12 = is_guest_mode(vcpu) ? get_shadow_vmcs12(vcpu)
+                                                   : get_vmcs12(vcpu);
        short offset;
 
        if (!nested_vmx_check_permission(vcpu))
                return 1;
 
-       if (vmx->nested.current_vmptr == -1ull)
+       /*
+        * In VMX non-root operation, when the VMCS-link pointer is -1ull,
+        * any VMWRITE sets the ALU flags for VMfailInvalid.
+        */
+       if (vmx->nested.current_vmptr == -1ull ||
+           (is_guest_mode(vcpu) &&
+            get_vmcs12(vcpu)->vmcs_link_pointer == -1ull))
                return nested_vmx_failInvalid(vcpu);
 
        if (vmx_instruction_info & (1u << 10))
@@ -4747,24 +4750,12 @@ static int handle_vmwrite(struct kvm_vcpu *vcpu)
                return nested_vmx_failValid(vcpu,
                        VMXERR_VMWRITE_READ_ONLY_VMCS_COMPONENT);
 
-       if (!is_guest_mode(vcpu)) {
-               vmcs12 = get_vmcs12(vcpu);
-
-               /*
-                * Ensure vmcs12 is up-to-date before any VMWRITE that dirties
-                * vmcs12, else we may crush a field or consume a stale value.
-                */
-               if (!is_shadow_field_rw(field))
-                       copy_vmcs02_to_vmcs12_rare(vcpu, vmcs12);
-       } else {
-               /*
-                * When vmcs->vmcs_link_pointer is -1ull, any VMWRITE
-                * to shadowed-field sets the ALU flags for VMfailInvalid.
-                */
-               if (get_vmcs12(vcpu)->vmcs_link_pointer == -1ull)
-                       return nested_vmx_failInvalid(vcpu);
-               vmcs12 = get_shadow_vmcs12(vcpu);
-       }
+       /*
+        * Ensure vmcs12 is up-to-date before any VMWRITE that dirties
+        * vmcs12, else we may crush a field or consume a stale value.
+        */
+       if (!is_guest_mode(vcpu) && !is_shadow_field_rw(field))
+               copy_vmcs02_to_vmcs12_rare(vcpu, vmcs12);
 
        offset = vmcs_field_to_offset(field);
        if (offset < 0)