* [PATCH bpf v3 0/2] disable private stack for sleepable programs
@ 2026-08-22 22:54 Christian Simon
2026-08-22 22:54 ` [PATCH bpf v3 1/2] bpf: " Christian Simon
2026-08-22 22:54 ` [PATCH bpf v3 2/2] selftests/bpf: verify preemptible uprobes avoid private stack Christian Simon
0 siblings, 2 replies; 14+ messages in thread
From: Christian Simon @ 2026-08-22 22:54 UTC (permalink / raw)
To: bpf
Cc: Christian Simon, ast, andrii, daniel, martin.lau, tj,
yonghong.song, stable, andrii.nakryiko, olsajiri
A JITed BPF program can use one private stack per program and CPU.
Sleepable programs can be preempted, allowing another task to run the
same program on the same CPU. The second invocation then reuses and can
overwrite the first invocation's private stack.
This patch series disables private stacks for sleepable programs and
adds a selftest covering that stack corruption.
---
Changes in v3:
- Target sleepable only.
- Add the powerpc Fixes tag.
- Split fix and selftests
v2: https://lore.kernel.org/bpf/20260818203234.1142913-1-simon@swine.de/
Christian Simon (2):
bpf: disable private stack for sleepable programs
selftests/bpf: verify preemptible uprobes avoid private stack
kernel/bpf/verifier.c | 9 +
.../bpf/prog_tests/uprobe_sleepable_stack.c | 165 ++++++++++++++++++
.../bpf/progs/uprobe_sleepable_stack.c | 89 ++++++++++
3 files changed, 263 insertions(+)
create mode 100644 tools/testing/selftests/bpf/prog_tests/uprobe_sleepable_stack.c
create mode 100644 tools/testing/selftests/bpf/progs/uprobe_sleepable_stack.c
base-commit: 75b0a6db4300e4c2c9e97a0848deaa7acfb42fb7
--
2.54.0
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH bpf v3 1/2] bpf: disable private stack for sleepable programs
2026-08-22 22:54 [PATCH bpf v3 0/2] disable private stack for sleepable programs Christian Simon
@ 2026-08-22 22:54 ` Christian Simon
2026-08-22 23:10 ` sashiko-bot
` (2 more replies)
2026-08-22 22:54 ` [PATCH bpf v3 2/2] selftests/bpf: verify preemptible uprobes avoid private stack Christian Simon
1 sibling, 3 replies; 14+ messages in thread
From: Christian Simon @ 2026-08-22 22:54 UTC (permalink / raw)
To: bpf
Cc: Christian Simon, ast, andrii, daniel, martin.lau, tj,
yonghong.song, stable, andrii.nakryiko, olsajiri
A JITed BPF program can use one private stack per program and CPU.
Sleepable programs can be preempted, allowing another task to run the
same program on the same CPU. The second invocation then reuses and can
overwrite the first invocation's private stack.
Disable private stack for sleepable programs so they use the regular kernel
stack, which handles preemption correctly. This change is intentionally
limited to programs marked sleepable; preemptible non-sleepable dispatch
paths require separate protection.
Fixes: 7d1cd70d4b16 ("bpf, x86: Support private stack in jit")
Fixes: 6c17a882d380 ("bpf, arm64: JIT support for private stack")
Fixes: 156d985123b6 ("powerpc64/bpf: Implement JIT support for private stack")
Cc: stable@vger.kernel.org
Signed-off-by: Christian Simon <simon@swine.de>
---
kernel/bpf/verifier.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 5e37ca75e5c4..038753ef07a9 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -5237,6 +5237,15 @@ static enum priv_stack_mode bpf_enable_priv_stack(struct bpf_prog *prog)
if (!bpf_jit_supports_private_stack())
return NO_PRIV_STACK;
+ /*
+ * Sleepable programs can be preempted, allowing another task to run
+ * the same program on the same CPU. Since private stack is per-CPU
+ * and per-program, the second invocation would corrupt the first's
+ * stack. Disable private stack for sleepable programs.
+ */
+ if (prog->sleepable)
+ return NO_PRIV_STACK;
+
/* bpf_prog_check_recur() checks all prog types that use bpf trampoline
* while kprobe/tp/perf_event/raw_tp don't use trampoline hence checked
* explicitly.
--
2.54.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH bpf v3 2/2] selftests/bpf: verify preemptible uprobes avoid private stack
2026-08-22 22:54 [PATCH bpf v3 0/2] disable private stack for sleepable programs Christian Simon
2026-08-22 22:54 ` [PATCH bpf v3 1/2] bpf: " Christian Simon
@ 2026-08-22 22:54 ` Christian Simon
2026-08-22 23:05 ` sashiko-bot
2026-08-22 23:58 ` bot+bpf-ci
1 sibling, 2 replies; 14+ messages in thread
From: Christian Simon @ 2026-08-22 22:54 UTC (permalink / raw)
To: bpf
Cc: Christian Simon, ast, andrii, daniel, martin.lau, tj,
yonghong.song, stable, andrii.nakryiko, olsajiri
Pin two threads to one CPU and overlap invocations of the same uprobe
program. Verify that both invocations execute and that the first
invocation's stack frame is not corrupted by the second.
Cover sleepable classic and multi-uprobe programs with both 64-byte
stack frames, which select private stack when eligible, and small stack
frames as controls. Skip the test when preemption, JIT, or architecture
private-stack support is unavailable.
Signed-off-by: Christian Simon <simon@swine.de>
---
I have noticed the "volatile" warning, I do think it is fine for this
selftests purposes.
.../bpf/prog_tests/uprobe_sleepable_stack.c | 165 ++++++++++++++++++
.../bpf/progs/uprobe_sleepable_stack.c | 89 ++++++++++
2 files changed, 254 insertions(+)
create mode 100644 tools/testing/selftests/bpf/prog_tests/uprobe_sleepable_stack.c
create mode 100644 tools/testing/selftests/bpf/progs/uprobe_sleepable_stack.c
diff --git a/tools/testing/selftests/bpf/prog_tests/uprobe_sleepable_stack.c b/tools/testing/selftests/bpf/prog_tests/uprobe_sleepable_stack.c
new file mode 100644
index 000000000000..a18970d2c584
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/uprobe_sleepable_stack.c
@@ -0,0 +1,165 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Test that preemptible uprobe programs don't use private stack.
+ *
+ * Private stack is per-CPU and per-program, so preemption during a program's
+ * execution would allow another task to corrupt the stack. The verifier must
+ * disable private stack for programs whose invocation can be preempted.
+ *
+ * This test overlaps two invocations of the same uprobe program on the same
+ * CPU and verifies:
+ * 1. Both invocations execute
+ * 2. No stack corruption occurs (each task has its own stack frame)
+ */
+#include <pthread.h>
+#include <sched.h>
+#include <unistd.h>
+
+#include <test_progs.h>
+#include "uprobe_sleepable_stack.skel.h"
+
+static noinline void uprobe_sleepable_stack_trigger(void)
+{
+ asm volatile("");
+}
+
+static void *trigger_uprobe(void *arg)
+{
+ uprobe_sleepable_stack_trigger();
+ return NULL;
+}
+
+static void reset_state(struct uprobe_sleepable_stack *skel)
+{
+ skel->bss->ready = 0;
+ skel->bss->release = 0;
+ skel->bss->executions = 0;
+ skel->bss->corruptions = 0;
+ skel->bss->loop_exhausted = 0;
+}
+
+static void assert_results(struct uprobe_sleepable_stack *skel)
+{
+ ASSERT_EQ(skel->bss->loop_exhausted, 0, "loop_exhausted");
+ ASSERT_EQ(skel->bss->executions, 2, "executions");
+ ASSERT_EQ(skel->bss->corruptions, 0, "corruptions");
+}
+
+static void run_test(struct uprobe_sleepable_stack *skel, bool multi,
+ bool large_stack)
+{
+ LIBBPF_OPTS(bpf_uprobe_opts, opts);
+ LIBBPF_OPTS(bpf_uprobe_multi_opts, multi_opts);
+ const char *binary = "/proc/self/exe";
+ struct bpf_program *prog;
+ struct bpf_link *link;
+ pthread_t thread;
+ long link_err;
+ int err, i;
+
+ reset_state(skel);
+
+ if (multi) {
+ prog = large_stack ? skel->progs.uprobe_multi_sleepable_large_stack :
+ skel->progs.uprobe_multi_sleepable_small_stack;
+ link = bpf_program__attach_uprobe_multi(
+ prog, 0, binary, "uprobe_sleepable_stack_trigger",
+ &multi_opts);
+ } else {
+ opts.func_name = "uprobe_sleepable_stack_trigger";
+ prog = large_stack ? skel->progs.uprobe_sleepable_large_stack :
+ skel->progs.uprobe_sleepable_small_stack;
+ link = bpf_program__attach_uprobe_opts(prog, 0, binary, 0,
+ &opts);
+ }
+
+ link_err = libbpf_get_error(link);
+ if (link_err == -EOPNOTSUPP) {
+ test__skip();
+ return;
+ }
+ if (!ASSERT_OK_PTR(link, "attach_uprobe"))
+ return;
+
+ err = pthread_create(&thread, NULL, trigger_uprobe, NULL);
+ if (!ASSERT_OK(err, "pthread_create"))
+ goto cleanup;
+
+ for (i = 0; i < 10000; i++) {
+ if (__atomic_load_n(&skel->bss->ready, __ATOMIC_ACQUIRE))
+ break;
+ usleep(1000);
+ }
+
+ if (ASSERT_LT(i, 10000, "first_uprobe_ready"))
+ uprobe_sleepable_stack_trigger();
+ __atomic_store_n(&skel->bss->release, 1, __ATOMIC_RELEASE);
+
+ err = pthread_join(thread, NULL);
+ if (!ASSERT_OK(err, "pthread_join"))
+ goto cleanup;
+
+ assert_results(skel);
+
+cleanup:
+ bpf_link__destroy(link);
+}
+
+void test_uprobe_sleepable_stack(void)
+{
+ struct uprobe_sleepable_stack *skel = NULL;
+ cpu_set_t old_mask, mask;
+ bool affinity_set = false;
+ int cpu;
+
+#if !defined(__x86_64__) && !defined(__aarch64__) && !defined(__powerpc64__)
+ test__skip();
+ return;
+#endif
+ if (!env.jit_enabled) {
+ test__skip();
+ return;
+ }
+
+ if (!ASSERT_OK(sched_getaffinity(0, sizeof(old_mask), &old_mask),
+ "get_affinity"))
+ return;
+
+ CPU_ZERO(&mask);
+ for (cpu = 0; cpu < CPU_SETSIZE; cpu++) {
+ if (CPU_ISSET(cpu, &old_mask)) {
+ CPU_SET(cpu, &mask);
+ break;
+ }
+ }
+ if (!ASSERT_LT(cpu, CPU_SETSIZE, "available_cpu"))
+ return;
+ /* Both triggers must run on the same CPU to test stack sharing */
+ if (!ASSERT_OK(sched_setaffinity(0, sizeof(mask), &mask),
+ "set_affinity"))
+ return;
+ affinity_set = true;
+
+ skel = uprobe_sleepable_stack__open_and_load();
+ if (!ASSERT_OK_PTR(skel, "skel_open"))
+ goto cleanup;
+ if (!skel->kconfig->CONFIG_PREEMPTION) {
+ test__skip();
+ goto cleanup;
+ }
+
+ if (test__start_subtest("sleepable_classic_large"))
+ run_test(skel, false, true);
+ if (test__start_subtest("sleepable_classic_small"))
+ run_test(skel, false, false);
+ if (test__start_subtest("sleepable_multi_large"))
+ run_test(skel, true, true);
+ if (test__start_subtest("sleepable_multi_small"))
+ run_test(skel, true, false);
+
+cleanup:
+ uprobe_sleepable_stack__destroy(skel);
+ if (affinity_set)
+ ASSERT_OK(sched_setaffinity(0, sizeof(old_mask), &old_mask),
+ "restore_affinity");
+}
diff --git a/tools/testing/selftests/bpf/progs/uprobe_sleepable_stack.c b/tools/testing/selftests/bpf/progs/uprobe_sleepable_stack.c
new file mode 100644
index 000000000000..07e0ff548720
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/uprobe_sleepable_stack.c
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <vmlinux.h>
+#include <bpf/bpf_helpers.h>
+
+extern bool CONFIG_PREEMPTION __kconfig __weak;
+
+volatile int ready;
+volatile int release;
+volatile int executions;
+volatile int corruptions;
+int loop_exhausted;
+
+static long wait_for_release(__u32 index, void *ctx)
+{
+ return release ? 1 : 0;
+}
+
+/*
+ * Test that preemptible uprobes don't use private stack. A 64-byte frame would
+ * normally trigger private stack selection, but programs whose invocation can
+ * be preempted must not use it. Both invocations must execute without
+ * corruption.
+ */
+static __always_inline int run_stack_test(volatile __u64 *stack)
+{
+ __u64 id = bpf_get_current_pid_tgid();
+ int seq;
+
+ if (!CONFIG_PREEMPTION)
+ return 0;
+
+ stack[0] = id;
+ seq = executions;
+ executions = seq + 1;
+ /*
+ * If private stack were used, an unguarded second invocation would
+ * overwrite the first invocation's frame. With regular stack, each task
+ * has its own stack frame.
+ */
+ if (seq) {
+ stack[0] = ~id;
+ return 0;
+ }
+
+ ready = 1;
+ bpf_loop(1 << 23, wait_for_release, NULL, 0);
+ if (!release)
+ loop_exhausted = 1;
+ if (stack[0] != id)
+ corruptions++;
+
+ return 0;
+}
+
+SEC("uprobe.s//proc/self/exe:uprobe_sleepable_stack_trigger")
+int uprobe_sleepable_large_stack(struct pt_regs *ctx)
+{
+ /* A 64-byte frame would select private stack for non-sleepable progs */
+ volatile __u64 stack[8] = {};
+
+ return run_stack_test(stack);
+}
+
+SEC("uprobe.s//proc/self/exe:uprobe_sleepable_stack_trigger")
+int uprobe_sleepable_small_stack(struct pt_regs *ctx)
+{
+ /* Small stack as control - never triggers private stack */
+ volatile __u64 stack[1] = {};
+
+ return run_stack_test(stack);
+}
+
+SEC("uprobe.multi.s//proc/self/exe:uprobe_sleepable_stack_trigger")
+int uprobe_multi_sleepable_large_stack(struct pt_regs *ctx)
+{
+ volatile __u64 stack[8] = {};
+
+ return run_stack_test(stack);
+}
+
+SEC("uprobe.multi.s//proc/self/exe:uprobe_sleepable_stack_trigger")
+int uprobe_multi_sleepable_small_stack(struct pt_regs *ctx)
+{
+ volatile __u64 stack[1] = {};
+
+ return run_stack_test(stack);
+}
+
+char LICENSE[] SEC("license") = "GPL";
--
2.54.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH bpf v3 2/2] selftests/bpf: verify preemptible uprobes avoid private stack
2026-08-22 22:54 ` [PATCH bpf v3 2/2] selftests/bpf: verify preemptible uprobes avoid private stack Christian Simon
@ 2026-08-22 23:05 ` sashiko-bot
2026-08-22 23:58 ` bot+bpf-ci
1 sibling, 0 replies; 14+ messages in thread
From: sashiko-bot @ 2026-08-22 23:05 UTC (permalink / raw)
To: Christian Simon; +Cc: bpf
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] Spurious test failure (flakiness) due to insufficiently small timeout limit in bpf_loop.
--
--- Patch [2]: [PATCH bpf v3 2/2] selftests/bpf: verify preemptible uprobes avoid private stack ---
commit c17909e48f5484c8e9bf3341a1fc87b98ad29988
Author: Christian Simon <simon@swine.de>
selftests/bpf: verify preemptible uprobes avoid private stack
Pin two threads to one CPU and overlap invocations of the same uprobe
program. Verify that both invocations execute and that the first
invocation's stack frame is not corrupted by the second.
> diff --git a/tools/testing/selftests/bpf/progs/uprobe_sleepable_stack.c b/tools/testing/selftests/bpf/progs/uprobe_sleepable_stack.c
> index 0000000000000..07e0ff5487208
> --- /dev/null
> +++ b/tools/testing/selftests/bpf/progs/uprobe_sleepable_stack.c
[ ... ]
> +static __always_inline int run_stack_test(volatile __u64 *stack)
> +{
[ ... ]
> + ready = 1;
> + bpf_loop(1 << 23, wait_for_release, NULL, 0);
> + if (!release)
> + loop_exhausted = 1;
[Severity: Medium]
Could this iteration limit cause spurious test failures under load?
In a heavily loaded CI environment, the main thread's usleep(1000) can be
delayed significantly (for example, if timer granularity is 10ms or due to
hypervisor latency). On a fast CPU, 8.38M iterations of this trivial callback
might complete in just a few milliseconds, exhausting the loop before the
main thread wakes up and sets release.
If this happens, loop_exhausted is set to 1 and the selftest fails.
Is it possible to safely extend this wait time by wrapping the bpf_loop call
in an outer bounded loop?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260822225444.2774461-1-simon@swine.de?part=2
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH bpf v3 1/2] bpf: disable private stack for sleepable programs
2026-08-22 22:54 ` [PATCH bpf v3 1/2] bpf: " Christian Simon
@ 2026-08-22 23:10 ` sashiko-bot
2026-08-22 23:46 ` bot+bpf-ci
2026-08-26 1:20 ` Alexei Starovoitov
2 siblings, 0 replies; 14+ messages in thread
From: sashiko-bot @ 2026-08-22 23:10 UTC (permalink / raw)
To: Christian Simon; +Cc: bpf
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Non-sleepable BPF uprobe programs remain vulnerable to per-CPU private stack corruption.
--
--- Patch [1]: [PATCH bpf v3 1/2] bpf: disable private stack for sleepable programs ---
commit 5b27c96c855b5a6df31f1d2543a92540c69a5d98
Author: Christian Simon <simon@swine.de>
bpf: disable private stack for sleepable programs
This commit disables the use of private stacks for sleepable BPF programs
since they can be preempted, which would allow a second invocation of the
program on the same CPU to corrupt the first invocation's stack. The fix
forces sleepable programs to use the regular kernel stack which handles
preemption correctly.
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index 5e37ca75e5c4a..038753ef07a99 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -5237,6 +5237,15 @@ static enum priv_stack_mode bpf_enable_priv_stack(struct bpf_prog *prog)
> if (!bpf_jit_supports_private_stack())
> return NO_PRIV_STACK;
>
> + /*
> + * Sleepable programs can be preempted, allowing another task to run
> + * the same program on the same CPU. Since private stack is per-CPU
> + * and per-program, the second invocation would corrupt the first's
> + * stack. Disable private stack for sleepable programs.
> + */
> + if (prog->sleepable)
> + return NO_PRIV_STACK;
> +
> /* bpf_prog_check_recur() checks all prog types that use bpf trampoline
> * while kprobe/tp/perf_event/raw_tp don't use trampoline hence checked
> * explicitly.
[Severity: High]
This is a pre-existing issue and was not introduced by this patch, but does
this leave non-sleepable uprobes vulnerable to the same stack corruption?
The patch correctly fixes sleepable programs, but the commit message mentions
that preemptible non-sleepable dispatch paths require separate protection.
However, non-sleepable uprobes are granted private stacks because they fall
under BPF_PROG_TYPE_KPROBE in the switch statement immediately below this code.
If we look at bpf_prog_run_array_uprobe() in include/linux/bpf.h,
non-sleepable uprobes are executed with only rcu_read_lock():
if (!prog->sleepable)
rcu_read_lock();
run_ctx.bpf_cookie = item->bpf_cookie;
ret &= run_prog(prog, ctx);
item++;
if (!prog->sleepable)
rcu_read_unlock();
Under CONFIG_PREEMPT_RCU and CONFIG_PREEMPT, rcu_read_lock() does not disable
preemption. Could a task executing this non-sleepable uprobe be preempted,
allowing another task on the same CPU to trigger the same uprobe and overwrite
its per-CPU private stack?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260822225444.2774461-1-simon@swine.de?part=1
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH bpf v3 1/2] bpf: disable private stack for sleepable programs
2026-08-22 22:54 ` [PATCH bpf v3 1/2] bpf: " Christian Simon
2026-08-22 23:10 ` sashiko-bot
@ 2026-08-22 23:46 ` bot+bpf-ci
2026-08-26 1:20 ` Alexei Starovoitov
2 siblings, 0 replies; 14+ messages in thread
From: bot+bpf-ci @ 2026-08-22 23:46 UTC (permalink / raw)
To: simon, bpf
Cc: simon, ast, andrii, daniel, martin.lau, tj, yonghong.song, stable,
andrii.nakryiko, olsajiri, ast, andrii, daniel, martin.lau,
eddyz87, yonghong.song, clm, ihor.solodrai
[-- Attachment #1: Type: text/plain, Size: 4332 bytes --]
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index 5e37ca75e5c4..038753ef07a9 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -5237,6 +5237,15 @@ static enum priv_stack_mode bpf_enable_priv_stack(struct bpf_prog *prog)
> if (!bpf_jit_supports_private_stack())
> return NO_PRIV_STACK;
>
> + /*
> + * Sleepable programs can be preempted, allowing another task to run
> + * the same program on the same CPU. Since private stack is per-CPU
> + * and per-program, the second invocation would corrupt the first's
> + * stack. Disable private stack for sleepable programs.
> + */
Is this comment accurate for all the program types below?
For BPF_PROG_TYPE_TRACING / LSM / STRUCT_OPS, private stack is only
granted when bpf_prog_check_recur(prog) holds, and that same predicate
makes bpf_trampoline_enter() install __bpf_prog_enter_sleepable_recur(),
which bumps the per-CPU prog->active counter under migrate_disable() and
skips the nested invocation.
Similarly, the sleepable raw-tracepoint runner __bpf_trace_run() calls
bpf_prog_get_recursion_context().
The statement "the second invocation would corrupt the first's stack"
would be true for sleepable uprobe programs run via uprobe_prog_run(),
which takes no recursion context. Could the comment explain why the check
is placed before the switch rather than in the case arm that actually
needs it?
> + if (prog->sleepable)
> + return NO_PRIV_STACK;
> +
Does placing this check before the prog-type switch have unintended
consequences?
The check strips the private stack from BPF_PROG_TYPE_TRACING / LSM /
STRUCT_OPS even though those paths are already protected. For these types,
bpf_trampoline_enter() consults bpf_prog_check_recur(prog):
kernel/bpf/trampoline.c:bpf_trampoline_enter() {
if (bpf_prog_check_recur(prog))
return sleepable ? __bpf_prog_enter_sleepable_recur :
__bpf_prog_enter_recur;
and __bpf_prog_enter_sleepable_recur() does migrate_disable() and then
bpf_prog_get_recursion_context(prog), which uses a per-CPU prog->active
counter. A second task entering the same program on the same CPU sees
active != 1 and is skipped, so it can never reach the private stack.
The real hole appears to be below the new check: BPF_PROG_TYPE_KPROBE /
TRACEPOINT / PERF_EVENT / RAW_TRACEPOINT return PRIV_STACK_ADAPTIVE
unconditionally. For sleepable uprobes (the only sleepable case allowed by
can_be_sleepable()), the uprobe runner takes no recursion context:
kernel/trace/bpf_trace.c:uprobe_prog_run() {
if (sleepable)
rcu_read_lock_trace();
...
migrate_disable();
err = bpf_prog_run(link->link.prog, regs);
so a sleepable uprobe can genuinely be re-entered on the same CPU.
Moving the check into the case arm (BPF_PROG_TYPE_KPROBE through
BPF_PROG_TYPE_RAW_TRACEPOINT) would close the uprobe hole without taking
the private stack away from the trampoline types that already handle
re-entry.
There's also a user-visible side effect: priv_stack_mode decides how
check_max_stack_depth_subprog() budgets stack. PRIV_STACK_ADAPTIVE checks
each subprog on its own against MAX_BPF_STACK; NO_PRIV_STACK accumulates
depth += subprog_depth across bpf2bpf frames and checks the combined total
against MAX_BPF_STACK (512).
Any existing sleepable program whose bpf2bpf subtree exceeds 512 bytes
total - SEC("fentry.s/..."), SEC("fexit.s/..."), SEC("fmod_ret.s/..."),
SEC("uprobe.s/...") - now fails to load with -EACCES and "combined stack
size of %d calls is %d. Too large", where it verified fine before. The
selftest at tools/testing/selftests/bpf/progs/verifier_private_stack.c:86
("Private stack, subtree > MAX_BPF_STACK", 512-byte main + 32-byte
subprog, __success) has exactly this shape; it only survives because it
uses the non-sleepable SEC("kprobe"). With Cc: stable@vger.kernel.org,
this would break working programs on a stable update.
> /* bpf_prog_check_recur() checks all prog types that use bpf trampoline
> * while kprobe/tp/perf_event/raw_tp don't use trampoline hence checked
> * explicitly.
---
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/32604492082
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH bpf v3 2/2] selftests/bpf: verify preemptible uprobes avoid private stack
2026-08-22 22:54 ` [PATCH bpf v3 2/2] selftests/bpf: verify preemptible uprobes avoid private stack Christian Simon
2026-08-22 23:05 ` sashiko-bot
@ 2026-08-22 23:58 ` bot+bpf-ci
1 sibling, 0 replies; 14+ messages in thread
From: bot+bpf-ci @ 2026-08-22 23:58 UTC (permalink / raw)
To: simon, bpf
Cc: simon, ast, andrii, daniel, martin.lau, tj, yonghong.song, stable,
andrii.nakryiko, olsajiri, ast, andrii, daniel, martin.lau,
eddyz87, yonghong.song, clm, ihor.solodrai
[-- Attachment #1: Type: text/plain, Size: 3109 bytes --]
> diff --git a/tools/testing/selftests/bpf/prog_tests/uprobe_sleepable_stack.c b/tools/testing/selftests/bpf/prog_tests/uprobe_sleepable_stack.c
> new file mode 100644
> index 000000000000..a18970d2c584
> --- /dev/null
> +++ b/tools/testing/selftests/bpf/prog_tests/uprobe_sleepable_stack.c
A subsystem pattern flags this as potentially concerning: the BPF
selftests guide asks whether a new test file for a narrow variant of
behavior should instead be a new case in an existing more general test.
The behavior being tested - that the verifier disables private stack for
sleepable uprobes - is a verifier-level decision made in
bpf_enable_priv_stack() when prog->sleepable is set. The test suite
already has tools/testing/selftests/bpf/progs/verifier_private_stack.c
in the same directory, which covers private-stack selection
deterministically by asserting on JIT output patterns with __jited()
annotations.
This patch adds a 254-line, two-file runtime test that depends on thread
timing and CPU affinity. Adding a SEC("uprobe.s") case to the verifier
test with a 64-byte frame would pin the fix by asserting the absence of
the private-frame-pointer setup instruction, without needing threads or
timing dependencies.
The runtime test does exercise something the verifier test cannot -
actual concurrent same-CPU execution - so this is raised as a question:
would extending verifier_private_stack.c have been a simpler way to pin
the verifier change, or is the runtime concurrency test worth the added
complexity?
[ ... ]
> @@ -0,0 +1,165 @@
[ ... ]
> +void test_uprobe_sleepable_stack(void)
> +{
> + struct uprobe_sleepable_stack *skel = NULL;
> + cpu_set_t old_mask, mask;
> + bool affinity_set = false;
> + int cpu;
> +
> +#if !defined(__x86_64__) && !defined(__aarch64__) && !defined(__powerpc64__)
> + test__skip();
> + return;
> +#endif
> + if (!env.jit_enabled) {
> + test__skip();
> + return;
> + }
[ ... ]
> + if (!skel->kconfig->CONFIG_PREEMPTION) {
> + test__skip();
> + goto cleanup;
> + }
[ ... ]
> + link_err = libbpf_get_error(link);
> + if (link_err == -EOPNOTSUPP) {
> + test__skip();
> + return;
> + }
This isn't a bug, but could the skip paths include diagnostics? All four
skip sites (unsupported architecture, JIT disabled, CONFIG_PREEMPTION
unset, and attach returning -EOPNOTSUPP) call bare test__skip() with no
message, so a skipped result gives the operator no way to tell which
prerequisite was missing.
The test_progs framework's test__skip() takes no arguments, so this
matches prevailing practice across the test suite. Is it worth noting
because the missing prerequisite that matters most - runtime preemption
actually being enabled - would be most helpful to communicate.
> diff --git a/tools/testing/selftests/bpf/progs/uprobe_sleepable_stack.c b/tools/testing/selftests/bpf/progs/uprobe_sleepable_stack.c
[ ... ]
---
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/32604492082
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH bpf v3 1/2] bpf: disable private stack for sleepable programs
2026-08-22 22:54 ` [PATCH bpf v3 1/2] bpf: " Christian Simon
2026-08-22 23:10 ` sashiko-bot
2026-08-22 23:46 ` bot+bpf-ci
@ 2026-08-26 1:20 ` Alexei Starovoitov
2026-08-26 13:11 ` Jiri Olsa
2026-08-27 14:56 ` Andrii Nakryiko
2 siblings, 2 replies; 14+ messages in thread
From: Alexei Starovoitov @ 2026-08-26 1:20 UTC (permalink / raw)
To: Christian Simon, bpf
Cc: ast, andrii, daniel, martin.lau, tj, yonghong.song, stable,
andrii.nakryiko, olsajiri
On Sat Aug 22, 2026 at 3:54 PM PDT, Christian Simon wrote:
> A JITed BPF program can use one private stack per program and CPU.
> Sleepable programs can be preempted, allowing another task to run the
> same program on the same CPU. The second invocation then reuses and can
> overwrite the first invocation's private stack.
I'm confused by this. sleepable progs go through __bpf_prog_enter_sleepable_recur()
which has per-prog recurison counter. So preemption of the prog
doesn't break private stack.
If the same prog attemps to execute on the same cpu it will be skipped.
syscall prog types go via bpf_prog_run_array_sleepable()
that have per prog recursions counter.
Looks like we're not doing it for bpf_prog_run_array_uprobe().
I'm not sure what the right trade off here.
I feel universally checking for recursion is better
then selectively disabling private stack for uprobe.
> Disable private stack for sleepable programs so they use the regular kernel
> stack, which handles preemption correctly. This change is intentionally
> limited to programs marked sleepable; preemptible non-sleepable dispatch
> paths require separate protection.
>
> Fixes: 7d1cd70d4b16 ("bpf, x86: Support private stack in jit")
> Fixes: 6c17a882d380 ("bpf, arm64: JIT support for private stack")
> Fixes: 156d985123b6 ("powerpc64/bpf: Implement JIT support for private stack")
> Cc: stable@vger.kernel.org
> Signed-off-by: Christian Simon <simon@swine.de>
> ---
> kernel/bpf/verifier.c | 9 +++++++++
> 1 file changed, 9 insertions(+)
>
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index 5e37ca75e5c4..038753ef07a9 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -5237,6 +5237,15 @@ static enum priv_stack_mode bpf_enable_priv_stack(struct bpf_prog *prog)
> if (!bpf_jit_supports_private_stack())
> return NO_PRIV_STACK;
>
> + /*
> + * Sleepable programs can be preempted, allowing another task to run
> + * the same program on the same CPU. Since private stack is per-CPU
> + * and per-program, the second invocation would corrupt the first's
> + * stack. Disable private stack for sleepable programs.
> + */
> + if (prog->sleepable)
> + return NO_PRIV_STACK;
This is not true in genreal. sleepable progs can use priv stack.
pw-bot: cr
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH bpf v3 1/2] bpf: disable private stack for sleepable programs
2026-08-26 1:20 ` Alexei Starovoitov
@ 2026-08-26 13:11 ` Jiri Olsa
2026-08-27 14:56 ` Andrii Nakryiko
1 sibling, 0 replies; 14+ messages in thread
From: Jiri Olsa @ 2026-08-26 13:11 UTC (permalink / raw)
To: Alexei Starovoitov
Cc: Christian Simon, bpf, ast, andrii, daniel, martin.lau, tj,
yonghong.song, stable, andrii.nakryiko, olsajiri
On Tue, Aug 25, 2026 at 06:20:16PM -0700, Alexei Starovoitov wrote:
> On Sat Aug 22, 2026 at 3:54 PM PDT, Christian Simon wrote:
> > A JITed BPF program can use one private stack per program and CPU.
> > Sleepable programs can be preempted, allowing another task to run the
> > same program on the same CPU. The second invocation then reuses and can
> > overwrite the first invocation's private stack.
>
> I'm confused by this. sleepable progs go through __bpf_prog_enter_sleepable_recur()
> which has per-prog recurison counter. So preemption of the prog
> doesn't break private stack.
> If the same prog attemps to execute on the same cpu it will be skipped.
>
> syscall prog types go via bpf_prog_run_array_sleepable()
> that have per prog recursions counter.
>
> Looks like we're not doing it for bpf_prog_run_array_uprobe().
> I'm not sure what the right trade off here.
> I feel universally checking for recursion is better
> then selectively disabling private stack for uprobe.
also during the load we can't tell if kprobe program will be attached
as kprobe or uprobe [1] so having a way to disable private stack for
a program would solve this as well
jirka
[1] https://lore.kernel.org/bpf/ao2f-rBgT0SqX6Pw@krava/
>
> > Disable private stack for sleepable programs so they use the regular kernel
> > stack, which handles preemption correctly. This change is intentionally
> > limited to programs marked sleepable; preemptible non-sleepable dispatch
> > paths require separate protection.
> >
> > Fixes: 7d1cd70d4b16 ("bpf, x86: Support private stack in jit")
> > Fixes: 6c17a882d380 ("bpf, arm64: JIT support for private stack")
> > Fixes: 156d985123b6 ("powerpc64/bpf: Implement JIT support for private stack")
> > Cc: stable@vger.kernel.org
> > Signed-off-by: Christian Simon <simon@swine.de>
> > ---
> > kernel/bpf/verifier.c | 9 +++++++++
> > 1 file changed, 9 insertions(+)
> >
> > diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> > index 5e37ca75e5c4..038753ef07a9 100644
> > --- a/kernel/bpf/verifier.c
> > +++ b/kernel/bpf/verifier.c
> > @@ -5237,6 +5237,15 @@ static enum priv_stack_mode bpf_enable_priv_stack(struct bpf_prog *prog)
> > if (!bpf_jit_supports_private_stack())
> > return NO_PRIV_STACK;
> >
> > + /*
> > + * Sleepable programs can be preempted, allowing another task to run
> > + * the same program on the same CPU. Since private stack is per-CPU
> > + * and per-program, the second invocation would corrupt the first's
> > + * stack. Disable private stack for sleepable programs.
> > + */
> > + if (prog->sleepable)
> > + return NO_PRIV_STACK;
>
> This is not true in genreal. sleepable progs can use priv stack.
>
> pw-bot: cr
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH bpf v3 1/2] bpf: disable private stack for sleepable programs
2026-08-26 1:20 ` Alexei Starovoitov
2026-08-26 13:11 ` Jiri Olsa
@ 2026-08-27 14:56 ` Andrii Nakryiko
2026-08-27 16:35 ` Alexei Starovoitov
1 sibling, 1 reply; 14+ messages in thread
From: Andrii Nakryiko @ 2026-08-27 14:56 UTC (permalink / raw)
To: Alexei Starovoitov
Cc: Christian Simon, bpf, ast, andrii, daniel, martin.lau, tj,
yonghong.song, stable, olsajiri
On Tue, Aug 25, 2026 at 6:20 PM Alexei Starovoitov
<alexei.starovoitov@gmail.com> wrote:
>
> On Sat Aug 22, 2026 at 3:54 PM PDT, Christian Simon wrote:
> > A JITed BPF program can use one private stack per program and CPU.
> > Sleepable programs can be preempted, allowing another task to run the
> > same program on the same CPU. The second invocation then reuses and can
> > overwrite the first invocation's private stack.
>
> I'm confused by this. sleepable progs go through __bpf_prog_enter_sleepable_recur()
> which has per-prog recurison counter. So preemption of the prog
> doesn't break private stack.
> If the same prog attemps to execute on the same cpu it will be skipped.
>
> syscall prog types go via bpf_prog_run_array_sleepable()
> that have per prog recursions counter.
>
> Looks like we're not doing it for bpf_prog_run_array_uprobe().
> I'm not sure what the right trade off here.
> I feel universally checking for recursion is better
> then selectively disabling private stack for uprobe.
I'd really like to avoid adding this "recursion protection" to uprobe.
With uprobes, there is no recursion, it's called from well defined
context in the kernel and you can't have recursive uprobe BPF
programs.
All you can have is a very valid and possible sleepable uprobe
interleaving, which the user cannot prevent or work around, they have
no control over this and it's just a fact of life.
E.g., a simple scenario, we attach one bpf program (let's call it U)
to some USDT. BPF program U is sleepable and actually can sleep due to
page faults (e.g., unwinding Python stack trace requires sleepable
mode for reliably getting filename strings from Python runtime, which
are not always paged in).
In such a case, you can have thread A and thread B both hitting the
same USDT (e.g., somewhere in memory allocator or whatnot). Let's say
thread A hits it first on CPU X, BPF program U starts executing and
unwinding Python stack, does bpf_copy_from_user() for string contents
and causes page fault, is taken off CPU X. Meanwhile thread B hits
USDT on the same CPU X, kernel runs program U, and it is supposed to
work completely independently and concurrently (no shared state or
whatever) from U's execution in thread A.
Yet, if we add this per-CPU "recursion check", we'll just skip U's
execution for thread B. This is data loss, and it's very bad in
practice because it frequently just invalidates the entire data
collection trustworthiness.
So I think we should disable private stack for uprobes (sleepable or
not) instead. I'm not sure private stack buys us anything for uprobe
cases.
As Jiri mentioned, at verification/jitting time we can't tell kprobe
from uprobe, though, so that's a bit of a problem, but it's a separate
discussion we should have. Perhaps having an extra expected attach
type, or type, or some program flag to designate uprobe program as
such would be appropriate, not sure. Let's discuss that.
But please, let's not make uprobes unreliable for no good reason.
>
> > Disable private stack for sleepable programs so they use the regular kernel
> > stack, which handles preemption correctly. This change is intentionally
> > limited to programs marked sleepable; preemptible non-sleepable dispatch
> > paths require separate protection.
> >
> > Fixes: 7d1cd70d4b16 ("bpf, x86: Support private stack in jit")
> > Fixes: 6c17a882d380 ("bpf, arm64: JIT support for private stack")
> > Fixes: 156d985123b6 ("powerpc64/bpf: Implement JIT support for private stack")
> > Cc: stable@vger.kernel.org
> > Signed-off-by: Christian Simon <simon@swine.de>
> > ---
> > kernel/bpf/verifier.c | 9 +++++++++
> > 1 file changed, 9 insertions(+)
> >
> > diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> > index 5e37ca75e5c4..038753ef07a9 100644
> > --- a/kernel/bpf/verifier.c
> > +++ b/kernel/bpf/verifier.c
> > @@ -5237,6 +5237,15 @@ static enum priv_stack_mode bpf_enable_priv_stack(struct bpf_prog *prog)
> > if (!bpf_jit_supports_private_stack())
> > return NO_PRIV_STACK;
> >
> > + /*
> > + * Sleepable programs can be preempted, allowing another task to run
> > + * the same program on the same CPU. Since private stack is per-CPU
> > + * and per-program, the second invocation would corrupt the first's
> > + * stack. Disable private stack for sleepable programs.
> > + */
> > + if (prog->sleepable)
> > + return NO_PRIV_STACK;
>
> This is not true in genreal. sleepable progs can use priv stack.
>
> pw-bot: cr
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH bpf v3 1/2] bpf: disable private stack for sleepable programs
2026-08-27 14:56 ` Andrii Nakryiko
@ 2026-08-27 16:35 ` Alexei Starovoitov
2026-08-27 16:40 ` Andrii Nakryiko
0 siblings, 1 reply; 14+ messages in thread
From: Alexei Starovoitov @ 2026-08-27 16:35 UTC (permalink / raw)
To: Andrii Nakryiko
Cc: Christian Simon, bpf, Alexei Starovoitov, Andrii Nakryiko,
Daniel Borkmann, Martin KaFai Lau, Tejun Heo, Yonghong Song,
stable, Jiri Olsa
On Thu, Aug 27, 2026 at 7:56 AM Andrii Nakryiko
<andrii.nakryiko@gmail.com> wrote:
>
> On Tue, Aug 25, 2026 at 6:20 PM Alexei Starovoitov
> <alexei.starovoitov@gmail.com> wrote:
> >
> > On Sat Aug 22, 2026 at 3:54 PM PDT, Christian Simon wrote:
> > > A JITed BPF program can use one private stack per program and CPU.
> > > Sleepable programs can be preempted, allowing another task to run the
> > > same program on the same CPU. The second invocation then reuses and can
> > > overwrite the first invocation's private stack.
> >
> > I'm confused by this. sleepable progs go through __bpf_prog_enter_sleepable_recur()
> > which has per-prog recurison counter. So preemption of the prog
> > doesn't break private stack.
> > If the same prog attemps to execute on the same cpu it will be skipped.
> >
> > syscall prog types go via bpf_prog_run_array_sleepable()
> > that have per prog recursions counter.
> >
> > Looks like we're not doing it for bpf_prog_run_array_uprobe().
> > I'm not sure what the right trade off here.
> > I feel universally checking for recursion is better
> > then selectively disabling private stack for uprobe.
>
> I'd really like to avoid adding this "recursion protection" to uprobe.
> With uprobes, there is no recursion, it's called from well defined
> context in the kernel and you can't have recursive uprobe BPF
> programs.
>
> All you can have is a very valid and possible sleepable uprobe
> interleaving, which the user cannot prevent or work around, they have
> no control over this and it's just a fact of life.
>
> E.g., a simple scenario, we attach one bpf program (let's call it U)
> to some USDT. BPF program U is sleepable and actually can sleep due to
> page faults (e.g., unwinding Python stack trace requires sleepable
> mode for reliably getting filename strings from Python runtime, which
> are not always paged in).
>
> In such a case, you can have thread A and thread B both hitting the
> same USDT (e.g., somewhere in memory allocator or whatnot). Let's say
> thread A hits it first on CPU X, BPF program U starts executing and
> unwinding Python stack, does bpf_copy_from_user() for string contents
> and causes page fault, is taken off CPU X. Meanwhile thread B hits
> USDT on the same CPU X, kernel runs program U, and it is supposed to
> work completely independently and concurrently (no shared state or
> whatever) from U's execution in thread A.
>
> Yet, if we add this per-CPU "recursion check", we'll just skip U's
> execution for thread B. This is data loss, and it's very bad in
> practice because it frequently just invalidates the entire data
> collection trustworthiness.
ok. fair
> So I think we should disable private stack for uprobes (sleepable or
> not) instead. I'm not sure private stack buys us anything for uprobe
> cases.
why disable priv stack for non-sleepable uprobes?
While non-sleepable bpf prog is executing the same or different
uprobe cannot execute on the same cpu.
So bpf prog can be preempted by kernel execution,
but a user task cannot start preempt bpf prog,
so 2nd uprobe cannot start running,
no?
> As Jiri mentioned, at verification/jitting time we can't tell kprobe
> from uprobe, though, so that's a bit of a problem, but it's a separate
> discussion we should have. Perhaps having an extra expected attach
> type, or type, or some program flag to designate uprobe program as
> such would be appropriate, not sure. Let's discuss that.
we don't have sleepable kprobes.
So disable sleepable && [ku]probe type is enough. no?
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH bpf v3 1/2] bpf: disable private stack for sleepable programs
2026-08-27 16:35 ` Alexei Starovoitov
@ 2026-08-27 16:40 ` Andrii Nakryiko
2026-08-27 16:55 ` Alexei Starovoitov
0 siblings, 1 reply; 14+ messages in thread
From: Andrii Nakryiko @ 2026-08-27 16:40 UTC (permalink / raw)
To: Alexei Starovoitov
Cc: Christian Simon, bpf, Alexei Starovoitov, Andrii Nakryiko,
Daniel Borkmann, Martin KaFai Lau, Tejun Heo, Yonghong Song,
stable, Jiri Olsa
On Thu, Aug 27, 2026 at 9:35 AM Alexei Starovoitov
<alexei.starovoitov@gmail.com> wrote:
>
> On Thu, Aug 27, 2026 at 7:56 AM Andrii Nakryiko
> <andrii.nakryiko@gmail.com> wrote:
> >
> > On Tue, Aug 25, 2026 at 6:20 PM Alexei Starovoitov
> > <alexei.starovoitov@gmail.com> wrote:
> > >
> > > On Sat Aug 22, 2026 at 3:54 PM PDT, Christian Simon wrote:
> > > > A JITed BPF program can use one private stack per program and CPU.
> > > > Sleepable programs can be preempted, allowing another task to run the
> > > > same program on the same CPU. The second invocation then reuses and can
> > > > overwrite the first invocation's private stack.
> > >
> > > I'm confused by this. sleepable progs go through __bpf_prog_enter_sleepable_recur()
> > > which has per-prog recurison counter. So preemption of the prog
> > > doesn't break private stack.
> > > If the same prog attemps to execute on the same cpu it will be skipped.
> > >
> > > syscall prog types go via bpf_prog_run_array_sleepable()
> > > that have per prog recursions counter.
> > >
> > > Looks like we're not doing it for bpf_prog_run_array_uprobe().
> > > I'm not sure what the right trade off here.
> > > I feel universally checking for recursion is better
> > > then selectively disabling private stack for uprobe.
> >
> > I'd really like to avoid adding this "recursion protection" to uprobe.
> > With uprobes, there is no recursion, it's called from well defined
> > context in the kernel and you can't have recursive uprobe BPF
> > programs.
> >
> > All you can have is a very valid and possible sleepable uprobe
> > interleaving, which the user cannot prevent or work around, they have
> > no control over this and it's just a fact of life.
> >
> > E.g., a simple scenario, we attach one bpf program (let's call it U)
> > to some USDT. BPF program U is sleepable and actually can sleep due to
> > page faults (e.g., unwinding Python stack trace requires sleepable
> > mode for reliably getting filename strings from Python runtime, which
> > are not always paged in).
> >
> > In such a case, you can have thread A and thread B both hitting the
> > same USDT (e.g., somewhere in memory allocator or whatnot). Let's say
> > thread A hits it first on CPU X, BPF program U starts executing and
> > unwinding Python stack, does bpf_copy_from_user() for string contents
> > and causes page fault, is taken off CPU X. Meanwhile thread B hits
> > USDT on the same CPU X, kernel runs program U, and it is supposed to
> > work completely independently and concurrently (no shared state or
> > whatever) from U's execution in thread A.
> >
> > Yet, if we add this per-CPU "recursion check", we'll just skip U's
> > execution for thread B. This is data loss, and it's very bad in
> > practice because it frequently just invalidates the entire data
> > collection trustworthiness.
>
> ok. fair
>
great, thanks!
> > So I think we should disable private stack for uprobes (sleepable or
> > not) instead. I'm not sure private stack buys us anything for uprobe
> > cases.
>
> why disable priv stack for non-sleepable uprobes?
> While non-sleepable bpf prog is executing the same or different
> uprobe cannot execute on the same cpu.
> So bpf prog can be preempted by kernel execution,
> but a user task cannot start preempt bpf prog,
> so 2nd uprobe cannot start running,
> no?
I think that changes on preemptible kernels, this was called out in
discussions on previous versions of this patch. So only for that
reason.
For non-preemptible kernels yes, it's only sleepable that is a problem.
>
> > As Jiri mentioned, at verification/jitting time we can't tell kprobe
> > from uprobe, though, so that's a bit of a problem, but it's a separate
> > discussion we should have. Perhaps having an extra expected attach
> > type, or type, or some program flag to designate uprobe program as
> > such would be appropriate, not sure. Let's discuss that.
>
> we don't have sleepable kprobes.
> So disable sleepable && [ku]probe type is enough. no?
Yes, unless we want to also safeguard preemptible kernels. But we can
do that as an extra #ifdef CONFIG_PREEMPT_RT or something?
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH bpf v3 1/2] bpf: disable private stack for sleepable programs
2026-08-27 16:40 ` Andrii Nakryiko
@ 2026-08-27 16:55 ` Alexei Starovoitov
2026-08-27 22:32 ` Jiri Olsa
0 siblings, 1 reply; 14+ messages in thread
From: Alexei Starovoitov @ 2026-08-27 16:55 UTC (permalink / raw)
To: Andrii Nakryiko
Cc: Christian Simon, bpf, Alexei Starovoitov, Andrii Nakryiko,
Daniel Borkmann, Martin KaFai Lau, Tejun Heo, Yonghong Song,
stable, Jiri Olsa
On Thu, Aug 27, 2026 at 9:40 AM Andrii Nakryiko
<andrii.nakryiko@gmail.com> wrote:
>
> On Thu, Aug 27, 2026 at 9:35 AM Alexei Starovoitov
> <alexei.starovoitov@gmail.com> wrote:
> >
> > On Thu, Aug 27, 2026 at 7:56 AM Andrii Nakryiko
> > <andrii.nakryiko@gmail.com> wrote:
> > >
> > > On Tue, Aug 25, 2026 at 6:20 PM Alexei Starovoitov
> > > <alexei.starovoitov@gmail.com> wrote:
> > > >
> > > > On Sat Aug 22, 2026 at 3:54 PM PDT, Christian Simon wrote:
> > > > > A JITed BPF program can use one private stack per program and CPU.
> > > > > Sleepable programs can be preempted, allowing another task to run the
> > > > > same program on the same CPU. The second invocation then reuses and can
> > > > > overwrite the first invocation's private stack.
> > > >
> > > > I'm confused by this. sleepable progs go through __bpf_prog_enter_sleepable_recur()
> > > > which has per-prog recurison counter. So preemption of the prog
> > > > doesn't break private stack.
> > > > If the same prog attemps to execute on the same cpu it will be skipped.
> > > >
> > > > syscall prog types go via bpf_prog_run_array_sleepable()
> > > > that have per prog recursions counter.
> > > >
> > > > Looks like we're not doing it for bpf_prog_run_array_uprobe().
> > > > I'm not sure what the right trade off here.
> > > > I feel universally checking for recursion is better
> > > > then selectively disabling private stack for uprobe.
> > >
> > > I'd really like to avoid adding this "recursion protection" to uprobe.
> > > With uprobes, there is no recursion, it's called from well defined
> > > context in the kernel and you can't have recursive uprobe BPF
> > > programs.
> > >
> > > All you can have is a very valid and possible sleepable uprobe
> > > interleaving, which the user cannot prevent or work around, they have
> > > no control over this and it's just a fact of life.
> > >
> > > E.g., a simple scenario, we attach one bpf program (let's call it U)
> > > to some USDT. BPF program U is sleepable and actually can sleep due to
> > > page faults (e.g., unwinding Python stack trace requires sleepable
> > > mode for reliably getting filename strings from Python runtime, which
> > > are not always paged in).
> > >
> > > In such a case, you can have thread A and thread B both hitting the
> > > same USDT (e.g., somewhere in memory allocator or whatnot). Let's say
> > > thread A hits it first on CPU X, BPF program U starts executing and
> > > unwinding Python stack, does bpf_copy_from_user() for string contents
> > > and causes page fault, is taken off CPU X. Meanwhile thread B hits
> > > USDT on the same CPU X, kernel runs program U, and it is supposed to
> > > work completely independently and concurrently (no shared state or
> > > whatever) from U's execution in thread A.
> > >
> > > Yet, if we add this per-CPU "recursion check", we'll just skip U's
> > > execution for thread B. This is data loss, and it's very bad in
> > > practice because it frequently just invalidates the entire data
> > > collection trustworthiness.
> >
> > ok. fair
> >
>
> great, thanks!
>
> > > So I think we should disable private stack for uprobes (sleepable or
> > > not) instead. I'm not sure private stack buys us anything for uprobe
> > > cases.
> >
> > why disable priv stack for non-sleepable uprobes?
> > While non-sleepable bpf prog is executing the same or different
> > uprobe cannot execute on the same cpu.
> > So bpf prog can be preempted by kernel execution,
> > but a user task cannot start preempt bpf prog,
> > so 2nd uprobe cannot start running,
> > no?
>
> I think that changes on preemptible kernels, this was called out in
> discussions on previous versions of this patch. So only for that
> reason.
my understanding is that preemptable kernel doesn't mean that
bpf prog can be preempted by user space.
only by kernel.
I looked up earlier thread, but don't understand what Jiri meant.
Jiri,
please clarify what problem do you see with non-sleepable uprobes?
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH bpf v3 1/2] bpf: disable private stack for sleepable programs
2026-08-27 16:55 ` Alexei Starovoitov
@ 2026-08-27 22:32 ` Jiri Olsa
0 siblings, 0 replies; 14+ messages in thread
From: Jiri Olsa @ 2026-08-27 22:32 UTC (permalink / raw)
To: Alexei Starovoitov
Cc: Andrii Nakryiko, Christian Simon, bpf, Alexei Starovoitov,
Andrii Nakryiko, Daniel Borkmann, Martin KaFai Lau, Tejun Heo,
Yonghong Song, stable, Jiri Olsa
On Thu, Aug 27, 2026 at 09:55:08AM -0700, Alexei Starovoitov wrote:
> On Thu, Aug 27, 2026 at 9:40 AM Andrii Nakryiko
> <andrii.nakryiko@gmail.com> wrote:
> >
> > On Thu, Aug 27, 2026 at 9:35 AM Alexei Starovoitov
> > <alexei.starovoitov@gmail.com> wrote:
> > >
> > > On Thu, Aug 27, 2026 at 7:56 AM Andrii Nakryiko
> > > <andrii.nakryiko@gmail.com> wrote:
> > > >
> > > > On Tue, Aug 25, 2026 at 6:20 PM Alexei Starovoitov
> > > > <alexei.starovoitov@gmail.com> wrote:
> > > > >
> > > > > On Sat Aug 22, 2026 at 3:54 PM PDT, Christian Simon wrote:
> > > > > > A JITed BPF program can use one private stack per program and CPU.
> > > > > > Sleepable programs can be preempted, allowing another task to run the
> > > > > > same program on the same CPU. The second invocation then reuses and can
> > > > > > overwrite the first invocation's private stack.
> > > > >
> > > > > I'm confused by this. sleepable progs go through __bpf_prog_enter_sleepable_recur()
> > > > > which has per-prog recurison counter. So preemption of the prog
> > > > > doesn't break private stack.
> > > > > If the same prog attemps to execute on the same cpu it will be skipped.
> > > > >
> > > > > syscall prog types go via bpf_prog_run_array_sleepable()
> > > > > that have per prog recursions counter.
> > > > >
> > > > > Looks like we're not doing it for bpf_prog_run_array_uprobe().
> > > > > I'm not sure what the right trade off here.
> > > > > I feel universally checking for recursion is better
> > > > > then selectively disabling private stack for uprobe.
> > > >
> > > > I'd really like to avoid adding this "recursion protection" to uprobe.
> > > > With uprobes, there is no recursion, it's called from well defined
> > > > context in the kernel and you can't have recursive uprobe BPF
> > > > programs.
> > > >
> > > > All you can have is a very valid and possible sleepable uprobe
> > > > interleaving, which the user cannot prevent or work around, they have
> > > > no control over this and it's just a fact of life.
> > > >
> > > > E.g., a simple scenario, we attach one bpf program (let's call it U)
> > > > to some USDT. BPF program U is sleepable and actually can sleep due to
> > > > page faults (e.g., unwinding Python stack trace requires sleepable
> > > > mode for reliably getting filename strings from Python runtime, which
> > > > are not always paged in).
> > > >
> > > > In such a case, you can have thread A and thread B both hitting the
> > > > same USDT (e.g., somewhere in memory allocator or whatnot). Let's say
> > > > thread A hits it first on CPU X, BPF program U starts executing and
> > > > unwinding Python stack, does bpf_copy_from_user() for string contents
> > > > and causes page fault, is taken off CPU X. Meanwhile thread B hits
> > > > USDT on the same CPU X, kernel runs program U, and it is supposed to
> > > > work completely independently and concurrently (no shared state or
> > > > whatever) from U's execution in thread A.
> > > >
> > > > Yet, if we add this per-CPU "recursion check", we'll just skip U's
> > > > execution for thread B. This is data loss, and it's very bad in
> > > > practice because it frequently just invalidates the entire data
> > > > collection trustworthiness.
> > >
> > > ok. fair
> > >
> >
> > great, thanks!
> >
> > > > So I think we should disable private stack for uprobes (sleepable or
> > > > not) instead. I'm not sure private stack buys us anything for uprobe
> > > > cases.
> > >
> > > why disable priv stack for non-sleepable uprobes?
> > > While non-sleepable bpf prog is executing the same or different
> > > uprobe cannot execute on the same cpu.
> > > So bpf prog can be preempted by kernel execution,
> > > but a user task cannot start preempt bpf prog,
> > > so 2nd uprobe cannot start running,
> > > no?
> >
> > I think that changes on preemptible kernels, this was called out in
> > discussions on previous versions of this patch. So only for that
> > reason.
>
> my understanding is that preemptable kernel doesn't mean that
> bpf prog can be preempted by user space.
> only by kernel.
>
> I looked up earlier thread, but don't understand what Jiri meant.
>
> Jiri,
> please clarify what problem do you see with non-sleepable uprobes?
hum.. non-sleepable uprobe prog is run by bpf_prog_run_array_uprobe
and it disables only task migration, preemption is not disabled and
holds rcu_read_lock (which seems ok for preemption)
so I'm not sure why it wouldn't be preemptible by another task
jirka
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2026-08-27 22:32 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-22 22:54 [PATCH bpf v3 0/2] disable private stack for sleepable programs Christian Simon
2026-08-22 22:54 ` [PATCH bpf v3 1/2] bpf: " Christian Simon
2026-08-22 23:10 ` sashiko-bot
2026-08-22 23:46 ` bot+bpf-ci
2026-08-26 1:20 ` Alexei Starovoitov
2026-08-26 13:11 ` Jiri Olsa
2026-08-27 14:56 ` Andrii Nakryiko
2026-08-27 16:35 ` Alexei Starovoitov
2026-08-27 16:40 ` Andrii Nakryiko
2026-08-27 16:55 ` Alexei Starovoitov
2026-08-27 22:32 ` Jiri Olsa
2026-08-22 22:54 ` [PATCH bpf v3 2/2] selftests/bpf: verify preemptible uprobes avoid private stack Christian Simon
2026-08-22 23:05 ` sashiko-bot
2026-08-22 23:58 ` bot+bpf-ci
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox