Skip to content

Commit

Permalink
KVM: nVMX: reorganize initial steps of vmx_set_nested_state
Browse files Browse the repository at this point in the history
Commit 332d079 ("KVM: nVMX: KVM_SET_NESTED_STATE - Tear down old EVMCS
state before setting new state", 2019-05-02) broke evmcs_test because the
eVMCS setup must be performed even if there is no VMXON region defined,
as long as the eVMCS bit is set in the assist page.

While the simplest possible fix would be to add a check on
kvm_state->flags & KVM_STATE_NESTED_EVMCS in the initial "if" that
covers kvm_state->hdr.vmx.vmxon_pa == -1ull, that is quite ugly.

Instead, this patch moves checks earlier in the function and
conditionalizes them on kvm_state->hdr.vmx.vmxon_pa, so that
vmx_set_nested_state always goes through vmx_leave_nested
and nested_enable_evmcs.

Fixes: 332d079 ("KVM: nVMX: KVM_SET_NESTED_STATE - Tear down old EVMCS state before setting new state")
Cc: Aaron Lewis <[email protected]>
Reviewed-by: Vitaly Kuznetsov <[email protected]>
Signed-off-by: Paolo Bonzini <[email protected]>
  • Loading branch information
bonzini committed Jun 20, 2019
1 parent 9dba988 commit 9fd5887
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 23 deletions.
26 changes: 15 additions & 11 deletions arch/x86/kvm/vmx/nested.c
Original file line number Diff line number Diff line change
Expand Up @@ -5343,22 +5343,22 @@ static int vmx_set_nested_state(struct kvm_vcpu *vcpu,
if (kvm_state->format != KVM_STATE_NESTED_FORMAT_VMX)
return -EINVAL;

if (!nested_vmx_allowed(vcpu))
return kvm_state->hdr.vmx.vmxon_pa == -1ull ? 0 : -EINVAL;

if (kvm_state->hdr.vmx.vmxon_pa == -1ull) {
if (kvm_state->hdr.vmx.smm.flags)
return -EINVAL;

if (kvm_state->hdr.vmx.vmcs12_pa != -1ull)
return -EINVAL;

vmx_leave_nested(vcpu);
return 0;
}
if (kvm_state->flags & ~KVM_STATE_NESTED_EVMCS)
return -EINVAL;
} else {
if (!nested_vmx_allowed(vcpu))
return -EINVAL;

if (!page_address_valid(vcpu, kvm_state->hdr.vmx.vmxon_pa))
return -EINVAL;
if (!page_address_valid(vcpu, kvm_state->hdr.vmx.vmxon_pa))
return -EINVAL;
}

if ((kvm_state->hdr.vmx.smm.flags & KVM_STATE_NESTED_SMM_GUEST_MODE) &&
(kvm_state->flags & KVM_STATE_NESTED_GUEST_MODE))
Expand All @@ -5381,11 +5381,15 @@ static int vmx_set_nested_state(struct kvm_vcpu *vcpu,
return -EINVAL;

vmx_leave_nested(vcpu);
if (kvm_state->hdr.vmx.vmxon_pa == -1ull)
return 0;
if (kvm_state->flags & KVM_STATE_NESTED_EVMCS) {
if (!nested_vmx_allowed(vcpu))
return -EINVAL;

if (kvm_state->flags & KVM_STATE_NESTED_EVMCS)
nested_enable_evmcs(vcpu, NULL);
}

if (kvm_state->hdr.vmx.vmxon_pa == -1ull)
return 0;

vmx->nested.vmxon_ptr = kvm_state->hdr.vmx.vmxon_pa;
ret = enter_vmx_operation(vcpu);
Expand Down
32 changes: 20 additions & 12 deletions tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,36 +123,44 @@ void test_vmx_nested_state(struct kvm_vm *vm)
/*
* We cannot virtualize anything if the guest does not have VMX
* enabled. We expect KVM_SET_NESTED_STATE to return 0 if vmxon_pa
* is set to -1ull.
* is set to -1ull, but the flags must be zero.
*/
set_default_vmx_state(state, state_sz);
state->hdr.vmx.vmxon_pa = -1ull;
test_nested_state_expect_einval(vm, state);

state->hdr.vmx.vmcs12_pa = -1ull;
state->flags = KVM_STATE_NESTED_EVMCS;
test_nested_state_expect_einval(vm, state);

state->flags = 0;
test_nested_state(vm, state);

/* Enable VMX in the guest CPUID. */
vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid());

/* It is invalid to have vmxon_pa == -1ull and SMM flags non-zero. */
/*
* Setting vmxon_pa == -1ull and vmcs_pa == -1ull exits early without
* setting the nested state but flags other than eVMCS must be clear.
*/
set_default_vmx_state(state, state_sz);
state->hdr.vmx.vmxon_pa = -1ull;
state->hdr.vmx.vmcs12_pa = -1ull;
test_nested_state_expect_einval(vm, state);

state->flags = KVM_STATE_NESTED_EVMCS;
test_nested_state(vm, state);

/* It is invalid to have vmxon_pa == -1ull and SMM flags non-zero. */
state->hdr.vmx.smm.flags = 1;
test_nested_state_expect_einval(vm, state);

/* It is invalid to have vmxon_pa == -1ull and vmcs_pa != -1ull. */
set_default_vmx_state(state, state_sz);
state->hdr.vmx.vmxon_pa = -1ull;
state->hdr.vmx.vmcs12_pa = 0;
state->flags = 0;
test_nested_state_expect_einval(vm, state);

/*
* Setting vmxon_pa == -1ull and vmcs_pa == -1ull exits early without
* setting the nested state.
*/
set_default_vmx_state(state, state_sz);
state->hdr.vmx.vmxon_pa = -1ull;
state->hdr.vmx.vmcs12_pa = -1ull;
test_nested_state(vm, state);

/* It is invalid to have vmxon_pa set to a non-page aligned address. */
set_default_vmx_state(state, state_sz);
state->hdr.vmx.vmxon_pa = 1;
Expand Down

0 comments on commit 9fd5887

Please sign in to comment.