KVM: nVMX: check for required but missing VMCS12 in KVM_SET_NESTED_STATE
authorPaolo Bonzini <pbonzini@redhat.com>
Mon, 27 Jul 2020 13:00:37 +0000 (09:00 -0400)
committerPaolo Bonzini <pbonzini@redhat.com>
Mon, 27 Jul 2020 13:04:49 +0000 (09:04 -0400)
A missing VMCS12 was not causing -EINVAL (it was just read with
copy_from_user, so it is not a security issue, but it is still
wrong).  Test for VMCS12 validity and reject the nested state
if a VMCS12 is required but not present.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/x86/kvm/vmx/nested.c
arch/x86/kvm/vmx/nested.h
tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c

index d4a4cec..6a0e32a 100644 (file)
@@ -6108,9 +6108,16 @@ static int vmx_set_nested_state(struct kvm_vcpu *vcpu,
        if (ret)
                return ret;
 
-       /* Empty 'VMXON' state is permitted */
-       if (kvm_state->size < sizeof(*kvm_state) + sizeof(*vmcs12))
-               return 0;
+       /* Empty 'VMXON' state is permitted if no VMCS loaded */
+       if (kvm_state->size < sizeof(*kvm_state) + sizeof(*vmcs12)) {
+               /* See vmx_has_valid_vmcs12.  */
+               if ((kvm_state->flags & KVM_STATE_NESTED_GUEST_MODE) ||
+                   (kvm_state->flags & KVM_STATE_NESTED_EVMCS) ||
+                   (kvm_state->hdr.vmx.vmcs12_pa != -1ull))
+                       return -EINVAL;
+               else
+                       return 0;
+       }
 
        if (kvm_state->hdr.vmx.vmcs12_pa != -1ull) {
                if (kvm_state->hdr.vmx.vmcs12_pa == kvm_state->hdr.vmx.vmxon_pa ||
index 758bccc..197148d 100644 (file)
@@ -47,6 +47,11 @@ static inline struct vmcs12 *get_shadow_vmcs12(struct kvm_vcpu *vcpu)
        return to_vmx(vcpu)->nested.cached_shadow_vmcs12;
 }
 
+/*
+ * Note: the same condition is checked against the state provided by userspace
+ * in vmx_set_nested_state; if it is satisfied, the nested state must include
+ * the VMCS12.
+ */
 static inline int vmx_has_valid_vmcs12(struct kvm_vcpu *vcpu)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
index d14a34f..94f28a6 100644 (file)
@@ -183,9 +183,19 @@ void test_vmx_nested_state(struct kvm_vm *vm)
        state->hdr.vmx.smm.flags = KVM_STATE_NESTED_SMM_GUEST_MODE;
        test_nested_state_expect_einval(vm, state);
 
-       /* Size must be large enough to fit kvm_nested_state and vmcs12. */
+       /*
+        * Size must be large enough to fit kvm_nested_state and vmcs12
+        * if VMCS12 physical address is set
+        */
+       set_default_vmx_state(state, state_sz);
+       state->size = sizeof(*state);
+       state->flags = 0;
+       test_nested_state_expect_einval(vm, state);
+
        set_default_vmx_state(state, state_sz);
        state->size = sizeof(*state);
+       state->flags = 0;
+       state->hdr.vmx.vmcs12_pa = -1;
        test_nested_state(vm, state);
 
        /*