diff options
| author | Ladi Prosek <lprosek@redhat.com> | 2016-11-30 10:03:11 -0500 |
|---|---|---|
| committer | Paolo Bonzini <pbonzini@redhat.com> | 2016-12-08 09:31:10 -0500 |
| commit | 1dc35dacc16b4f13547125c5df2d026d9e46ea01 (patch) | |
| tree | b65c2fffe3be59f812ab38da97b73e249657ce8f | |
| parent | 9ed38ffad47316dbdc16de0de275868c7771754d (diff) | |
KVM: nVMX: check host CR3 on vmentry and vmexit
This commit adds missing host CR3 checks. Before entering guest mode, the value
of CR3 is checked for reserved bits. After returning, nested_vmx_load_cr3 is
called to set the new CR3 value and check and load PDPTRs.
Signed-off-by: Ladi Prosek <lprosek@redhat.com>
Signed-off-by: Radim Krčmář <rkrcmar@redhat.com>
| -rw-r--r-- | arch/x86/include/uapi/asm/vmx.h | 1 | ||||
| -rw-r--r-- | arch/x86/kvm/vmx.c | 25 |
2 files changed, 19 insertions, 7 deletions
diff --git a/arch/x86/include/uapi/asm/vmx.h b/arch/x86/include/uapi/asm/vmx.h index f9dea4fd4107..14458658e988 100644 --- a/arch/x86/include/uapi/asm/vmx.h +++ b/arch/x86/include/uapi/asm/vmx.h | |||
| @@ -133,6 +133,7 @@ | |||
| 133 | { EXIT_REASON_XRSTORS, "XRSTORS" } | 133 | { EXIT_REASON_XRSTORS, "XRSTORS" } |
| 134 | 134 | ||
| 135 | #define VMX_ABORT_SAVE_GUEST_MSR_FAIL 1 | 135 | #define VMX_ABORT_SAVE_GUEST_MSR_FAIL 1 |
| 136 | #define VMX_ABORT_LOAD_HOST_PDPTE_FAIL 2 | ||
| 136 | #define VMX_ABORT_LOAD_HOST_MSR_FAIL 4 | 137 | #define VMX_ABORT_LOAD_HOST_MSR_FAIL 4 |
| 137 | 138 | ||
| 138 | #endif /* _UAPIVMX_H */ | 139 | #endif /* _UAPIVMX_H */ |
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index a0d6e59f4f34..7280a355737e 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c | |||
| @@ -9968,6 +9968,14 @@ static int nested_vmx_store_msr(struct kvm_vcpu *vcpu, u64 gpa, u32 count) | |||
| 9968 | return 0; | 9968 | return 0; |
| 9969 | } | 9969 | } |
| 9970 | 9970 | ||
| 9971 | static bool nested_cr3_valid(struct kvm_vcpu *vcpu, unsigned long val) | ||
| 9972 | { | ||
| 9973 | unsigned long invalid_mask; | ||
| 9974 | |||
| 9975 | invalid_mask = (~0ULL) << cpuid_maxphyaddr(vcpu); | ||
| 9976 | return (val & invalid_mask) == 0; | ||
| 9977 | } | ||
| 9978 | |||
| 9971 | /* | 9979 | /* |
| 9972 | * Load guest's/host's cr3 at nested entry/exit. nested_ept is true if we are | 9980 | * Load guest's/host's cr3 at nested entry/exit. nested_ept is true if we are |
| 9973 | * emulating VM entry into a guest with EPT enabled. | 9981 | * emulating VM entry into a guest with EPT enabled. |
| @@ -9977,11 +9985,8 @@ static int nested_vmx_store_msr(struct kvm_vcpu *vcpu, u64 gpa, u32 count) | |||
| 9977 | static int nested_vmx_load_cr3(struct kvm_vcpu *vcpu, unsigned long cr3, bool nested_ept, | 9985 | static int nested_vmx_load_cr3(struct kvm_vcpu *vcpu, unsigned long cr3, bool nested_ept, |
| 9978 | unsigned long *entry_failure_code) | 9986 | unsigned long *entry_failure_code) |
| 9979 | { | 9987 | { |
| 9980 | unsigned long invalid_mask; | ||
| 9981 | |||
| 9982 | if (cr3 != kvm_read_cr3(vcpu) || (!nested_ept && pdptrs_changed(vcpu))) { | 9988 | if (cr3 != kvm_read_cr3(vcpu) || (!nested_ept && pdptrs_changed(vcpu))) { |
| 9983 | invalid_mask = (~0ULL) << cpuid_maxphyaddr(vcpu); | 9989 | if (!nested_cr3_valid(vcpu, cr3)) { |
| 9984 | if (cr3 & invalid_mask) { | ||
| 9985 | *entry_failure_code = ENTRY_FAIL_DEFAULT; | 9990 | *entry_failure_code = ENTRY_FAIL_DEFAULT; |
| 9986 | return 1; | 9991 | return 1; |
| 9987 | } | 9992 | } |
| @@ -10452,7 +10457,8 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch) | |||
| 10452 | } | 10457 | } |
| 10453 | 10458 | ||
| 10454 | if (!nested_host_cr0_valid(vcpu, vmcs12->host_cr0) || | 10459 | if (!nested_host_cr0_valid(vcpu, vmcs12->host_cr0) || |
| 10455 | !nested_host_cr4_valid(vcpu, vmcs12->host_cr4)) { | 10460 | !nested_host_cr4_valid(vcpu, vmcs12->host_cr4) || |
| 10461 | !nested_cr3_valid(vcpu, vmcs12->host_cr3)) { | ||
| 10456 | nested_vmx_failValid(vcpu, | 10462 | nested_vmx_failValid(vcpu, |
| 10457 | VMXERR_ENTRY_INVALID_HOST_STATE_FIELD); | 10463 | VMXERR_ENTRY_INVALID_HOST_STATE_FIELD); |
| 10458 | goto out; | 10464 | goto out; |
| @@ -10879,6 +10885,7 @@ static void load_vmcs12_host_state(struct kvm_vcpu *vcpu, | |||
| 10879 | struct vmcs12 *vmcs12) | 10885 | struct vmcs12 *vmcs12) |
| 10880 | { | 10886 | { |
| 10881 | struct kvm_segment seg; | 10887 | struct kvm_segment seg; |
| 10888 | unsigned long entry_failure_code; | ||
| 10882 | 10889 | ||
| 10883 | if (vmcs12->vm_exit_controls & VM_EXIT_LOAD_IA32_EFER) | 10890 | if (vmcs12->vm_exit_controls & VM_EXIT_LOAD_IA32_EFER) |
| 10884 | vcpu->arch.efer = vmcs12->host_ia32_efer; | 10891 | vcpu->arch.efer = vmcs12->host_ia32_efer; |
| @@ -10916,8 +10923,12 @@ static void load_vmcs12_host_state(struct kvm_vcpu *vcpu, | |||
| 10916 | 10923 | ||
| 10917 | nested_ept_uninit_mmu_context(vcpu); | 10924 | nested_ept_uninit_mmu_context(vcpu); |
| 10918 | 10925 | ||
| 10919 | kvm_set_cr3(vcpu, vmcs12->host_cr3); | 10926 | /* |
| 10920 | kvm_mmu_reset_context(vcpu); | 10927 | * Only PDPTE load can fail as the value of cr3 was checked on entry and |
| 10928 | * couldn't have changed. | ||
| 10929 | */ | ||
| 10930 | if (nested_vmx_load_cr3(vcpu, vmcs12->host_cr3, false, &entry_failure_code)) | ||
| 10931 | nested_vmx_abort(vcpu, VMX_ABORT_LOAD_HOST_PDPTE_FAIL); | ||
| 10921 | 10932 | ||
| 10922 | if (!enable_ept) | 10933 | if (!enable_ept) |
| 10923 | vcpu->arch.walk_mmu->inject_page_fault = kvm_inject_page_fault; | 10934 | vcpu->arch.walk_mmu->inject_page_fault = kvm_inject_page_fault; |
