| From 11988499e62b310f3bf6f6d0a807a06d3f9ccc96 Mon Sep 17 00:00:00 2001 |
| From: Sean Christopherson <sean.j.christopherson@intel.com> |
| Date: Tue, 2 Apr 2019 08:19:15 -0700 |
| Subject: KVM: x86: Skip EFER vs. guest CPUID checks for host-initiated writes |
| |
| From: Sean Christopherson <sean.j.christopherson@intel.com> |
| |
| commit 11988499e62b310f3bf6f6d0a807a06d3f9ccc96 upstream. |
| |
| KVM allows userspace to violate consistency checks related to the |
| guest's CPUID model to some degree. Generally speaking, userspace has |
| carte blanche when it comes to guest state so long as jamming invalid |
| state won't negatively affect the host. |
| |
| Currently this is seems to be a non-issue as most of the interesting |
| EFER checks are missing, e.g. NX and LME, but those will be added |
| shortly. Proactively exempt userspace from the CPUID checks so as not |
| to break userspace. |
| |
| Note, the efer_reserved_bits check still applies to userspace writes as |
| that mask reflects the host's capabilities, e.g. KVM shouldn't allow a |
| guest to run with NX=1 if it has been disabled in the host. |
| |
| Fixes: d80174745ba39 ("KVM: SVM: Only allow setting of EFER_SVME when CPUID SVM is set") |
| Cc: stable@vger.kernel.org |
| Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com> |
| Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| arch/x86/kvm/x86.c | 33 ++++++++++++++++++++++----------- |
| 1 file changed, 22 insertions(+), 11 deletions(-) |
| |
| --- a/arch/x86/kvm/x86.c |
| +++ b/arch/x86/kvm/x86.c |
| @@ -990,11 +990,8 @@ static u32 emulated_msrs[] = { |
| |
| static unsigned num_emulated_msrs; |
| |
| -bool kvm_valid_efer(struct kvm_vcpu *vcpu, u64 efer) |
| +static bool __kvm_valid_efer(struct kvm_vcpu *vcpu, u64 efer) |
| { |
| - if (efer & efer_reserved_bits) |
| - return false; |
| - |
| if (efer & EFER_FFXSR) { |
| struct kvm_cpuid_entry2 *feat; |
| |
| @@ -1012,19 +1009,33 @@ bool kvm_valid_efer(struct kvm_vcpu *vcp |
| } |
| |
| return true; |
| + |
| +} |
| +bool kvm_valid_efer(struct kvm_vcpu *vcpu, u64 efer) |
| +{ |
| + if (efer & efer_reserved_bits) |
| + return false; |
| + |
| + return __kvm_valid_efer(vcpu, efer); |
| } |
| EXPORT_SYMBOL_GPL(kvm_valid_efer); |
| |
| -static int set_efer(struct kvm_vcpu *vcpu, u64 efer) |
| +static int set_efer(struct kvm_vcpu *vcpu, struct msr_data *msr_info) |
| { |
| u64 old_efer = vcpu->arch.efer; |
| + u64 efer = msr_info->data; |
| |
| - if (!kvm_valid_efer(vcpu, efer)) |
| - return 1; |
| + if (efer & efer_reserved_bits) |
| + return false; |
| |
| - if (is_paging(vcpu) |
| - && (vcpu->arch.efer & EFER_LME) != (efer & EFER_LME)) |
| - return 1; |
| + if (!msr_info->host_initiated) { |
| + if (!__kvm_valid_efer(vcpu, efer)) |
| + return 1; |
| + |
| + if (is_paging(vcpu) && |
| + (vcpu->arch.efer & EFER_LME) != (efer & EFER_LME)) |
| + return 1; |
| + } |
| |
| efer &= ~EFER_LMA; |
| efer |= vcpu->arch.efer & EFER_LMA; |
| @@ -2055,7 +2066,7 @@ int kvm_set_msr_common(struct kvm_vcpu * |
| break; |
| |
| case MSR_EFER: |
| - return set_efer(vcpu, data); |
| + return set_efer(vcpu, msr_info); |
| case MSR_K7_HWCR: |
| data &= ~(u64)0x40; /* ignore flush filter disable */ |
| data &= ~(u64)0x100; /* ignore ignne emulation enable */ |