From: David Woodhouse <[email protected]>

kvm_vcpu_ioctl_set_cpuid() runs kvm_vcpu_after_set_cpuid() on every
plane twin, but only the calling vCPU is loaded. The vendor callback
writes VMCS/VMCB controls, and on VMX those writes go to whatever VMCS
is loaded on the current pCPU: the caller's, not the twin's. The
twin's controls shadow is updated anyway, so the stale values in its
real VMCS can never be corrected later; a twin created before
KVM_SET_CPUID2 keeps its empty-CPUID controls (RDSEED/RDRAND exiting
among them), and the guest's higher VTL takes a spurious #UD on its
first RDSEED.

Swap the twin in as the loaded vCPU around its update. Plane ioctls
all share the common vCPU mutex, so the twin cannot be loaded
elsewhere concurrently.

Signed-off-by: David Woodhouse <[email protected]>
Assisted-by: LLM
---
 arch/x86/kvm/cpuid.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
index fe8a793b1643..f744e7845843 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -592,7 +592,20 @@ static int kvm_set_cpuid(struct kvm_vcpu *vcpu, struct 
kvm_cpuid_entry2 *e2,
 #ifdef CONFIG_KVM_XEN
                v->arch.xen.cpuid = kvm_get_hypervisor_cpuid(vcpu, 
XEN_SIGNATURE);
 #endif
+               /*
+                * The ioctl loaded the calling vCPU; updating a twin's
+                * VMCS/VMCB controls requires that twin to be the loaded
+                * one, so swap it in around the update.
+                */
+               if (v != vcpu) {
+                       vcpu_put(vcpu);
+                       vcpu_load(v);
+               }
                kvm_vcpu_after_set_cpuid(v);
+               if (v != vcpu) {
+                       vcpu_put(v);
+                       vcpu_load(vcpu);
+               }
        }
 
 success:
-- 
2.50.1


Reply via email to