From: Kumar Kartikeya Dwivedi <memxor@gmail.com>
To: bpf@vger.kernel.org
Cc: Alexei Starovoitov <ast@kernel.org>,
Andrii Nakryiko <andrii@kernel.org>,
Daniel Borkmann <daniel@iogearbox.net>,
Eduard Zingerman <eddyz87@gmail.com>,
Emil Tsalapatis <emil@etsalapatis.com>,
Nicholas Carlini <npc@anthropic.com>,
kkd@meta.com, kernel-team@meta.com
Subject: [PATCH bpf-next v1 2/2] selftests/bpf: Test global subprog callback contexts
Date: Sat, 5 Sep 2026 05:40:16 +0200 [thread overview]
Message-ID: <20260905034018.2095649-3-memxor@gmail.com> (raw)
In-Reply-To: <20260905034018.2095649-1-memxor@gmail.com>
Exercise global subprogram verification from workqueue and task-work
callbacks. Both callback types can run in a sleepable context even when the
containing program is not sleepable, so an unprotected callback must not let
the global subprogram use implicit RCU protection inherited from the program.
Add negative cases which load an RCU-protected task kptr in a global
subprogram reached from each callback type. The tests fail on an unfixed
kernel because the programs are incorrectly accepted.
Also cover a workqueue callback protected by an explicit RCU read-side
critical section. Finally, call the same harmless global subprogram directly
from the main program and from an unprotected callback. This requires both
non-sleepable and sleepable verification roots and proves that global calls
from callbacks are not rejected wholesale.
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
.../bpf/progs/verifier_async_cb_context.c | 131 ++++++++++++++++++
1 file changed, 131 insertions(+)
diff --git a/tools/testing/selftests/bpf/progs/verifier_async_cb_context.c b/tools/testing/selftests/bpf/progs/verifier_async_cb_context.c
index 6bf95550a024..9ce7359913f8 100644
--- a/tools/testing/selftests/bpf/progs/verifier_async_cb_context.c
+++ b/tools/testing/selftests/bpf/progs/verifier_async_cb_context.c
@@ -9,6 +9,11 @@
char _license[] SEC("license") = "GPL";
+struct task_struct *bpf_task_acquire(struct task_struct *p) __ksym;
+void bpf_task_release(struct task_struct *p) __ksym;
+void bpf_rcu_read_lock(void) __ksym;
+void bpf_rcu_read_unlock(void) __ksym;
+
/* Timer tests */
struct timer_elem {
@@ -66,6 +71,7 @@ int timer_sleepable_prog(void *ctx)
struct wq_elem {
struct bpf_wq w;
+ struct task_struct __kptr *task;
};
struct {
@@ -119,6 +125,105 @@ int wq_sleepable_prog(void *ctx)
return 0;
}
+__noinline int wq_global_acquire(void)
+{
+ struct task_struct *task, *acquired;
+ struct wq_elem *val;
+ int key = 0;
+
+ val = bpf_map_lookup_elem(&wq_map, &key);
+ if (!val)
+ return 0;
+
+ task = val->task;
+ if (!task)
+ return 0;
+
+ acquired = bpf_task_acquire(task);
+ if (acquired)
+ bpf_task_release(acquired);
+ return 0;
+}
+
+static int wq_global_rcu_cb(void *map, int *key, void *value)
+{
+ return wq_global_acquire();
+}
+
+SEC("fentry/bpf_fentry_test1")
+__failure __msg("R1 must be a rcu pointer")
+int wq_global_rcu_prog(void *ctx)
+{
+ struct wq_elem *val;
+ int key = 0;
+
+ val = bpf_map_lookup_elem(&wq_map, &key);
+ if (!val)
+ return 0;
+
+ bpf_wq_init(&val->w, &wq_map, 0);
+ bpf_wq_set_callback(&val->w, wq_global_rcu_cb, 0);
+ return 0;
+}
+
+static int wq_global_rcu_lock_cb(void *map, int *key, void *value)
+{
+ int ret;
+
+ bpf_rcu_read_lock();
+ ret = wq_global_acquire();
+ bpf_rcu_read_unlock();
+ return ret;
+}
+
+SEC("fentry/bpf_fentry_test1")
+__success
+int wq_global_rcu_lock_prog(void *ctx)
+{
+ struct wq_elem *val;
+ int key = 0;
+
+ /* Verify the same global subprog in non-sleepable and protected contexts. */
+ wq_global_acquire();
+
+ val = bpf_map_lookup_elem(&wq_map, &key);
+ if (!val)
+ return 0;
+
+ bpf_wq_init(&val->w, &wq_map, 0);
+ bpf_wq_set_callback(&val->w, wq_global_rcu_lock_cb, 0);
+ return 0;
+}
+
+__noinline int wq_global_no_rcu(void)
+{
+ return 0;
+}
+
+static int wq_global_no_rcu_cb(void *map, int *key, void *value)
+{
+ return wq_global_no_rcu();
+}
+
+SEC("fentry/bpf_fentry_test1")
+__success
+int wq_global_no_rcu_prog(void *ctx)
+{
+ struct wq_elem *val;
+ int key = 0;
+
+ /* Verify the same global in non-sleepable and unprotected contexts. */
+ wq_global_no_rcu();
+
+ val = bpf_map_lookup_elem(&wq_map, &key);
+ if (!val)
+ return 0;
+
+ bpf_wq_init(&val->w, &wq_map, 0);
+ bpf_wq_set_callback(&val->w, wq_global_no_rcu_cb, 0);
+ return 0;
+}
+
/* Task work tests */
struct task_work_elem {
@@ -179,3 +284,29 @@ int task_work_sleepable_prog(void *ctx)
bpf_task_work_schedule_resume(task, &val->tw, &task_work_map, task_work_cb);
return 0;
}
+
+static int task_work_global_rcu_cb(struct bpf_map *map, void *key, void *value)
+{
+ return wq_global_acquire();
+}
+
+SEC("fentry/bpf_fentry_test1")
+__failure __msg("R1 must be a rcu pointer")
+int task_work_global_rcu_prog(void *ctx)
+{
+ struct task_work_elem *val;
+ struct task_struct *task;
+ int key = 0;
+
+ val = bpf_map_lookup_elem(&task_work_map, &key);
+ if (!val)
+ return 0;
+
+ task = bpf_get_current_task_btf();
+ if (!task)
+ return 0;
+
+ bpf_task_work_schedule_resume(task, &val->tw, &task_work_map,
+ task_work_global_rcu_cb);
+ return 0;
+}
--
2.53.0
next prev parent reply other threads:[~2026-09-05 3:40 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-05 3:40 [PATCH bpf-next v1 0/2] Fix global subprog verification context Kumar Kartikeya Dwivedi
2026-09-05 3:40 ` [PATCH bpf-next v1 1/2] bpf: Verify global subprogs in each sleepability context Kumar Kartikeya Dwivedi
2026-09-05 3:54 ` sashiko-bot
2026-09-05 4:39 ` bot+bpf-ci
2026-09-05 3:40 ` Kumar Kartikeya Dwivedi [this message]
2026-09-05 4:39 ` [PATCH bpf-next v1 2/2] selftests/bpf: Test global subprog callback contexts bot+bpf-ci
2026-09-05 4:33 ` [PATCH bpf-next v1 0/2] Fix global subprog verification context Kumar Kartikeya Dwivedi
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=20260905034018.2095649-3-memxor@gmail.com \
--to=memxor@gmail.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=eddyz87@gmail.com \
--cc=emil@etsalapatis.com \
--cc=kernel-team@meta.com \
--cc=kkd@meta.com \
--cc=npc@anthropic.com \
/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