Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

+32 -12
+27 -12
arch/x86/kvm/vmx/nested.c
··· 6856 6856 free_nested(vcpu); 6857 6857 } 6858 6858 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 + 6859 6881 static int vmx_set_nested_state(struct kvm_vcpu *vcpu, 6860 6882 struct kvm_nested_state __user *user_kvm_nested_state, 6861 6883 struct kvm_nested_state *kvm_state) 6862 6884 { 6863 6885 struct vcpu_vmx *vmx = to_vmx(vcpu); 6864 6886 struct vmcs12 *vmcs12; 6865 - enum vm_entry_failure_code ignored; 6866 6887 struct kvm_vmx_nested_state_data __user *user_vmx_nested_state = 6867 6888 &user_kvm_nested_state->data.vmx[0]; 6868 6889 int ret; ··· 7014 6993 vmx->nested.mtf_pending = 7015 6994 !!(kvm_state->flags & KVM_STATE_NESTED_MTF_PENDING); 7016 6995 7017 - ret = -EINVAL; 7018 6996 if (nested_cpu_has_shadow_vmcs(vmcs12) && 7019 6997 vmcs12->vmcs_link_pointer != INVALID_GPA) { 7020 6998 struct vmcs12 *shadow_vmcs12 = get_shadow_vmcs12(vcpu); 7021 6999 7000 + ret = -EINVAL; 7022 7001 if (kvm_state->size < 7023 7002 sizeof(*kvm_state) + 7024 7003 sizeof(user_vmx_nested_state->vmcs12) + sizeof(*shadow_vmcs12)) 7025 7004 goto error_guest_mode; 7026 7005 7006 + ret = -EFAULT; 7027 7007 if (copy_from_user(shadow_vmcs12, 7028 7008 user_vmx_nested_state->shadow_vmcs12, 7029 - sizeof(*shadow_vmcs12))) { 7030 - ret = -EFAULT; 7031 - goto error_guest_mode; 7032 - } 7033 - 7034 - if (shadow_vmcs12->hdr.revision_id != VMCS12_REVISION || 7035 - !shadow_vmcs12->hdr.shadow_vmcs) 7009 + sizeof(*shadow_vmcs12))) 7036 7010 goto error_guest_mode; 7037 7011 } 7038 7012 ··· 7038 7022 kvm_state->hdr.vmx.preemption_timer_deadline; 7039 7023 } 7040 7024 7041 - if (nested_vmx_check_controls(vcpu, vmcs12) || 7042 - nested_vmx_check_host_state(vcpu, vmcs12) || 7043 - nested_vmx_check_guest_state(vcpu, vmcs12, &ignored)) 7025 + ret = nested_vmx_check_restored_vmcs12(vcpu); 7026 + if (ret < 0) 7044 7027 goto error_guest_mode; 7045 7028 7046 7029 vmx->nested.dirty_vmcs12 = true;
+1
arch/x86/kvm/vmx/nested.h
··· 22 22 void nested_vmx_hardware_unsetup(void); 23 23 __init int nested_vmx_hardware_setup(int (*exit_handlers[])(struct kvm_vcpu *)); 24 24 void nested_vmx_set_vmcs_shadowing_bitmap(void); 25 + int nested_vmx_check_restored_vmcs12(struct kvm_vcpu *vcpu); 25 26 void nested_vmx_free_vcpu(struct kvm_vcpu *vcpu); 26 27 enum nvmx_vmentry_status nested_vmx_enter_non_root_mode(struct kvm_vcpu *vcpu, 27 28 bool from_vmentry);
+4
arch/x86/kvm/vmx/vmx.c
··· 8528 8528 } 8529 8529 8530 8530 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 + 8531 8535 ret = nested_vmx_enter_non_root_mode(vcpu, false); 8532 8536 if (ret) 8533 8537 return ret;