* [PATCH v2 bpf-next] bpf: Fix suspicious RCU usage for sleepable bpf_get_stack()
@ 2026-11-02 7:37 Feng Yang
2026-11-02 8:14 ` bot+bpf-ci
2026-11-03 3:03 ` Alexei Starovoitov
0 siblings, 2 replies; 4+ messages in thread
From: Feng Yang @ 2026-11-02 7:37 UTC (permalink / raw)
To: song, jolsa, ihor.solodrai, kpsingh, matt, ast, daniel, andrii,
eddyz87, memxor, martin.lau, yonghong.song, emil, rostedt,
mhiramat, mathieu.desnoyers
Cc: bpf, linux-trace-kernel
From: Feng Yang <yangfeng@kylinos.cn>
Sleepable BPF programs run under rcu_read_lock_trace(), not classic RCU.
bpf_get_stack() relies on the caller holding a classic RCU read lock:
get_perf_callchain() -> get_callchain_entry() dereferences
callchain_cpus_entries, and the returned entry is read until
callchain_store(). __bpf_get_stack() takes that lock only for the
sleepable variant, i.e. when may_fault is true.
The sleepable variant was added by commit d4dd9775ec24 ("bpf: wire up
sleepable bpf_get_stack() and bpf_get_task_stack() helpers") but only
wired up for kprobe/uprobe. All other program types that can be
sleepable still get the non-sleepable variant:
- tracing_prog_func_proto() serves BPF_TRACE_ITER, fentry/fexit/fmod_ret
and BPF_TRACE_RAW_TP programs, and falls back to
raw_tp_prog_func_proto() for BPF_FUNC_get_stack, which always returns
bpf_get_stack_proto_raw_tp. Sleepable iterators have been allowed
since commit cf83b2d2e2b6 ("bpf: Permit cond_resched for some
iterators"), e.g. for the task_file target.
- tp_prog_func_proto() serves BPF_PROG_TYPE_TRACEPOINT programs and
always returns bpf_get_stack_proto_tp. Sleepable programs of that
type are allowed on syscall tracepoints since commit 8cfb77d30920
("bpf: Verifier support for sleepable tracepoint programs"); they run
through trace_call_bpf_faultable() and bpf_prog_run_array_sleepable(),
which hold rcu_tasks_trace but no classic RCU read lock.
So a sleepable program calling bpf_get_stack() triggers:
WARNING: suspicious RCU usage
suspicious rcu_dereference_check() usage!
Route these paths to bpf_get_stack_sleepable() and mark the new protos
might_sleep, since build_id_parse() may fault in file data for
BPF_F_USER_STACK | BPF_F_USER_BUILD_ID. Sleepable programs that call
bpf_get_stack() from inside a bpf_rcu_read_lock() region are now rejected
by the verifier, which is the correct behavior for a helper that can
sleep.
Reported-by: Kaiyan Mei <M202472210@hust.edu.cn>
Reported-by: Yinhao Hu <dddddd@hust.edu.cn>
Closes: https://lore.kernel.org/all/41ce77bf.17656.1a17b3fcb04.Coremail.kaiyanm@hust.edu.cn/
Signed-off-by: Feng Yang <yangfeng@kylinos.cn>
---
v2: Move regs onto the stack.
v1: https://lore.kernel.org/all/20261028093548.790977-1-yangfeng59949@163.com/
---
kernel/trace/bpf_trace.c | 54 ++++++++++++++++++++++++++++++++++++++--
1 file changed, 52 insertions(+), 2 deletions(-)
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index 14adfb85fdb2..7d8414d85737 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -84,6 +84,7 @@ static struct bpf_raw_event_map *bpf_get_raw_tracepoint_module(const char *name)
u64 bpf_get_stackid(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5);
u64 bpf_get_stack(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5);
+u64 bpf_get_stack_sleepable(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5);
static int bpf_btf_printf_prepare(struct btf_ptr *ptr, u32 btf_ptr_size,
u64 flags, const struct btf **btf,
@@ -1466,6 +1467,26 @@ static const struct bpf_func_proto bpf_get_stack_proto_tp = {
.arg4_type = ARG_ANYTHING,
};
+BPF_CALL_4(bpf_get_stack_tp_sleepable, void *, tp_buff, void *, buf, u32, size,
+ u64, flags)
+{
+ struct pt_regs *regs = *(struct pt_regs **)tp_buff;
+
+ return bpf_get_stack_sleepable((unsigned long) regs, (unsigned long) buf,
+ (unsigned long) size, flags, 0);
+}
+
+static const struct bpf_func_proto bpf_get_stack_proto_tp_sleepable = {
+ .func = bpf_get_stack_tp_sleepable,
+ .gpl_only = true,
+ .might_sleep = true,
+ .ret_type = RET_INTEGER,
+ .arg1_type = ARG_PTR_TO_CTX,
+ .arg2_type = ARG_PTR_TO_UNINIT_MEM,
+ .arg3_type = ARG_MEM_SIZE_OR_ZERO,
+ .arg4_type = ARG_ANYTHING,
+};
+
static const struct bpf_func_proto *
tp_prog_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
{
@@ -1475,7 +1496,8 @@ tp_prog_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
case BPF_FUNC_get_stackid:
return &bpf_get_stackid_proto_tp;
case BPF_FUNC_get_stack:
- return &bpf_get_stack_proto_tp;
+ return prog->sleepable ? &bpf_get_stack_proto_tp_sleepable
+ : &bpf_get_stack_proto_tp;
case BPF_FUNC_get_attach_cookie:
return &bpf_get_attach_cookie_proto_trace;
default:
@@ -1705,6 +1727,33 @@ static const struct bpf_func_proto bpf_get_stack_proto_raw_tp = {
.arg4_type = ARG_ANYTHING,
};
+BPF_CALL_4(bpf_get_stack_raw_tp_sleepable, struct bpf_raw_tracepoint_args *, args,
+ void *, buf, u32, size, u64, flags)
+{
+ /*
+ * Don't take a per-CPU bpf_raw_tp_regs slot here: those slots are a
+ * LIFO nest counter and cannot be held across the sleep that
+ * build_id_parse() may take. Sleepable programs never run in
+ * IRQ/NMI context, so a stack copy is sufficient.
+ */
+ struct pt_regs regs = {};
+
+ perf_fetch_caller_regs(®s);
+ return bpf_get_stack_sleepable((unsigned long) ®s, (unsigned long) buf,
+ (unsigned long) size, flags, 0);
+}
+
+static const struct bpf_func_proto bpf_get_stack_proto_raw_tp_sleepable = {
+ .func = bpf_get_stack_raw_tp_sleepable,
+ .gpl_only = true,
+ .might_sleep = true,
+ .ret_type = RET_INTEGER,
+ .arg1_type = ARG_PTR_TO_CTX,
+ .arg2_type = ARG_PTR_TO_UNINIT_MEM,
+ .arg3_type = ARG_MEM_SIZE_OR_ZERO,
+ .arg4_type = ARG_ANYTHING,
+};
+
static const struct bpf_func_proto *
raw_tp_prog_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
{
@@ -1714,7 +1763,8 @@ raw_tp_prog_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
case BPF_FUNC_get_stackid:
return &bpf_get_stackid_proto_raw_tp;
case BPF_FUNC_get_stack:
- return &bpf_get_stack_proto_raw_tp;
+ return prog->sleepable ? &bpf_get_stack_proto_raw_tp_sleepable
+ : &bpf_get_stack_proto_raw_tp;
case BPF_FUNC_get_attach_cookie:
return &bpf_get_attach_cookie_proto_tracing;
default:
--
2.25.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH v2 bpf-next] bpf: Fix suspicious RCU usage for sleepable bpf_get_stack()
2026-11-02 7:37 [PATCH v2 bpf-next] bpf: Fix suspicious RCU usage for sleepable bpf_get_stack() Feng Yang
@ 2026-11-02 8:14 ` bot+bpf-ci
2026-11-03 3:03 ` Alexei Starovoitov
1 sibling, 0 replies; 4+ messages in thread
From: bot+bpf-ci @ 2026-11-02 8:14 UTC (permalink / raw)
To: yangfeng59949, song, jolsa, ihor.solodrai, kpsingh, matt, ast,
daniel, andrii, eddyz87, memxor, martin.lau, yonghong.song, emil,
rostedt, mhiramat, mathieu.desnoyers
Cc: bpf, linux-trace-kernel, ast, andrii, daniel, martin.lau, eddyz87,
yonghong.song, mason, ihor.solodrai
[-- Attachment #1: Type: text/plain, Size: 4513 bytes --]
> bpf: Fix suspicious RCU usage for sleepable bpf_get_stack()
TL;DR: Commit message only: it understates scope. Sleepable LSM and SYSCALL
programs also get the might_sleep bpf_get_stack(), so calls in
preempt/IRQ-disabled or lock regions are rejected too. Code matches existing
policy.
> bpf: Fix suspicious RCU usage for sleepable bpf_get_stack()
>
> Sleepable BPF programs run under rcu_read_lock_trace(), not classic RCU.
> bpf_get_stack() relies on the caller holding a classic RCU read lock:
> get_perf_callchain() -> get_callchain_entry() dereferences
> callchain_cpus_entries, and the returned entry is read until
> callchain_store(). __bpf_get_stack() takes that lock only for the
> sleepable variant, i.e. when may_fault is true.
>
> The sleepable variant was added by commit d4dd9775ec24 ("bpf: wire up
> sleepable bpf_get_stack() and bpf_get_task_stack() helpers") but only
> wired up for kprobe/uprobe. All other program types that can be
> sleepable still get the non-sleepable variant:
>
> - tracing_prog_func_proto() serves BPF_TRACE_ITER, fentry/fexit/fmod_ret
> and BPF_TRACE_RAW_TP programs, and falls back to
> raw_tp_prog_func_proto() for BPF_FUNC_get_stack, which always returns
> bpf_get_stack_proto_raw_tp. Sleepable iterators have been allowed
> since commit cf83b2d2e2b6 ("bpf: Permit cond_resched for some
> iterators"), e.g. for the task_file target.
>
> - tp_prog_func_proto() serves BPF_PROG_TYPE_TRACEPOINT programs and
> always returns bpf_get_stack_proto_tp. Sleepable programs of that
> type are allowed on syscall tracepoints since commit 8cfb77d30920
> ("bpf: Verifier support for sleepable tracepoint programs"); they run
> through trace_call_bpf_faultable() and bpf_prog_run_array_sleepable(),
> which hold rcu_tasks_trace but no classic RCU read lock.
>
> So a sleepable program calling bpf_get_stack() triggers:
>
> WARNING: suspicious RCU usage
> suspicious rcu_dereference_check() usage!
>
> Route these paths to bpf_get_stack_sleepable() and mark the new protos
> might_sleep, since build_id_parse() may fault in file data for
> BPF_F_USER_STACK | BPF_F_USER_BUILD_ID. Sleepable programs that call
> bpf_get_stack() from inside a bpf_rcu_read_lock() region are now rejected
> by the verifier, which is the correct behavior for a helper that can
> sleep.
>
> Reported-by: Kaiyan Mei <M202472210@hust.edu.cn>
> Reported-by: Yinhao Hu <dddddd@hust.edu.cn>
> Closes: https://lore.kernel.org/all/41ce77bf.17656.1a17b3fcb04.Coremail.kaiyanm@hust.edu.cn/
> Signed-off-by: Feng Yang <yangfeng@kylinos.cn>
The commit message lists tracing_prog_func_proto() (iterators,
fentry/fexit/fmod_ret, BPF_TRACE_RAW_TP) and BPF_PROG_TYPE_TRACEPOINT as the
affected paths, and says only that calls from inside a bpf_rcu_read_lock()
region are now rejected. Is that the full scope of the behaviour change?
The raw_tp_prog_func_proto() change reaches more program types than that:
- BPF_PROG_TYPE_RAW_TRACEPOINT uses it directly, via
raw_tracepoint_verifier_ops.get_func_proto.
- BPF_PROG_TYPE_LSM reaches it through the default case of
bpf_lsm_func_proto() -> tracing_prog_func_proto().
- BPF_PROG_TYPE_SYSCALL, which is always sleepable, reaches it through the
default case of syscall_prog_func_proto() -> tracing_prog_func_proto().
For each of these, a sleepable program's BPF_FUNC_get_stack now resolves to
bpf_get_stack_proto_raw_tp_sleepable, which has .might_sleep = true.
check_helper_call() will then reject the call wherever in_sleepable_context()
is false:
sleepable helper bpf_get_stack#67 in rcu_read_lock region
or the equivalent non-preemptible, IRQ-disabled or lock region variants.
Before the patch these programs loaded and ran, since the old helper never
slept.
The code change itself matches the policy already applied to uprobe programs
and bpf_get_task_stack() by commit 9d02927fdf4e ("bpf: Mark faultable stack
helpers as sleepable"), so only the description of the user-visible scope
looks incomplete.
Could the commit message mention that sleepable LSM and BPF_PROG_TYPE_SYSCALL
programs are affected as well, and that calls from preempt-disabled,
IRQ-disabled and lock-held regions are rejected too, not only calls inside a
bpf_rcu_read_lock() region?
---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/41409077371
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH v2 bpf-next] bpf: Fix suspicious RCU usage for sleepable bpf_get_stack()
2026-11-02 7:37 [PATCH v2 bpf-next] bpf: Fix suspicious RCU usage for sleepable bpf_get_stack() Feng Yang
2026-11-02 8:14 ` bot+bpf-ci
@ 2026-11-03 3:03 ` Alexei Starovoitov
2026-11-03 9:02 ` Feng Yang
1 sibling, 1 reply; 4+ messages in thread
From: Alexei Starovoitov @ 2026-11-03 3:03 UTC (permalink / raw)
To: Feng Yang, song, jolsa, ihor.solodrai, kpsingh, matt, daniel,
andrii, eddyz87, memxor, martin.lau, yonghong.song, emil, rostedt,
mhiramat, mathieu.desnoyers
Cc: bpf, linux-trace-kernel
On Sun, Nov 01, 2026 at 11:37 PM Feng Yang <yangfeng59949@163.com> wrote:
> Route these paths to bpf_get_stack_sleepable() and mark the new protos
> might_sleep, since build_id_parse() may fault in file data for
> BPF_F_USER_STACK | BPF_F_USER_BUILD_ID. Sleepable programs that call
> bpf_get_stack() from inside a bpf_rcu_read_lock() region are now rejected
> by the verifier, which is the correct behavior for a helper that can
> sleep.
That's a new feature. It's not a fix for the splat.
Andrii's point in v1 is about build IDs. That's a good reason for this
patch, but the splat needs Songsen's patch anyway:
https://lore.kernel.org/bpf/20261028121859.994-1-yangsongsen@insta360.com/
Songsen's patch this patch
------------------------------------ --------------- -------------
splat in sleepable progs fixed fixed
splat in bpf_wq, task_work callbacks fixed still there
build ID when the page is paged out no yes
progs that load today all load some rejected
Row 2: the callback is sleepable, but its prog is not.
bpf_wq_work() rcu_read_lock_trace() only
callback_fn() prog->sleepable == false
bpf_get_task_stack() may_fault == false
__bpf_get_stack() no rcu_read_lock()
get_callchain_entry() rcu_dereference(): splat
Row 4: sleepable fentry, lsm, iter, syscall and tracepoint progs that
call bpf_get_stack() under bpf_rcu_read_lock() or bpf_preempt_disable()
load fine today. With this patch the verifier rejects them.
It does so even when flags don't have BPF_F_USER_BUILD_ID.
Pls respin it as a feature, with a new subject and commit log
and a selftest.
pw-bot: cr
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH v2 bpf-next] bpf: Fix suspicious RCU usage for sleepable bpf_get_stack()
2026-11-03 3:03 ` Alexei Starovoitov
@ 2026-11-03 9:02 ` Feng Yang
0 siblings, 0 replies; 4+ messages in thread
From: Feng Yang @ 2026-11-03 9:02 UTC (permalink / raw)
To: alexei.starovoitov
Cc: andrii, bpf, daniel, eddyz87, emil, ihor.solodrai, jolsa, kpsingh,
linux-trace-kernel, martin.lau, mathieu.desnoyers, matt, memxor,
mhiramat, rostedt, song, yangfeng59949, yonghong.song
On Tue, 03 Nov 2026 03:03:02 +0000, Alexei Starovoitov wrote:
> On Sun, Nov 01, 2026 at 11:37 PM Feng Yang <yangfeng59949@163.com> wrote:
> > Route these paths to bpf_get_stack_sleepable() and mark the new protos
> > might_sleep, since build_id_parse() may fault in file data for
> > BPF_F_USER_STACK | BPF_F_USER_BUILD_ID. Sleepable programs that call
> > bpf_get_stack() from inside a bpf_rcu_read_lock() region are now rejected
> > by the verifier, which is the correct behavior for a helper that can
> > sleep.
>
> That's a new feature. It's not a fix for the splat.
> Andrii's point in v1 is about build IDs. That's a good reason for this
> patch, but the splat needs Songsen's patch anyway:
> https://lore.kernel.org/bpf/20261028121859.994-1-yangsongsen@insta360.com/
>
> Songsen's patch this patch
> ------------------------------------ --------------- -------------
> splat in sleepable progs fixed fixed
> splat in bpf_wq, task_work callbacks fixed still there
> build ID when the page is paged out no yes
> progs that load today all load some rejected
>
> Row 2: the callback is sleepable, but its prog is not.
>
> bpf_wq_work() rcu_read_lock_trace() only
> callback_fn() prog->sleepable == false
> bpf_get_task_stack() may_fault == false
> __bpf_get_stack() no rcu_read_lock()
> get_callchain_entry() rcu_dereference(): splat
>
> Row 4: sleepable fentry, lsm, iter, syscall and tracepoint progs that
> call bpf_get_stack() under bpf_rcu_read_lock() or bpf_preempt_disable()
> load fine today. With this patch the verifier rejects them.
> It does so even when flags don't have BPF_F_USER_BUILD_ID.
>
> Pls respin it as a feature, with a new subject and commit log
> and a selftest.
Thanks. I will add the selftest and respin this patch as a feature change.
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-11-03 9:03 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-02 7:37 [PATCH v2 bpf-next] bpf: Fix suspicious RCU usage for sleepable bpf_get_stack() Feng Yang
2026-11-02 8:14 ` bot+bpf-ci
2026-11-03 3:03 ` Alexei Starovoitov
2026-11-03 9:02 ` Feng Yang
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox