* [PATCH + QUESTION] bpf: use cond_resched_tasks_rcu_qs in bpf_fd_array_map_clear() loop
@ 2026-07-16 1:53 Rik van Riel
2026-07-16 2:16 ` sashiko-bot
2026-07-16 3:17 ` Paul E. McKenney
0 siblings, 2 replies; 3+ messages in thread
From: Rik van Riel @ 2026-07-16 1:53 UTC (permalink / raw)
To: Daniel Borkmann
Cc: kernel-team, Andrii Nakryiko, Eduard Zingerman, Song Liu,
Yonghong Song, linux-kernel, bpf, Paul E. McKenney,
Frederic Weisbecker, Neeraj Upadhyay, Ingo Molnar, Peter Zijlstra,
Steven Rostedt
syzkaller creates a PROG_ARRAY with huge max_entries and triggers perf
tracepoint open close in parallel. The hung task detector reports
"INFO: task hung in perf_tp_event_init" with event_mutex held waiting
for synchronize_rcu_tasks().
bpf_fd_array_map_clear walks max_entries under RCU read lock on a
workqueue kworker. Commit 4406942e65ca added cond_resched for classic
RCU, but under PREEMPT it is a no-op and a preempted kworker never
reports RCU-tasks QS. The loop then blocks the grace period while
event_mutex is held in ftrace_shutdown, stalling perf_event_open().
Use cond_resched_tasks_rcu_qs to report RCU-tasks QS independent of
preemption model. The grace period completes and event_mutex is
released normally.
Fixes: da765a2f5993 ("bpf: Add poke dependency tracking for prog array maps")
Fixes: 4406942e65ca ("bpf: Fix RCU stall in bpf_fd_array_map_clear()")
Cc: stable@vger.kernel.org
Signed-off-by: Rik van Riel <riel@surriel.com>
Assisted-by: Claude:claude-opus-4-8
---
QUESTION: should we change cond_resched() instead, so it unblocks RCU
in any preempt configuration where cond_resched() is a noop?
That would take care of every bug of this shape with one change,
and rcu_tasks_qs() looks cheap enough?
kernel/bpf/arraymap.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c
index 248b4818178c..55fd97375130 100644
--- a/kernel/bpf/arraymap.c
+++ b/kernel/bpf/arraymap.c
@@ -1015,7 +1015,8 @@ static void bpf_fd_array_map_clear(struct bpf_map *map, bool need_defer)
for (i = 0; i < array->map.max_entries; i++) {
__fd_array_map_delete_elem(map, &i, need_defer);
- cond_resched();
+ /* cond_resched() is a noop with preempt; unblock RCU */
+ cond_resched_tasks_rcu_qs();
}
}
--
2.53.0-Meta
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH + QUESTION] bpf: use cond_resched_tasks_rcu_qs in bpf_fd_array_map_clear() loop
2026-07-16 1:53 [PATCH + QUESTION] bpf: use cond_resched_tasks_rcu_qs in bpf_fd_array_map_clear() loop Rik van Riel
@ 2026-07-16 2:16 ` sashiko-bot
2026-07-16 3:17 ` Paul E. McKenney
1 sibling, 0 replies; 3+ messages in thread
From: sashiko-bot @ 2026-07-16 2:16 UTC (permalink / raw)
To: Rik van Riel; +Cc: bpf
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
New issues:
- [Medium] The commit message incorrectly claims that `bpf_fd_array_map_clear()` executes 'under RCU read lock'.
Pre-existing issues:
- [High] perf_event_fd_array_release() iterates over the entire map under a single rcu_read_lock() region, causing Classic RCU stalls for large maps.
- [High] The patch only fixes the RCU-tasks stall in bpf_fd_array_map_clear(), leaving identical vulnerabilities in other BPF map teardown functions.
- [High] A Time-Of-Check to Time-Of-Use race in perf_event_fd_array_release can maliciously delete concurrently updated perf events.
--
--- Patch [1]: [PATCH + QUESTION] bpf: use cond_resched_tasks_rcu_qs in bpf_fd_array_map_clear() loop ---
commit c19063bda5ebcdaccc0217e960d2910817786a73
Author: Rik van Riel <riel@surriel.com>
bpf: use cond_resched_tasks_rcu_qs in bpf_fd_array_map_clear() loop
syzkaller creates a PROG_ARRAY with huge max_entries and triggers perf
tracepoint open close in parallel. The hung task detector reports
"INFO: task hung in perf_tp_event_init" with event_mutex held waiting
for synchronize_rcu_tasks().
> bpf_fd_array_map_clear walks max_entries under RCU read lock on a
> workqueue kworker. Commit 4406942e65ca added cond_resched for classic
> RCU, but under PREEMPT it is a no-op and a preempted kworker never
> reports RCU-tasks QS. The loop then blocks the grace period while
> event_mutex is held in ftrace_shutdown, stalling perf_event_open().
[Severity: Medium]
This isn't a bug introduced by this patch, but the commit message incorrectly
claims that bpf_fd_array_map_clear() executes 'under RCU read lock'.
bpf_fd_array_map_clear() is executed via map destruction callbacks (e.g.,
prog_array_map_clear_deferred) on a sleepable workqueue context without holding
rcu_read_lock(). If a classic RCU read lock were actually held, calling
cond_resched_tasks_rcu_qs() (which invokes cond_resched()) would be an illegal
sleeping operation and trigger might_sleep() lockdep splats.
Could the commit message be updated to reflect the actual context?
[ ... ]
> diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c
> index 248b4818178cd..55fd97375130b 100644
> --- a/kernel/bpf/arraymap.c
> +++ b/kernel/bpf/arraymap.c
> @@ -1015,7 +1015,8 @@ static void bpf_fd_array_map_clear(struct bpf_map *map, bool need_defer)
>
> for (i = 0; i < array->map.max_entries; i++) {
> __fd_array_map_delete_elem(map, &i, need_defer);
> - cond_resched();
> + /* cond_resched() is a noop with preempt; unblock RCU */
> + cond_resched_tasks_rcu_qs();
> }
> }
[Severity: High]
This isn't a bug introduced by this patch, but the fix only addresses the
RCU-tasks stall in bpf_fd_array_map_clear(), leaving similar issues in other
BPF map teardown functions.
For instance, fd_htab_map_free() in kernel/bpf/hashtab.c loops over all
buckets without any yield point:
for (i = 0; i < htab->n_buckets; i++) {
head = select_bucket(htab, i);
...
}
Also, bpf_array_free_percpu() in kernel/bpf/arraymap.c loops over max_entries
using only cond_resched():
for (i = 0; i < array->map.max_entries; i++) {
free_percpu(array->pptrs[i]);
cond_resched();
}
Since cond_resched() is a noop under CONFIG_PREEMPT, wouldn't these loops
similarly stall RCU Tasks when freeing huge hash or per-cpu array maps?
[Severity: High]
This is another pre-existing issue, but while we are looking at
arraymap teardown, perf_event_fd_array_release() also has a potential issue.
It iterates over the entire map under a single rcu_read_lock() region:
rcu_read_lock();
for (i = 0; i < array->map.max_entries; i++) {
ee = READ_ONCE(array->ptrs[i]);
if (ee && ee->map_file == map_file)
__fd_array_map_delete_elem(map, &i, true);
}
rcu_read_unlock();
Does this cause Classic RCU stalls for large maps, since it prevents grace
periods from completing without any yield points?
[Severity: High]
Additionally, there seems to be a pre-existing Time-Of-Check to Time-Of-Use
race in perf_event_fd_array_release() calling __fd_array_map_delete_elem().
If Thread A closes a map file, it triggers perf_event_fd_array_release(), which
verifies ee->map_file == map_file.
If Thread B concurrently calls bpf_map_update_elem to replace the element,
Thread A then calls __fd_array_map_delete_elem(), which unconditionally
executes:
old_ptr = xchg(array->ptrs + index, NULL);
Does this mean Thread A could unconditionally nullify Thread B's newly inserted
element, incorrectly deleting it from the map?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260715215314.44423f47@fangorn?part=1
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH + QUESTION] bpf: use cond_resched_tasks_rcu_qs in bpf_fd_array_map_clear() loop
2026-07-16 1:53 [PATCH + QUESTION] bpf: use cond_resched_tasks_rcu_qs in bpf_fd_array_map_clear() loop Rik van Riel
2026-07-16 2:16 ` sashiko-bot
@ 2026-07-16 3:17 ` Paul E. McKenney
1 sibling, 0 replies; 3+ messages in thread
From: Paul E. McKenney @ 2026-07-16 3:17 UTC (permalink / raw)
To: Rik van Riel
Cc: Daniel Borkmann, kernel-team, Andrii Nakryiko, Eduard Zingerman,
Song Liu, Yonghong Song, linux-kernel, bpf, Frederic Weisbecker,
Neeraj Upadhyay, Ingo Molnar, Peter Zijlstra, Steven Rostedt
On Wed, Jul 15, 2026 at 09:53:13PM -0400, Rik van Riel wrote:
> syzkaller creates a PROG_ARRAY with huge max_entries and triggers perf
> tracepoint open close in parallel. The hung task detector reports
> "INFO: task hung in perf_tp_event_init" with event_mutex held waiting
> for synchronize_rcu_tasks().
>
> bpf_fd_array_map_clear walks max_entries under RCU read lock on a
> workqueue kworker. Commit 4406942e65ca added cond_resched for classic
> RCU, but under PREEMPT it is a no-op and a preempted kworker never
> reports RCU-tasks QS. The loop then blocks the grace period while
> event_mutex is held in ftrace_shutdown, stalling perf_event_open().
>
> Use cond_resched_tasks_rcu_qs to report RCU-tasks QS independent of
> preemption model. The grace period completes and event_mutex is
> released normally.
>
> Fixes: da765a2f5993 ("bpf: Add poke dependency tracking for prog array maps")
> Fixes: 4406942e65ca ("bpf: Fix RCU stall in bpf_fd_array_map_clear()")
> Cc: stable@vger.kernel.org
> Signed-off-by: Rik van Riel <riel@surriel.com>
> Assisted-by: Claude:claude-opus-4-8
> ---
> QUESTION: should we change cond_resched() instead, so it unblocks RCU
> in any preempt configuration where cond_resched() is a noop?
>
> That would take care of every bug of this shape with one change,
> and rcu_tasks_qs() looks cheap enough?
Just confirming that rcu_tasks_qs() is quite cheap: Check a constant,
check a flag in the task_struct structure, and, if set, set another flag
in this same structure. If there is no RCU Tasks grace period in effect,
the first flag will always be zero.
Thanx, Paul
> kernel/bpf/arraymap.c | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c
> index 248b4818178c..55fd97375130 100644
> --- a/kernel/bpf/arraymap.c
> +++ b/kernel/bpf/arraymap.c
> @@ -1015,7 +1015,8 @@ static void bpf_fd_array_map_clear(struct bpf_map *map, bool need_defer)
>
> for (i = 0; i < array->map.max_entries; i++) {
> __fd_array_map_delete_elem(map, &i, need_defer);
> - cond_resched();
> + /* cond_resched() is a noop with preempt; unblock RCU */
> + cond_resched_tasks_rcu_qs();
> }
> }
>
> --
> 2.53.0-Meta
>
>
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-07-16 3:17 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-16 1:53 [PATCH + QUESTION] bpf: use cond_resched_tasks_rcu_qs in bpf_fd_array_map_clear() loop Rik van Riel
2026-07-16 2:16 ` sashiko-bot
2026-07-16 3:17 ` Paul E. McKenney
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.