BPF List
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Kumar Kartikeya Dwivedi" <memxor@gmail.com>, bpf@vger.kernel.org
Subject: Re: [PATCH bpf-next v1 06/20] bpf: Defer bpf_task_wake() to irq_work when IRQs are disabled
Date: Tue, 10 Nov 2026 01:16:14 +0000	[thread overview]
Message-ID: <sashiko-outbox-205948@kernel.org> (raw)
In-Reply-To: <e405280f8db39c5e378b6c42077c8b8f1f2c6d0d.1794269506.git.memxor@gmail.com>

Thank you for your contribution! Sashiko AI review found 2 potential
issues to consider:
- [High] bpf: use-after-free in bpf_task_wake_defer() pinning
  task->usage
- [Medium] bpf: undrained per-CPU wake queue in bpf_task_wake_defer() on
  dying CPU
--

commit 35b974753f83ac79811d129b40ee5a3e768f027c
Author: Kumar Kartikeya Dwivedi <memxor@gmail.com>

bpf: Defer bpf_task_wake() to irq_work when IRQs are disabled

This commit defers bpf_task_wake() calls made with IRQs disabled to a
per-CPU hard irq_work queue using a per-task bpf_wake_node list node.

> diff --git a/kernel/bpf/task_park.c b/kernel/bpf/task_park.c
> index 39c9f085f7a97..5a9b3124312ee 100644
> --- a/kernel/bpf/task_park.c
> +++ b/kernel/bpf/task_park.c
[ ... ]
> +static DEFINE_PER_CPU(struct wake_q_node *, bpf_task_wake_queue);
> +
> +static void bpf_task_wake_deferred(struct irq_work *work)
> +{
> +	struct wake_q_node *node = xchg(this_cpu_ptr(&bpf_task_wake_queue), NULL);
> +
> +	while (node) {
> +		struct task_struct *task = container_of(node, struct task_struct, bpf_wake_node);
> +
> +		node = node->next == WAKE_Q_TAIL ? NULL : node->next;
> +		/* The task may be queued again from here on. */
> +		WRITE_ONCE(task->bpf_wake_node.next, NULL);
> +		wake_up_state(task, TASK_INTERRUPTIBLE);
> +		put_task_struct(task);
> +	}
> +}
> +
> +static DEFINE_PER_CPU(struct irq_work, bpf_task_wake_work) =
> +	IRQ_WORK_INIT_HARD(bpf_task_wake_deferred);
> +
> +static void bpf_task_wake_defer(struct task_struct *task)
> +{
> +	struct wake_q_node *node = &task->bpf_wake_node, *head;
> +
> +	/*
> +	 * The claim, as in __wake_q_add(): NULL is free, anything else is
> +	 * queued. The xchg() that stored the pending word is a full barrier
> +	 * between that store and the claim, so a claim lost to another holder
> +	 * is still covered: the holder's wake follows its own reset of the
> +	 * node, which this claim did not observe, so the task it wakes
> +	 * observes the word.
> +	 */
> +	if (cmpxchg_relaxed(&node->next, NULL, WAKE_Q_TAIL))
> +		return;
> +	get_task_struct(task);

[Severity: High]
Can pinning task via get_task_struct() here cause a refcount addition on
zero and a use-after-free in bpf_task_wake_deferred()?

bpf_task_wake() is registered with KF_RCU, so a tracing or LSM program can
pass a task_struct whose usage count has already reached zero in
__put_task_struct():

__put_task_struct(tsk)
  security_task_free(tsk)
    <BPF program with IRQs disabled>
      bpf_task_wake(tsk, 0)
        bpf_task_wake_defer(tsk)
          get_task_struct(tsk)  <-- refcount_inc on 0
          irq_work_queue(...)
  free_task(tsk)
<irq_work>
  bpf_task_wake_deferred()
    WRITE_ONCE(tsk->bpf_wake_node.next, NULL)  <-- use-after-free
    wake_up_state(tsk, TASK_INTERRUPTIBLE)

A nascent task in copy_process() before rcu_users is initialized is also
freed by delayed_free_task() on fork failure without consulting
tsk->usage.  Pinning task with refcount_inc_not_zero(&task->rcu_users)
before claiming node->next (or releasing node->next on failure) and
dropping it with put_task_struct_rcu_user() in bpf_task_wake_deferred()
would avoid queuing tasks in either state.

> +	head = this_cpu_read(bpf_task_wake_queue);
> +	do {
> +		WRITE_ONCE(node->next, head ?: WAKE_Q_TAIL);
> +	} while (!try_cmpxchg(this_cpu_ptr(&bpf_task_wake_queue), &head, node));
> +	irq_work_queue(this_cpu_ptr(&bpf_task_wake_work));
> +}

[Severity: Medium]
Can a wakeup queued on an outgoing CPU after CPUHP_AP_SMPCFD_DYING stay
undrained while the CPU is offline?

During CPU hotplug teardown, __cpu_disable() disables local IPI delivery
and smpcfd_dying_cpu() runs irq_work_run() at CPUHP_AP_SMPCFD_DYING.
After that callback finishes, the migration stopper thread still parks on
the outgoing CPU and fires trace_sched_waking and trace_sched_switch with
IRQs disabled.  If a BPF program attached there calls bpf_task_wake(),
bpf_task_wake_defer() queues task onto the outgoing CPU's
bpf_task_wake_queue and raised_list, which smpcfd_dead_cpu() ->
irq_work_run_cpu() does not drain because it only flushes lazy_list.

The wakeup is lost and task->bpf_wake_node.next remains non-NULL while the
CPU stays offline, causing subsequent deferred bpf_task_wake() calls for
that task on online CPUs to fail the cmpxchg_relaxed() claim as well.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/cover.1794269506.git.memxor@gmail.com?part=6

  reply	other threads:[~2026-11-10  1:16 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-10  0:27 [PATCH bpf-next v1 00/20] BPF kthreads and waitqueues Kumar Kartikeya Dwivedi
2026-11-10  0:27 ` [PATCH bpf-next v1 01/20] bpf: Add bpf_task_park() and bpf_task_wake() Kumar Kartikeya Dwivedi
2026-11-10  0:27 ` [PATCH bpf-next v1 02/20] bpf: Invalidate what a bpf_task_park() sleep may free Kumar Kartikeya Dwivedi
2026-11-10  0:49   ` sashiko-bot
2026-11-10  0:27 ` [PATCH bpf-next v1 03/20] bpf: Refuse bpf_task_park() in callbacks Kumar Kartikeya Dwivedi
2026-11-10  0:40   ` sashiko-bot
2026-11-10  0:27 ` [PATCH bpf-next v1 04/20] bpf: Propagate bpf_task_park() through global functions Kumar Kartikeya Dwivedi
2026-11-10  4:50   ` bot+bpf-ci
2026-11-10  0:27 ` [PATCH bpf-next v1 05/20] bpf: Verify a function that parks in the context of its caller Kumar Kartikeya Dwivedi
2026-11-10  0:27 ` [PATCH bpf-next v1 06/20] bpf: Defer bpf_task_wake() to irq_work when IRQs are disabled Kumar Kartikeya Dwivedi
2026-11-10  1:16   ` sashiko-bot [this message]
2026-11-10  0:27 ` [PATCH bpf-next v1 07/20] bpf: Keep programs that park away from per-CPU state and tail calls Kumar Kartikeya Dwivedi
2026-11-10  4:50   ` bot+bpf-ci
2026-11-10  0:27 ` [PATCH bpf-next v1 08/20] bpf: Register bpf_task_park() for syscall programs Kumar Kartikeya Dwivedi
2026-11-10  1:21   ` sashiko-bot
2026-11-10  4:50   ` bot+bpf-ci
2026-11-10  0:27 ` [PATCH bpf-next v1 09/20] bpf: Register bpf_task_wake() for all program types Kumar Kartikeya Dwivedi
2026-11-10  1:39   ` sashiko-bot
2026-11-10  4:50   ` bot+bpf-ci
2026-11-10  0:27 ` [PATCH bpf-next v1 10/20] bpf: Add BPF kthreads for syscall programs Kumar Kartikeya Dwivedi
2026-11-10  0:27 ` [PATCH bpf-next v1 11/20] bpf: Let a BPF kthread sleep in bpf_task_park() Kumar Kartikeya Dwivedi
2026-11-10  0:27 ` [PATCH bpf-next v1 12/20] bpf: Add bpf_kthread_bind() to pin a BPF kthread to a CPU Kumar Kartikeya Dwivedi
2026-11-10  4:50   ` bot+bpf-ci
2026-11-10  0:27 ` [PATCH bpf-next v1 13/20] bpf: Add bpf_kthread_attach_cgroup() to place a BPF kthread in a cgroup Kumar Kartikeya Dwivedi
2026-11-10  4:50   ` bot+bpf-ci
2026-11-10  0:27 ` [PATCH bpf-next v1 14/20] selftests/bpf: Test bpf_task_park() and bpf_task_wake() Kumar Kartikeya Dwivedi
2026-11-10  0:27 ` [PATCH bpf-next v1 15/20] selftests/bpf: Test what survives bpf_task_park() Kumar Kartikeya Dwivedi
2026-11-10  0:27 ` [PATCH bpf-next v1 16/20] selftests/bpf: Test bpf_task_park() across functions and callbacks Kumar Kartikeya Dwivedi
2026-11-10  0:27 ` [PATCH bpf-next v1 17/20] selftests/bpf: Test bpf_task_wake() from tracing programs Kumar Kartikeya Dwivedi
2026-11-10  0:27 ` [PATCH bpf-next v1 18/20] selftests/bpf: Test BPF kthreads Kumar Kartikeya Dwivedi
2026-11-10  4:50   ` bot+bpf-ci
2026-11-10  0:27 ` [PATCH bpf-next v1 19/20] selftests/bpf: Test bpf_kthread_bind() Kumar Kartikeya Dwivedi
2026-11-10  0:27 ` [PATCH bpf-next v1 20/20] selftests/bpf: Test bpf_kthread_attach_cgroup() Kumar Kartikeya Dwivedi
2026-11-10  4:50   ` bot+bpf-ci

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=sashiko-outbox-205948@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=memxor@gmail.com \
    --cc=sashiko-reviews@lists.linux.dev \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox