All of lore.kernel.org
 help / color / mirror / Atom feed
From: Vitaly Kuznetsov <vkuznets@redhat.com>
To: Ryosuke Yasuoka <ryasuoka@redhat.com>
Cc: x86@kernel.org, kvm@vger.kernel.org,
	linux-kernel@vger.kernel.org, pbonzini@redhat.com,
	tglx@linutronix.de, mingo@redhat.com, bp@alien8.de,
	dave.hansen@linux.intel.com, hpa@zytor.com
Subject: Re: [PATCH] x86/kvm: Avoid freeing stack-allocated node in kvm_async_pf_queue_task
Date: Wed, 03 Dec 2025 14:24:11 +0100	[thread overview]
Message-ID: <87cy4vlmv8.fsf@redhat.com> (raw)
In-Reply-To: <20251122090828.1416464-1-ryasuoka@redhat.com>

Ryosuke Yasuoka <ryasuoka@redhat.com> writes:

> kvm_async_pf_queue_task() can incorrectly remove a node allocated on the
> stack of kvm_async_pf_task_wait_schedule(). This occurs when a task
> request a PF while another task's PF request with the same token is
> still pending. 

The important missing part here is what the 'token' is. exc_page_fault()
sets it to (u32)read_cr2() so indeed I see possibilities that two
different tasks will generate the same token.

> Currently, kvm_async_pf_queue_task() assumes that any
> entry in the list is a dummy entry and tries to kfree(). To fix this,
> add a dummy flag to the node structure and the function should check
> this flag and kfree() only if it is a dummy entry.
>
> Signed-off-by: Ryosuke Yasuoka <ryasuoka@redhat.com>
> ---
>  arch/x86/kernel/kvm.c | 13 +++++++++++--
>  1 file changed, 11 insertions(+), 2 deletions(-)
>
> diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c
> index b67d7c59dca0..2c92ec528379 100644
> --- a/arch/x86/kernel/kvm.c
> +++ b/arch/x86/kernel/kvm.c
> @@ -88,6 +88,7 @@ struct kvm_task_sleep_node {
>  	struct swait_queue_head wq;
>  	u32 token;
>  	int cpu;
> +	bool dummy;
>  };
>  
>  static struct kvm_task_sleep_head {
> @@ -119,10 +120,17 @@ 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) {
> +		struct kvm_task_sleep_node *dummy = NULL;
> +
>  		/* dummy entry exist -> wake up was delivered ahead of PF */
> -		hlist_del(&e->link);
> +		/* Otherwise it should not be freed here. */

I think we can merge these two comments together and write something
better, e.g.
	/* 
         * 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;
>  	}


I think you also need to do 

diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c
index b67d7c59dca0..0a84a3100e72 100644
--- a/arch/x86/kernel/kvm.c
+++ b/arch/x86/kernel/kvm.c
@@ -128,6 +128,7 @@ static bool kvm_async_pf_queue_task(u32 token, struct kvm_task_sleep_node *n)
 
        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);

now as kvm_async_pf_task_wait_schedule() allocates struct
kvm_task_sleep_node() on the stack and thus 'n->dummy' can be anything.

>  
> @@ -230,6 +238,7 @@ static void kvm_async_pf_task_wake(u32 token)
>  		}
>  		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;
>
> base-commit: 2eba5e05d9bcf4cdea995ed51b0f07ba0275794a

Sorry for delayed reply!

-- 
Vitaly


      parent reply	other threads:[~2025-12-03 13:24 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-11-22  9:08 [PATCH] x86/kvm: Avoid freeing stack-allocated node in kvm_async_pf_queue_task Ryosuke Yasuoka
2025-12-02  3:48 ` Ryosuke Yasuoka
2025-12-03 13:24 ` Vitaly Kuznetsov [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87cy4vlmv8.fsf@redhat.com \
    --to=vkuznets@redhat.com \
    --cc=bp@alien8.de \
    --cc=dave.hansen@linux.intel.com \
    --cc=hpa@zytor.com \
    --cc=kvm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@redhat.com \
    --cc=pbonzini@redhat.com \
    --cc=ryasuoka@redhat.com \
    --cc=tglx@linutronix.de \
    --cc=x86@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.