From: Ryosuke Yasuoka Date: Sat, 6 Dec 2025 14:09:36 +0000 (+0900) Subject: x86/kvm: Avoid freeing stack-allocated node in kvm_async_pf_queue_task X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=95cc9e7cf03d3646abce4129d5c013af33a7df99;p=thirdparty%2Flinux.git x86/kvm: Avoid freeing stack-allocated node in kvm_async_pf_queue_task kvm_async_pf_queue_task() can incorrectly try to kfree() a node allocated on the stack of kvm_async_pf_task_wait_schedule(). This occurs when a task requests a PF while another task's PF request with the same token is still pending. Since the token is derived from the (u32)address in exc_page_fault(), two different tasks can generate the same token. Currently, kvm_async_pf_queue_task() assumes that any entry found in the list is a dummy entry and tries to kfree() it. To fix this, add a flag to the node structure to distinguish stack-allocated nodes, and only kfree() the node if it is a dummy entry. Signed-off-by: Ryosuke Yasuoka Message-ID: <20251206140939.144038-1-ryasuoka@redhat.com> Signed-off-by: Paolo Bonzini --- diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c index df78ddee0abb..37dc8465e0f5 100644 --- a/arch/x86/kernel/kvm.c +++ b/arch/x86/kernel/kvm.c @@ -89,6 +89,7 @@ struct kvm_task_sleep_node { struct swait_queue_head wq; u32 token; int cpu; + bool dummy; }; static struct kvm_task_sleep_head { @@ -120,15 +121,26 @@ static bool kvm_async_pf_queue_task(u32 token, struct kvm_task_sleep_node *n) raw_spin_lock(&b->lock); e = _find_apf_task(b, token); if (e) { - /* dummy entry exist -> wake up was delivered ahead of PF */ - hlist_del(&e->link); + struct kvm_task_sleep_node *dummy = NULL; + + /* + * The entry can either be a 'dummy' entry (which is put on the + * list when wake-up happens ahead of APF handling completion) + * or a token from another task which should not be touched. + */ + if (e->dummy) { + hlist_del(&e->link); + dummy = e; + } + raw_spin_unlock(&b->lock); - kfree(e); + kfree(dummy); return false; } n->token = token; n->cpu = smp_processor_id(); + n->dummy = false; init_swait_queue_head(&n->wq); hlist_add_head(&n->link, &b->list); raw_spin_unlock(&b->lock); @@ -231,6 +243,7 @@ again: } dummy->token = token; dummy->cpu = smp_processor_id(); + dummy->dummy = true; init_swait_queue_head(&dummy->wq); hlist_add_head(&dummy->link, &b->list); dummy = NULL;