Skip to content

Commit 5a30e8a

Browse files
committed
KVM: VMX: check validity of VMCS controls when returning from SMM
The VMCS12 is not available while in SMM. However, it can be overwritten if userspace manages to trigger copy_enlightened_to_vmcs12() - for example via KVM_GET_NESTED_STATE. Because of this, the VMCS12 has to be checked for validity before it is used to generate the VMCS02. Move the check code out of vmx_set_nested_state() (the other "not a VMLAUNCH/VMRESUME" path that emulates a nested vmentry) and reuse it in vmx_leave_smm(). Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
1 parent 87d0f90 commit 5a30e8a

3 files changed

Lines changed: 32 additions & 12 deletions

File tree

arch/x86/kvm/vmx/nested.c

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6856,13 +6856,34 @@ void vmx_leave_nested(struct kvm_vcpu *vcpu)
68566856
free_nested(vcpu);
68576857
}
68586858

6859+
int nested_vmx_check_restored_vmcs12(struct kvm_vcpu *vcpu)
6860+
{
6861+
enum vm_entry_failure_code ignored;
6862+
struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
6863+
6864+
if (nested_cpu_has_shadow_vmcs(vmcs12) &&
6865+
vmcs12->vmcs_link_pointer != INVALID_GPA) {
6866+
struct vmcs12 *shadow_vmcs12 = get_shadow_vmcs12(vcpu);
6867+
6868+
if (shadow_vmcs12->hdr.revision_id != VMCS12_REVISION ||
6869+
!shadow_vmcs12->hdr.shadow_vmcs)
6870+
return -EINVAL;
6871+
}
6872+
6873+
if (nested_vmx_check_controls(vcpu, vmcs12) ||
6874+
nested_vmx_check_host_state(vcpu, vmcs12) ||
6875+
nested_vmx_check_guest_state(vcpu, vmcs12, &ignored))
6876+
return -EINVAL;
6877+
6878+
return 0;
6879+
}
6880+
68596881
static int vmx_set_nested_state(struct kvm_vcpu *vcpu,
68606882
struct kvm_nested_state __user *user_kvm_nested_state,
68616883
struct kvm_nested_state *kvm_state)
68626884
{
68636885
struct vcpu_vmx *vmx = to_vmx(vcpu);
68646886
struct vmcs12 *vmcs12;
6865-
enum vm_entry_failure_code ignored;
68666887
struct kvm_vmx_nested_state_data __user *user_vmx_nested_state =
68676888
&user_kvm_nested_state->data.vmx[0];
68686889
int ret;
@@ -6993,25 +7014,20 @@ static int vmx_set_nested_state(struct kvm_vcpu *vcpu,
69937014
vmx->nested.mtf_pending =
69947015
!!(kvm_state->flags & KVM_STATE_NESTED_MTF_PENDING);
69957016

6996-
ret = -EINVAL;
69977017
if (nested_cpu_has_shadow_vmcs(vmcs12) &&
69987018
vmcs12->vmcs_link_pointer != INVALID_GPA) {
69997019
struct vmcs12 *shadow_vmcs12 = get_shadow_vmcs12(vcpu);
70007020

7021+
ret = -EINVAL;
70017022
if (kvm_state->size <
70027023
sizeof(*kvm_state) +
70037024
sizeof(user_vmx_nested_state->vmcs12) + sizeof(*shadow_vmcs12))
70047025
goto error_guest_mode;
70057026

7027+
ret = -EFAULT;
70067028
if (copy_from_user(shadow_vmcs12,
70077029
user_vmx_nested_state->shadow_vmcs12,
7008-
sizeof(*shadow_vmcs12))) {
7009-
ret = -EFAULT;
7010-
goto error_guest_mode;
7011-
}
7012-
7013-
if (shadow_vmcs12->hdr.revision_id != VMCS12_REVISION ||
7014-
!shadow_vmcs12->hdr.shadow_vmcs)
7030+
sizeof(*shadow_vmcs12)))
70157031
goto error_guest_mode;
70167032
}
70177033

@@ -7022,9 +7038,8 @@ static int vmx_set_nested_state(struct kvm_vcpu *vcpu,
70227038
kvm_state->hdr.vmx.preemption_timer_deadline;
70237039
}
70247040

7025-
if (nested_vmx_check_controls(vcpu, vmcs12) ||
7026-
nested_vmx_check_host_state(vcpu, vmcs12) ||
7027-
nested_vmx_check_guest_state(vcpu, vmcs12, &ignored))
7041+
ret = nested_vmx_check_restored_vmcs12(vcpu);
7042+
if (ret < 0)
70287043
goto error_guest_mode;
70297044

70307045
vmx->nested.dirty_vmcs12 = true;

arch/x86/kvm/vmx/nested.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ void nested_vmx_setup_ctls_msrs(struct vmcs_config *vmcs_conf, u32 ept_caps);
2222
void nested_vmx_hardware_unsetup(void);
2323
__init int nested_vmx_hardware_setup(int (*exit_handlers[])(struct kvm_vcpu *));
2424
void nested_vmx_set_vmcs_shadowing_bitmap(void);
25+
int nested_vmx_check_restored_vmcs12(struct kvm_vcpu *vcpu);
2526
void nested_vmx_free_vcpu(struct kvm_vcpu *vcpu);
2627
enum nvmx_vmentry_status nested_vmx_enter_non_root_mode(struct kvm_vcpu *vcpu,
2728
bool from_vmentry);

arch/x86/kvm/vmx/vmx.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8528,6 +8528,10 @@ int vmx_leave_smm(struct kvm_vcpu *vcpu, const union kvm_smram *smram)
85288528
}
85298529

85308530
if (vmx->nested.smm.guest_mode) {
8531+
/* Triple fault if the state is invalid. */
8532+
if (nested_vmx_check_restored_vmcs12(vcpu) < 0)
8533+
return 1;
8534+
85318535
ret = nested_vmx_enter_non_root_mode(vcpu, false);
85328536
if (ret)
85338537
return ret;

0 commit comments

Comments
 (0)