If a vCPU thread is migrated between an async page fault vmexit and the call to kvm_async_pf_wait_schedule(), the wait will occur on a different CPU than the page ready notification. When this happens, kvm_async_pf_wait_schedule() can exit and free the on-stack node before swake_up_one() finishes. Avoid this by protecting the accesses to &n.link with the bucket spinlock. Note that in principle this could use a single critical section that also covers kvm_async_pf_queue_task(), but that call is going to be moved out of kvm_async_pf_wait_schedule(). Cc: stable@vger.kernel.org Cc: Sean Christopherson Signed-off-by: Paolo Bonzini --- arch/x86/kernel/kvm.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c index 9f0efbe94793..6c0a794ed89a 100644 --- a/arch/x86/kernel/kvm.c +++ b/arch/x86/kernel/kvm.c @@ -152,6 +152,8 @@ static bool kvm_async_pf_queue_task(u32 token, struct kvm_task_sleep_node *n) */ void kvm_async_pf_task_wait_schedule(u32 token) { + u32 key = hash_32(token, KVM_TASK_SLEEP_HASHBITS); + struct kvm_task_sleep_head *b = &async_pf_sleepers[key]; struct kvm_task_sleep_node n; DECLARE_SWAITQUEUE(wait); @@ -160,16 +162,20 @@ void kvm_async_pf_task_wait_schedule(u32 token) if (!kvm_async_pf_queue_task(token, &n)) return; + raw_spin_lock(&b->lock); for (;;) { prepare_to_swait_exclusive(&n.wq, &wait, TASK_UNINTERRUPTIBLE); if (hlist_unhashed(&n.link)) break; + raw_spin_unlock(&b->lock); local_irq_enable(); schedule(); local_irq_disable(); + raw_spin_lock(&b->lock); } finish_swait(&n.wq, &wait); + raw_spin_unlock(&b->lock); } EXPORT_SYMBOL_FOR_KVM(kvm_async_pf_task_wait_schedule); -- 2.56.0