From: David Woodhouse <[email protected]>

The IPI virtualization PID table is indexed by vCPU ID, and a plane
vCPU has the same vCPU ID as its plane 0 twin. vmx_vcpu_create() for a
twin therefore repoints plane 0's entry at the twin's posted-interrupt
descriptor, and vmx_vcpu_free() for a twin (including the error path
of a failed KVM_CREATE_VCPU on a plane fd) clears it. Plane 0 is left
with no valid entry, or one naming a freed descriptor.

Nothing consumes the table while that is the case today: a VM with
planes has APICv inhibited, so IPIv stays off. But the entry must not
depend on that. Fill and clear it for the plane 0 vCPU only.

Fixes the IPIv PID-table handling for the plane vCPUs that "KVM:
Implement KVM_CREATE_VCPU ioctl for planes" creates.

Fixes: https://lore.kernel.org/all/[email protected]/
Signed-off-by: David Woodhouse <[email protected]>
---
 arch/x86/kvm/vmx/vmx.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index 44d0e8eba45b..591c7745e3e9 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -7525,7 +7525,8 @@ void vmx_vcpu_free(struct kvm_vcpu *vcpu)
        free_loaded_vmcs(vmx->loaded_vmcs);
        free_page((unsigned long)vmx->ve_info);
 
-       if (vmx_can_use_ipiv(vcpu))
+       /* See vmx_vcpu_create(): only the plane 0 vCPU owns the entry. */
+       if (vmx_can_use_ipiv(vcpu) && !vcpu->plane_level)
                WRITE_ONCE(to_kvm_vmx(vcpu->kvm)->pid_table[vcpu->vcpu_id], 0);
 }
 
@@ -7614,7 +7615,12 @@ int vmx_vcpu_create(struct kvm_vcpu *vcpu)
                vmx->ve_info = page_to_virt(page);
        }
 
-       if (vmx_can_use_ipiv(vcpu))
+       /*
+        * The PID table is indexed by vCPU ID, which a plane vCPU shares
+        * with its plane 0 twin: only plane 0 fills the entry, or creating
+        * (and freeing) a twin would repoint (and clear) plane 0's.
+        */
+       if (vmx_can_use_ipiv(vcpu) && !vcpu->plane_level)
                WRITE_ONCE(to_kvm_vmx(vcpu->kvm)->pid_table[vcpu->vcpu_id],
                           __pa(&vmx->vt.pi_desc) | PID_TABLE_ENTRY_VALID);
 
-- 
2.50.1


Reply via email to