Skip to content

Commit 8c01290

Browse files
committed
KVM: x86: Swap incoming guest CPUID into vCPU before massaging in KVM_SET_CPUID2
When handling KVM_SET_CPUID{,2}, swap the old and new CPUID arrays and lengths before processing the new CPUID, and simply undo the swap if setting the new CPUID fails for whatever reason. To keep the diff reasonable, continue passing the entry array and length to most helpers, and defer the more complete cleanup to future commits. For any sane VMM, setting "bad" CPUID state is not a hot path (or even something that is surviable), and setting guest CPUID before it's known good will allow removing all of KVM's infrastructure for processing CPUID entries directly (as opposed to operating on vcpu->arch.cpuid_entries). Reviewed-by: Maxim Levitsky <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Sean Christopherson <[email protected]>
1 parent 6174004 commit 8c01290

File tree

1 file changed

+32
-22
lines changed

1 file changed

+32
-22
lines changed

arch/x86/kvm/cpuid.c

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -142,10 +142,10 @@ static inline struct kvm_cpuid_entry2 *cpuid_entry2_find(
142142
return NULL;
143143
}
144144

145-
static int kvm_check_cpuid(struct kvm_vcpu *vcpu,
146-
struct kvm_cpuid_entry2 *entries,
147-
int nent)
145+
static int kvm_check_cpuid(struct kvm_vcpu *vcpu)
148146
{
147+
struct kvm_cpuid_entry2 *entries = vcpu->arch.cpuid_entries;
148+
int nent = vcpu->arch.cpuid_nent;
149149
struct kvm_cpuid_entry2 *best;
150150
u64 xfeatures;
151151

@@ -178,9 +178,6 @@ static int kvm_check_cpuid(struct kvm_vcpu *vcpu,
178178
return fpu_enable_guest_xfd_features(&vcpu->arch.guest_fpu, xfeatures);
179179
}
180180

181-
static void __kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu, struct kvm_cpuid_entry2 *entries,
182-
int nent);
183-
184181
/* Check whether the supplied CPUID data is equal to what is already set for the vCPU. */
185182
static int kvm_cpuid_check_equal(struct kvm_vcpu *vcpu, struct kvm_cpuid_entry2 *e2,
186183
int nent)
@@ -196,8 +193,10 @@ static int kvm_cpuid_check_equal(struct kvm_vcpu *vcpu, struct kvm_cpuid_entry2
196193
* CPUID processing is functionally correct only because any change in
197194
* CPUID is disallowed, i.e. using stale data is ok because the below
198195
* checks will reject the change.
196+
*
197+
* Note! @e2 and @nent track the _old_ CPUID entries!
199198
*/
200-
__kvm_update_cpuid_runtime(vcpu, e2, nent);
199+
kvm_update_cpuid_runtime(vcpu);
201200

202201
if (nent != vcpu->arch.cpuid_nent)
203202
return -EINVAL;
@@ -350,9 +349,11 @@ void kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu)
350349
}
351350
EXPORT_SYMBOL_GPL(kvm_update_cpuid_runtime);
352351

353-
static bool kvm_cpuid_has_hyperv(struct kvm_cpuid_entry2 *entries, int nent)
352+
static bool kvm_cpuid_has_hyperv(struct kvm_vcpu *vcpu)
354353
{
355354
#ifdef CONFIG_KVM_HYPERV
355+
struct kvm_cpuid_entry2 *entries = vcpu->arch.cpuid_entries;
356+
int nent = vcpu->arch.cpuid_nent;
356357
struct kvm_cpuid_entry2 *entry;
357358

358359
entry = cpuid_entry2_find(entries, nent, HYPERV_CPUID_INTERFACE,
@@ -429,8 +430,7 @@ void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)
429430
__cr4_reserved_bits(guest_cpuid_has, vcpu);
430431
#undef __kvm_cpu_cap_has
431432

432-
kvm_hv_set_cpuid(vcpu, kvm_cpuid_has_hyperv(vcpu->arch.cpuid_entries,
433-
vcpu->arch.cpuid_nent));
433+
kvm_hv_set_cpuid(vcpu, kvm_cpuid_has_hyperv(vcpu));
434434

435435
/* Invoke the vendor callback only after the above state is updated. */
436436
kvm_x86_call(vcpu_after_set_cpuid)(vcpu);
@@ -471,6 +471,15 @@ static int kvm_set_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid_entry2 *e2,
471471
{
472472
int r;
473473

474+
/*
475+
* Swap the existing (old) entries with the incoming (new) entries in
476+
* order to massage the new entries, e.g. to account for dynamic bits
477+
* that KVM controls, without clobbering the current guest CPUID, which
478+
* KVM needs to preserve in order to unwind on failure.
479+
*/
480+
swap(vcpu->arch.cpuid_entries, e2);
481+
swap(vcpu->arch.cpuid_nent, nent);
482+
474483
/*
475484
* KVM does not correctly handle changing guest CPUID after KVM_RUN, as
476485
* MAXPHYADDR, GBPAGES support, AMD reserved bit behavior, etc.. aren't
@@ -485,35 +494,36 @@ static int kvm_set_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid_entry2 *e2,
485494
if (kvm_vcpu_has_run(vcpu)) {
486495
r = kvm_cpuid_check_equal(vcpu, e2, nent);
487496
if (r)
488-
return r;
489-
490-
kvfree(e2);
491-
return 0;
497+
goto err;
498+
goto success;
492499
}
493500

494501
#ifdef CONFIG_KVM_HYPERV
495-
if (kvm_cpuid_has_hyperv(e2, nent)) {
502+
if (kvm_cpuid_has_hyperv(vcpu)) {
496503
r = kvm_hv_vcpu_init(vcpu);
497504
if (r)
498-
return r;
505+
goto err;
499506
}
500507
#endif
501508

502-
r = kvm_check_cpuid(vcpu, e2, nent);
509+
r = kvm_check_cpuid(vcpu);
503510
if (r)
504-
return r;
505-
506-
kvfree(vcpu->arch.cpuid_entries);
507-
vcpu->arch.cpuid_entries = e2;
508-
vcpu->arch.cpuid_nent = nent;
511+
goto err;
509512

510513
vcpu->arch.kvm_cpuid = kvm_get_hypervisor_cpuid(vcpu, KVM_SIGNATURE);
511514
#ifdef CONFIG_KVM_XEN
512515
vcpu->arch.xen.cpuid = kvm_get_hypervisor_cpuid(vcpu, XEN_SIGNATURE);
513516
#endif
514517
kvm_vcpu_after_set_cpuid(vcpu);
515518

519+
success:
520+
kvfree(e2);
516521
return 0;
522+
523+
err:
524+
swap(vcpu->arch.cpuid_entries, e2);
525+
swap(vcpu->arch.cpuid_nent, nent);
526+
return r;
517527
}
518528

519529
/* when an old userspace process fills a new kernel module */

0 commit comments

Comments
 (0)