mirror of
https://github.com/torvalds/linux.git
synced 2026-05-30 18:13:41 +02:00
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>
This commit is contained in:
parent
87d0f901a9
commit
5a30e8aea0
|
|
@ -6856,13 +6856,34 @@ void vmx_leave_nested(struct kvm_vcpu *vcpu)
|
|||
free_nested(vcpu);
|
||||
}
|
||||
|
||||
int nested_vmx_check_restored_vmcs12(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
enum vm_entry_failure_code ignored;
|
||||
struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
|
||||
|
||||
if (nested_cpu_has_shadow_vmcs(vmcs12) &&
|
||||
vmcs12->vmcs_link_pointer != INVALID_GPA) {
|
||||
struct vmcs12 *shadow_vmcs12 = get_shadow_vmcs12(vcpu);
|
||||
|
||||
if (shadow_vmcs12->hdr.revision_id != VMCS12_REVISION ||
|
||||
!shadow_vmcs12->hdr.shadow_vmcs)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (nested_vmx_check_controls(vcpu, vmcs12) ||
|
||||
nested_vmx_check_host_state(vcpu, vmcs12) ||
|
||||
nested_vmx_check_guest_state(vcpu, vmcs12, &ignored))
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vmx_set_nested_state(struct kvm_vcpu *vcpu,
|
||||
struct kvm_nested_state __user *user_kvm_nested_state,
|
||||
struct kvm_nested_state *kvm_state)
|
||||
{
|
||||
struct vcpu_vmx *vmx = to_vmx(vcpu);
|
||||
struct vmcs12 *vmcs12;
|
||||
enum vm_entry_failure_code ignored;
|
||||
struct kvm_vmx_nested_state_data __user *user_vmx_nested_state =
|
||||
&user_kvm_nested_state->data.vmx[0];
|
||||
int ret;
|
||||
|
|
@ -6993,25 +7014,20 @@ static int vmx_set_nested_state(struct kvm_vcpu *vcpu,
|
|||
vmx->nested.mtf_pending =
|
||||
!!(kvm_state->flags & KVM_STATE_NESTED_MTF_PENDING);
|
||||
|
||||
ret = -EINVAL;
|
||||
if (nested_cpu_has_shadow_vmcs(vmcs12) &&
|
||||
vmcs12->vmcs_link_pointer != INVALID_GPA) {
|
||||
struct vmcs12 *shadow_vmcs12 = get_shadow_vmcs12(vcpu);
|
||||
|
||||
ret = -EINVAL;
|
||||
if (kvm_state->size <
|
||||
sizeof(*kvm_state) +
|
||||
sizeof(user_vmx_nested_state->vmcs12) + sizeof(*shadow_vmcs12))
|
||||
goto error_guest_mode;
|
||||
|
||||
ret = -EFAULT;
|
||||
if (copy_from_user(shadow_vmcs12,
|
||||
user_vmx_nested_state->shadow_vmcs12,
|
||||
sizeof(*shadow_vmcs12))) {
|
||||
ret = -EFAULT;
|
||||
goto error_guest_mode;
|
||||
}
|
||||
|
||||
if (shadow_vmcs12->hdr.revision_id != VMCS12_REVISION ||
|
||||
!shadow_vmcs12->hdr.shadow_vmcs)
|
||||
sizeof(*shadow_vmcs12)))
|
||||
goto error_guest_mode;
|
||||
}
|
||||
|
||||
|
|
@ -7022,9 +7038,8 @@ static int vmx_set_nested_state(struct kvm_vcpu *vcpu,
|
|||
kvm_state->hdr.vmx.preemption_timer_deadline;
|
||||
}
|
||||
|
||||
if (nested_vmx_check_controls(vcpu, vmcs12) ||
|
||||
nested_vmx_check_host_state(vcpu, vmcs12) ||
|
||||
nested_vmx_check_guest_state(vcpu, vmcs12, &ignored))
|
||||
ret = nested_vmx_check_restored_vmcs12(vcpu);
|
||||
if (ret < 0)
|
||||
goto error_guest_mode;
|
||||
|
||||
vmx->nested.dirty_vmcs12 = true;
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ void nested_vmx_setup_ctls_msrs(struct vmcs_config *vmcs_conf, u32 ept_caps);
|
|||
void nested_vmx_hardware_unsetup(void);
|
||||
__init int nested_vmx_hardware_setup(int (*exit_handlers[])(struct kvm_vcpu *));
|
||||
void nested_vmx_set_vmcs_shadowing_bitmap(void);
|
||||
int nested_vmx_check_restored_vmcs12(struct kvm_vcpu *vcpu);
|
||||
void nested_vmx_free_vcpu(struct kvm_vcpu *vcpu);
|
||||
enum nvmx_vmentry_status nested_vmx_enter_non_root_mode(struct kvm_vcpu *vcpu,
|
||||
bool from_vmentry);
|
||||
|
|
|
|||
|
|
@ -8528,6 +8528,10 @@ int vmx_leave_smm(struct kvm_vcpu *vcpu, const union kvm_smram *smram)
|
|||
}
|
||||
|
||||
if (vmx->nested.smm.guest_mode) {
|
||||
/* Triple fault if the state is invalid. */
|
||||
if (nested_vmx_check_restored_vmcs12(vcpu) < 0)
|
||||
return 1;
|
||||
|
||||
ret = nested_vmx_enter_non_root_mode(vcpu, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user