mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-10 15:13:44 -04:00
KVM: x86: Explicitly do runtime CPUID updates "after" initial setup
Explicitly perform runtime CPUID adjustments as part of the "after set
CPUID" flow to guard against bugs where KVM consumes stale vCPU/CPUID
state during kvm_update_cpuid_runtime(). E.g. see commit 4736d85f0d
("KVM: x86: Use actual kvm_cpuid.base for clearing KVM_FEATURE_PV_UNHALT").
Whacking each mole individually is not sustainable or robust, e.g. while
the aforemention commit fixed KVM's PV features, the same issue lurks for
Xen and Hyper-V features, Xen and Hyper-V simply don't have any runtime
features (though spoiler alert, neither should KVM).
Updating runtime features in the "full" path will also simplify adding a
snapshot of the guest's capabilities, i.e. of caching the intersection of
guest CPUID and kvm_cpu_caps (modulo a few edge cases).
Link: https://lore.kernel.org/r/20241128013424.4096668-5-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
This commit is contained in:
@@ -178,6 +178,9 @@ static int kvm_check_cpuid(struct kvm_vcpu *vcpu,
|
||||
return fpu_enable_guest_xfd_features(&vcpu->arch.guest_fpu, xfeatures);
|
||||
}
|
||||
|
||||
static void __kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu, struct kvm_cpuid_entry2 *entries,
|
||||
int nent);
|
||||
|
||||
/* Check whether the supplied CPUID data is equal to what is already set for the vCPU. */
|
||||
static int kvm_cpuid_check_equal(struct kvm_vcpu *vcpu, struct kvm_cpuid_entry2 *e2,
|
||||
int nent)
|
||||
@@ -185,6 +188,17 @@ static int kvm_cpuid_check_equal(struct kvm_vcpu *vcpu, struct kvm_cpuid_entry2
|
||||
struct kvm_cpuid_entry2 *orig;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Apply runtime CPUID updates to the incoming CPUID entries to avoid
|
||||
* false positives due mismatches on KVM-owned feature flags. Note,
|
||||
* runtime CPUID updates may consume other CPUID-driven vCPU state,
|
||||
* e.g. KVM or Xen CPUID bases. Updating runtime state before full
|
||||
* CPUID processing is functionally correct only because any change in
|
||||
* CPUID is disallowed, i.e. using stale data is ok because the below
|
||||
* checks will reject the change.
|
||||
*/
|
||||
__kvm_update_cpuid_runtime(vcpu, e2, nent);
|
||||
|
||||
if (nent != vcpu->arch.cpuid_nent)
|
||||
return -EINVAL;
|
||||
|
||||
@@ -369,6 +383,8 @@ void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)
|
||||
bitmap_zero(vcpu->arch.governed_features.enabled,
|
||||
KVM_MAX_NR_GOVERNED_FEATURES);
|
||||
|
||||
kvm_update_cpuid_runtime(vcpu);
|
||||
|
||||
/*
|
||||
* If TDP is enabled, let the guest use GBPAGES if they're supported in
|
||||
* hardware. The hardware page walker doesn't let KVM disable GBPAGES,
|
||||
@@ -450,8 +466,6 @@ static int kvm_set_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid_entry2 *e2,
|
||||
{
|
||||
int r;
|
||||
|
||||
__kvm_update_cpuid_runtime(vcpu, e2, nent);
|
||||
|
||||
/*
|
||||
* KVM does not correctly handle changing guest CPUID after KVM_RUN, as
|
||||
* MAXPHYADDR, GBPAGES support, AMD reserved bit behavior, etc.. aren't
|
||||
|
||||
Reference in New Issue
Block a user