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
