diff options
| -rw-r--r-- | arch/x86/kvm/vmx.c | 140 |
1 files changed, 57 insertions, 83 deletions
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 880f371705bc..9b4b5d6dcd34 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c | |||
| @@ -6914,97 +6914,21 @@ static int get_vmx_mem_address(struct kvm_vcpu *vcpu, | |||
| 6914 | return 0; | 6914 | return 0; |
| 6915 | } | 6915 | } |
| 6916 | 6916 | ||
| 6917 | /* | 6917 | static int nested_vmx_get_vmptr(struct kvm_vcpu *vcpu, gpa_t *vmpointer) |
| 6918 | * This function performs the various checks including | ||
| 6919 | * - if it's 4KB aligned | ||
| 6920 | * - No bits beyond the physical address width are set | ||
| 6921 | * - Returns 0 on success or else 1 | ||
| 6922 | * (Intel SDM Section 30.3) | ||
| 6923 | */ | ||
| 6924 | static int nested_vmx_check_vmptr(struct kvm_vcpu *vcpu, int exit_reason, | ||
| 6925 | gpa_t *vmpointer) | ||
| 6926 | { | 6918 | { |
| 6927 | gva_t gva; | 6919 | gva_t gva; |
| 6928 | gpa_t vmptr; | ||
| 6929 | struct x86_exception e; | 6920 | struct x86_exception e; |
| 6930 | struct page *page; | ||
| 6931 | struct vcpu_vmx *vmx = to_vmx(vcpu); | ||
| 6932 | int maxphyaddr = cpuid_maxphyaddr(vcpu); | ||
| 6933 | 6921 | ||
| 6934 | if (get_vmx_mem_address(vcpu, vmcs_readl(EXIT_QUALIFICATION), | 6922 | if (get_vmx_mem_address(vcpu, vmcs_readl(EXIT_QUALIFICATION), |
| 6935 | vmcs_read32(VMX_INSTRUCTION_INFO), false, &gva)) | 6923 | vmcs_read32(VMX_INSTRUCTION_INFO), false, &gva)) |
| 6936 | return 1; | 6924 | return 1; |
| 6937 | 6925 | ||
| 6938 | if (kvm_read_guest_virt(&vcpu->arch.emulate_ctxt, gva, &vmptr, | 6926 | if (kvm_read_guest_virt(&vcpu->arch.emulate_ctxt, gva, vmpointer, |
| 6939 | sizeof(vmptr), &e)) { | 6927 | sizeof(*vmpointer), &e)) { |
| 6940 | kvm_inject_page_fault(vcpu, &e); | 6928 | kvm_inject_page_fault(vcpu, &e); |
| 6941 | return 1; | 6929 | return 1; |
| 6942 | } | 6930 | } |
| 6943 | 6931 | ||
| 6944 | switch (exit_reason) { | ||
| 6945 | case EXIT_REASON_VMON: | ||
| 6946 | /* | ||
| 6947 | * SDM 3: 24.11.5 | ||
| 6948 | * The first 4 bytes of VMXON region contain the supported | ||
| 6949 | * VMCS revision identifier | ||
| 6950 | * | ||
| 6951 | * Note - IA32_VMX_BASIC[48] will never be 1 | ||
| 6952 | * for the nested case; | ||
| 6953 | * which replaces physical address width with 32 | ||
| 6954 | * | ||
| 6955 | */ | ||
| 6956 | if (!PAGE_ALIGNED(vmptr) || (vmptr >> maxphyaddr)) { | ||
| 6957 | nested_vmx_failInvalid(vcpu); | ||
| 6958 | return kvm_skip_emulated_instruction(vcpu); | ||
| 6959 | } | ||
| 6960 | |||
| 6961 | page = nested_get_page(vcpu, vmptr); | ||
| 6962 | if (page == NULL) { | ||
| 6963 | nested_vmx_failInvalid(vcpu); | ||
| 6964 | return kvm_skip_emulated_instruction(vcpu); | ||
| 6965 | } | ||
| 6966 | if (*(u32 *)kmap(page) != VMCS12_REVISION) { | ||
| 6967 | kunmap(page); | ||
| 6968 | nested_release_page_clean(page); | ||
| 6969 | nested_vmx_failInvalid(vcpu); | ||
| 6970 | return kvm_skip_emulated_instruction(vcpu); | ||
| 6971 | } | ||
| 6972 | kunmap(page); | ||
| 6973 | nested_release_page_clean(page); | ||
| 6974 | vmx->nested.vmxon_ptr = vmptr; | ||
| 6975 | break; | ||
| 6976 | case EXIT_REASON_VMCLEAR: | ||
| 6977 | if (!PAGE_ALIGNED(vmptr) || (vmptr >> maxphyaddr)) { | ||
| 6978 | nested_vmx_failValid(vcpu, | ||
| 6979 | VMXERR_VMCLEAR_INVALID_ADDRESS); | ||
| 6980 | return kvm_skip_emulated_instruction(vcpu); | ||
| 6981 | } | ||
| 6982 | |||
| 6983 | if (vmptr == vmx->nested.vmxon_ptr) { | ||
| 6984 | nested_vmx_failValid(vcpu, | ||
| 6985 | VMXERR_VMCLEAR_VMXON_POINTER); | ||
| 6986 | return kvm_skip_emulated_instruction(vcpu); | ||
| 6987 | } | ||
| 6988 | break; | ||
| 6989 | case EXIT_REASON_VMPTRLD: | ||
| 6990 | if (!PAGE_ALIGNED(vmptr) || (vmptr >> maxphyaddr)) { | ||
| 6991 | nested_vmx_failValid(vcpu, | ||
| 6992 | VMXERR_VMPTRLD_INVALID_ADDRESS); | ||
| 6993 | return kvm_skip_emulated_instruction(vcpu); | ||
| 6994 | } | ||
| 6995 | |||
| 6996 | if (vmptr == vmx->nested.vmxon_ptr) { | ||
| 6997 | nested_vmx_failValid(vcpu, | ||
| 6998 | VMXERR_VMPTRLD_VMXON_POINTER); | ||
| 6999 | return kvm_skip_emulated_instruction(vcpu); | ||
| 7000 | } | ||
| 7001 | break; | ||
| 7002 | default: | ||
| 7003 | return 1; /* shouldn't happen */ | ||
| 7004 | } | ||
| 7005 | |||
| 7006 | if (vmpointer) | ||
| 7007 | *vmpointer = vmptr; | ||
| 7008 | return 0; | 6932 | return 0; |
| 7009 | } | 6933 | } |
| 7010 | 6934 | ||
| @@ -7066,6 +6990,8 @@ out_msr_bitmap: | |||
| 7066 | static int handle_vmon(struct kvm_vcpu *vcpu) | 6990 | static int handle_vmon(struct kvm_vcpu *vcpu) |
| 7067 | { | 6991 | { |
| 7068 | int ret; | 6992 | int ret; |
| 6993 | gpa_t vmptr; | ||
| 6994 | struct page *page; | ||
| 7069 | struct vcpu_vmx *vmx = to_vmx(vcpu); | 6995 | struct vcpu_vmx *vmx = to_vmx(vcpu); |
| 7070 | const u64 VMXON_NEEDED_FEATURES = FEATURE_CONTROL_LOCKED | 6996 | const u64 VMXON_NEEDED_FEATURES = FEATURE_CONTROL_LOCKED |
| 7071 | | FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX; | 6997 | | FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX; |
| @@ -7095,9 +7021,37 @@ static int handle_vmon(struct kvm_vcpu *vcpu) | |||
| 7095 | return 1; | 7021 | return 1; |
| 7096 | } | 7022 | } |
| 7097 | 7023 | ||
| 7098 | if (nested_vmx_check_vmptr(vcpu, EXIT_REASON_VMON, NULL)) | 7024 | if (nested_vmx_get_vmptr(vcpu, &vmptr)) |
| 7099 | return 1; | 7025 | return 1; |
| 7100 | 7026 | ||
| 7027 | /* | ||
| 7028 | * SDM 3: 24.11.5 | ||
| 7029 | * The first 4 bytes of VMXON region contain the supported | ||
| 7030 | * VMCS revision identifier | ||
| 7031 | * | ||
| 7032 | * Note - IA32_VMX_BASIC[48] will never be 1 for the nested case; | ||
| 7033 | * which replaces physical address width with 32 | ||
| 7034 | */ | ||
| 7035 | if (!PAGE_ALIGNED(vmptr) || (vmptr >> cpuid_maxphyaddr(vcpu))) { | ||
| 7036 | nested_vmx_failInvalid(vcpu); | ||
| 7037 | return kvm_skip_emulated_instruction(vcpu); | ||
| 7038 | } | ||
| 7039 | |||
| 7040 | page = nested_get_page(vcpu, vmptr); | ||
| 7041 | if (page == NULL) { | ||
| 7042 | nested_vmx_failInvalid(vcpu); | ||
| 7043 | return kvm_skip_emulated_instruction(vcpu); | ||
| 7044 | } | ||
| 7045 | if (*(u32 *)kmap(page) != VMCS12_REVISION) { | ||
| 7046 | kunmap(page); | ||
| 7047 | nested_release_page_clean(page); | ||
| 7048 | nested_vmx_failInvalid(vcpu); | ||
| 7049 | return kvm_skip_emulated_instruction(vcpu); | ||
| 7050 | } | ||
| 7051 | kunmap(page); | ||
| 7052 | nested_release_page_clean(page); | ||
| 7053 | |||
| 7054 | vmx->nested.vmxon_ptr = vmptr; | ||
| 7101 | ret = enter_vmx_operation(vcpu); | 7055 | ret = enter_vmx_operation(vcpu); |
| 7102 | if (ret) | 7056 | if (ret) |
| 7103 | return ret; | 7057 | return ret; |
| @@ -7213,9 +7167,19 @@ static int handle_vmclear(struct kvm_vcpu *vcpu) | |||
| 7213 | if (!nested_vmx_check_permission(vcpu)) | 7167 | if (!nested_vmx_check_permission(vcpu)) |
| 7214 | return 1; | 7168 | return 1; |
| 7215 | 7169 | ||
| 7216 | if (nested_vmx_check_vmptr(vcpu, EXIT_REASON_VMCLEAR, &vmptr)) | 7170 | if (nested_vmx_get_vmptr(vcpu, &vmptr)) |
| 7217 | return 1; | 7171 | return 1; |
| 7218 | 7172 | ||
| 7173 | if (!PAGE_ALIGNED(vmptr) || (vmptr >> cpuid_maxphyaddr(vcpu))) { | ||
| 7174 | nested_vmx_failValid(vcpu, VMXERR_VMCLEAR_INVALID_ADDRESS); | ||
| 7175 | return kvm_skip_emulated_instruction(vcpu); | ||
| 7176 | } | ||
| 7177 | |||
| 7178 | if (vmptr == vmx->nested.vmxon_ptr) { | ||
| 7179 | nested_vmx_failValid(vcpu, VMXERR_VMCLEAR_VMXON_POINTER); | ||
| 7180 | return kvm_skip_emulated_instruction(vcpu); | ||
| 7181 | } | ||
| 7182 | |||
| 7219 | if (vmptr == vmx->nested.current_vmptr) | 7183 | if (vmptr == vmx->nested.current_vmptr) |
| 7220 | nested_release_vmcs12(vmx); | 7184 | nested_release_vmcs12(vmx); |
| 7221 | 7185 | ||
| @@ -7545,9 +7509,19 @@ static int handle_vmptrld(struct kvm_vcpu *vcpu) | |||
| 7545 | if (!nested_vmx_check_permission(vcpu)) | 7509 | if (!nested_vmx_check_permission(vcpu)) |
| 7546 | return 1; | 7510 | return 1; |
| 7547 | 7511 | ||
| 7548 | if (nested_vmx_check_vmptr(vcpu, EXIT_REASON_VMPTRLD, &vmptr)) | 7512 | if (nested_vmx_get_vmptr(vcpu, &vmptr)) |
| 7549 | return 1; | 7513 | return 1; |
| 7550 | 7514 | ||
| 7515 | if (!PAGE_ALIGNED(vmptr) || (vmptr >> cpuid_maxphyaddr(vcpu))) { | ||
| 7516 | nested_vmx_failValid(vcpu, VMXERR_VMPTRLD_INVALID_ADDRESS); | ||
| 7517 | return kvm_skip_emulated_instruction(vcpu); | ||
| 7518 | } | ||
| 7519 | |||
| 7520 | if (vmptr == vmx->nested.vmxon_ptr) { | ||
| 7521 | nested_vmx_failValid(vcpu, VMXERR_VMPTRLD_VMXON_POINTER); | ||
| 7522 | return kvm_skip_emulated_instruction(vcpu); | ||
| 7523 | } | ||
| 7524 | |||
| 7551 | if (vmx->nested.current_vmptr != vmptr) { | 7525 | if (vmx->nested.current_vmptr != vmptr) { |
| 7552 | struct vmcs12 *new_vmcs12; | 7526 | struct vmcs12 *new_vmcs12; |
| 7553 | struct page *page; | 7527 | struct page *page; |
