mirror of
https://github.com/torvalds/linux.git
synced 2024-12-13 22:53:20 +00:00
KVM: x86: Forbid KVM_SET_CPUID{,2} after KVM_RUN
Commit 63f5a1909f
("KVM: x86: Alert userspace that KVM_SET_CPUID{,2}
after KVM_RUN is broken") officially deprecated KVM_SET_CPUID{,2} ioctls
after first successful KVM_RUN and promissed to make this sequence forbiden
in 5.16. It's time to fulfil the promise.
Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
Message-Id: <20211122175818.608220-3-vkuznets@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
6c1186430a
commit
feb627e8d6
@ -5025,6 +5025,14 @@ void kvm_mmu_after_set_cpuid(struct kvm_vcpu *vcpu)
|
|||||||
/*
|
/*
|
||||||
* Invalidate all MMU roles to force them to reinitialize as CPUID
|
* Invalidate all MMU roles to force them to reinitialize as CPUID
|
||||||
* information is factored into reserved bit calculations.
|
* information is factored into reserved bit calculations.
|
||||||
|
*
|
||||||
|
* Correctly handling multiple vCPU models with respect to paging and
|
||||||
|
* physical address properties) in a single VM would require tracking
|
||||||
|
* all relevant CPUID information in kvm_mmu_page_role. That is very
|
||||||
|
* undesirable as it would increase the memory requirements for
|
||||||
|
* gfn_track (see struct kvm_mmu_page_role comments). For now that
|
||||||
|
* problem is swept under the rug; KVM's CPUID API is horrific and
|
||||||
|
* it's all but impossible to solve it without introducing a new API.
|
||||||
*/
|
*/
|
||||||
vcpu->arch.root_mmu.mmu_role.ext.valid = 0;
|
vcpu->arch.root_mmu.mmu_role.ext.valid = 0;
|
||||||
vcpu->arch.guest_mmu.mmu_role.ext.valid = 0;
|
vcpu->arch.guest_mmu.mmu_role.ext.valid = 0;
|
||||||
@ -5032,24 +5040,10 @@ void kvm_mmu_after_set_cpuid(struct kvm_vcpu *vcpu)
|
|||||||
kvm_mmu_reset_context(vcpu);
|
kvm_mmu_reset_context(vcpu);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* KVM does not correctly handle changing guest CPUID after KVM_RUN, as
|
* Changing guest CPUID after KVM_RUN is forbidden, see the comment in
|
||||||
* MAXPHYADDR, GBPAGES support, AMD reserved bit behavior, etc.. aren't
|
* kvm_arch_vcpu_ioctl().
|
||||||
* tracked in kvm_mmu_page_role. As a result, KVM may miss guest page
|
|
||||||
* faults due to reusing SPs/SPTEs. Alert userspace, but otherwise
|
|
||||||
* sweep the problem under the rug.
|
|
||||||
*
|
|
||||||
* KVM's horrific CPUID ABI makes the problem all but impossible to
|
|
||||||
* solve, as correctly handling multiple vCPU models (with respect to
|
|
||||||
* paging and physical address properties) in a single VM would require
|
|
||||||
* tracking all relevant CPUID information in kvm_mmu_page_role. That
|
|
||||||
* is very undesirable as it would double the memory requirements for
|
|
||||||
* gfn_track (see struct kvm_mmu_page_role comments), and in practice
|
|
||||||
* no sane VMM mucks with the core vCPU model on the fly.
|
|
||||||
*/
|
*/
|
||||||
if (vcpu->arch.last_vmentry_cpu != -1) {
|
KVM_BUG_ON(vcpu->arch.last_vmentry_cpu != -1, vcpu->kvm);
|
||||||
pr_warn_ratelimited("KVM: KVM_SET_CPUID{,2} after KVM_RUN may cause guest instability\n");
|
|
||||||
pr_warn_ratelimited("KVM: KVM_SET_CPUID{,2} will fail after KVM_RUN starting with Linux 5.16\n");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void kvm_mmu_reset_context(struct kvm_vcpu *vcpu)
|
void kvm_mmu_reset_context(struct kvm_vcpu *vcpu)
|
||||||
|
@ -5148,6 +5148,17 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
|
|||||||
struct kvm_cpuid __user *cpuid_arg = argp;
|
struct kvm_cpuid __user *cpuid_arg = argp;
|
||||||
struct kvm_cpuid cpuid;
|
struct kvm_cpuid cpuid;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* KVM does not correctly handle changing guest CPUID after KVM_RUN, as
|
||||||
|
* MAXPHYADDR, GBPAGES support, AMD reserved bit behavior, etc.. aren't
|
||||||
|
* tracked in kvm_mmu_page_role. As a result, KVM may miss guest page
|
||||||
|
* faults due to reusing SPs/SPTEs. In practice no sane VMM mucks with
|
||||||
|
* the core vCPU model on the fly, so fail.
|
||||||
|
*/
|
||||||
|
r = -EINVAL;
|
||||||
|
if (vcpu->arch.last_vmentry_cpu != -1)
|
||||||
|
goto out;
|
||||||
|
|
||||||
r = -EFAULT;
|
r = -EFAULT;
|
||||||
if (copy_from_user(&cpuid, cpuid_arg, sizeof(cpuid)))
|
if (copy_from_user(&cpuid, cpuid_arg, sizeof(cpuid)))
|
||||||
goto out;
|
goto out;
|
||||||
@ -5158,6 +5169,14 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
|
|||||||
struct kvm_cpuid2 __user *cpuid_arg = argp;
|
struct kvm_cpuid2 __user *cpuid_arg = argp;
|
||||||
struct kvm_cpuid2 cpuid;
|
struct kvm_cpuid2 cpuid;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* KVM_SET_CPUID{,2} after KVM_RUN is forbidded, see the comment in
|
||||||
|
* KVM_SET_CPUID case above.
|
||||||
|
*/
|
||||||
|
r = -EINVAL;
|
||||||
|
if (vcpu->arch.last_vmentry_cpu != -1)
|
||||||
|
goto out;
|
||||||
|
|
||||||
r = -EFAULT;
|
r = -EFAULT;
|
||||||
if (copy_from_user(&cpuid, cpuid_arg, sizeof(cpuid)))
|
if (copy_from_user(&cpuid, cpuid_arg, sizeof(cpuid)))
|
||||||
goto out;
|
goto out;
|
||||||
|
Loading…
Reference in New Issue
Block a user