* [PATCH bpf-next v2 0/2] bpf: Nested rcu critical sections
@ 2025-11-17 20:04 Puranjay Mohan
2025-11-17 20:04 ` [PATCH bpf-next v2 1/2] bpf: support nested " Puranjay Mohan
` (2 more replies)
0 siblings, 3 replies; 6+ messages in thread
From: Puranjay Mohan @ 2025-11-17 20:04 UTC (permalink / raw)
To: bpf
Cc: Puranjay Mohan, kkd, Alexei Starovoitov, Andrii Nakryiko,
Daniel Borkmann, Martin KaFai Lau, Eduard Zingerman,
Puranjay Mohan, kernel-team
v1: https://lore.kernel.org/bpf/20250916113622.19540-1-puranjay@kernel.org/
Changes in v1->v2:
- Move the addition of new tests to a separate patch (Alexei)
- Avoid incrementing active_rcu_locks at two places (Eduard)
Support nested rcu critical sections by making the boolean flag
active_rcu_lock a counter and use it to manage rcu critical section
state. bpf_rcu_read_lock() increments this counter and
bpf_rcu_read_unlock() decrements it, MEM_RCU -> PTR_UNTRUSTED transition
happens when active_rcu_locks drops to 0.
Puranjay Mohan (2):
bpf: support nested rcu critical sections
selftests: bpf: Add tests for unbalanced rcu_read_lock
include/linux/bpf_verifier.h | 2 +-
kernel/bpf/verifier.c | 47 +++++++++----------
.../selftests/bpf/prog_tests/rcu_read_lock.c | 4 +-
.../selftests/bpf/progs/rcu_read_lock.c | 40 ++++++++++++++++
4 files changed, 66 insertions(+), 27 deletions(-)
--
2.47.1
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH bpf-next v2 1/2] bpf: support nested rcu critical sections
2025-11-17 20:04 [PATCH bpf-next v2 0/2] bpf: Nested rcu critical sections Puranjay Mohan
@ 2025-11-17 20:04 ` Puranjay Mohan
2025-11-22 1:13 ` Eduard Zingerman
2025-11-17 20:04 ` [PATCH bpf-next v2 2/2] selftests: bpf: Add tests for unbalanced rcu_read_lock Puranjay Mohan
2025-11-22 3:20 ` [PATCH bpf-next v2 0/2] bpf: Nested rcu critical sections patchwork-bot+netdevbpf
2 siblings, 1 reply; 6+ messages in thread
From: Puranjay Mohan @ 2025-11-17 20:04 UTC (permalink / raw)
To: bpf
Cc: Puranjay Mohan, kkd, Alexei Starovoitov, Andrii Nakryiko,
Daniel Borkmann, Martin KaFai Lau, Eduard Zingerman,
Puranjay Mohan, kernel-team
Currently, nested rcu critical sections are rejected by the verifier and
rcu_lock state is managed by a boolean variable. Add support for nested
rcu critical sections by make active_rcu_locks a counter similar to
active_preempt_locks. bpf_rcu_read_lock() increments this counter and
bpf_rcu_read_unlock() decrements it, MEM_RCU -> PTR_UNTRUSTED transition
happens when active_rcu_locks drops to 0.
Signed-off-by: Puranjay Mohan <puranjay@kernel.org>
---
include/linux/bpf_verifier.h | 2 +-
kernel/bpf/verifier.c | 47 +++++++++----------
.../selftests/bpf/prog_tests/rcu_read_lock.c | 2 +-
3 files changed, 24 insertions(+), 27 deletions(-)
diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
index 5441341f1ab9..9f9f539b99bd 100644
--- a/include/linux/bpf_verifier.h
+++ b/include/linux/bpf_verifier.h
@@ -416,7 +416,7 @@ struct bpf_verifier_state {
u32 active_irq_id;
u32 active_lock_id;
void *active_lock_ptr;
- bool active_rcu_lock;
+ u32 active_rcu_locks;
bool speculative;
bool in_sleepable;
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 098dd7f21c89..624aefb3103d 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -1437,7 +1437,7 @@ static int copy_reference_state(struct bpf_verifier_state *dst, const struct bpf
dst->acquired_refs = src->acquired_refs;
dst->active_locks = src->active_locks;
dst->active_preempt_locks = src->active_preempt_locks;
- dst->active_rcu_lock = src->active_rcu_lock;
+ dst->active_rcu_locks = src->active_rcu_locks;
dst->active_irq_id = src->active_irq_id;
dst->active_lock_id = src->active_lock_id;
dst->active_lock_ptr = src->active_lock_ptr;
@@ -5880,7 +5880,7 @@ static bool in_sleepable(struct bpf_verifier_env *env)
*/
static bool in_rcu_cs(struct bpf_verifier_env *env)
{
- return env->cur_state->active_rcu_lock ||
+ return env->cur_state->active_rcu_locks ||
env->cur_state->active_locks ||
!in_sleepable(env);
}
@@ -10735,7 +10735,7 @@ static int check_func_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
}
if (env->subprog_info[subprog].might_sleep &&
- (env->cur_state->active_rcu_lock || env->cur_state->active_preempt_locks ||
+ (env->cur_state->active_rcu_locks || env->cur_state->active_preempt_locks ||
env->cur_state->active_irq_id || !in_sleepable(env))) {
verbose(env, "global functions that may sleep are not allowed in non-sleepable context,\n"
"i.e., in a RCU/IRQ/preempt-disabled section, or in\n"
@@ -11314,7 +11314,7 @@ static int check_resource_leak(struct bpf_verifier_env *env, bool exception_exit
return -EINVAL;
}
- if (check_lock && env->cur_state->active_rcu_lock) {
+ if (check_lock && env->cur_state->active_rcu_locks) {
verbose(env, "%s cannot be used inside bpf_rcu_read_lock-ed region\n", prefix);
return -EINVAL;
}
@@ -11452,7 +11452,7 @@ static int get_helper_proto(struct bpf_verifier_env *env, int func_id,
/* Check if we're in a sleepable context. */
static inline bool in_sleepable_context(struct bpf_verifier_env *env)
{
- return !env->cur_state->active_rcu_lock &&
+ return !env->cur_state->active_rcu_locks &&
!env->cur_state->active_preempt_locks &&
!env->cur_state->active_irq_id &&
in_sleepable(env);
@@ -11518,7 +11518,7 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
return err;
}
- if (env->cur_state->active_rcu_lock) {
+ if (env->cur_state->active_rcu_locks) {
if (fn->might_sleep) {
verbose(env, "sleepable helper %s#%d in rcu_read_lock region\n",
func_id_name(func_id), func_id);
@@ -14006,36 +14006,33 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
preempt_disable = is_kfunc_bpf_preempt_disable(&meta);
preempt_enable = is_kfunc_bpf_preempt_enable(&meta);
- if (env->cur_state->active_rcu_lock) {
+ if (rcu_lock) {
+ env->cur_state->active_rcu_locks++;
+ } else if (rcu_unlock) {
struct bpf_func_state *state;
struct bpf_reg_state *reg;
u32 clear_mask = (1 << STACK_SPILL) | (1 << STACK_ITER);
- if (in_rbtree_lock_required_cb(env) && (rcu_lock || rcu_unlock)) {
- verbose(env, "Calling bpf_rcu_read_{lock,unlock} in unnecessary rbtree callback\n");
- return -EACCES;
- }
-
- if (rcu_lock) {
- verbose(env, "nested rcu read lock (kernel function %s)\n", func_name);
+ if (env->cur_state->active_rcu_locks == 0) {
+ verbose(env, "unmatched rcu read unlock (kernel function %s)\n", func_name);
return -EINVAL;
- } else if (rcu_unlock) {
+ }
+ if (--env->cur_state->active_rcu_locks == 0) {
bpf_for_each_reg_in_vstate_mask(env->cur_state, state, reg, clear_mask, ({
if (reg->type & MEM_RCU) {
reg->type &= ~(MEM_RCU | PTR_MAYBE_NULL);
reg->type |= PTR_UNTRUSTED;
}
}));
- env->cur_state->active_rcu_lock = false;
- } else if (sleepable) {
- verbose(env, "kernel func %s is sleepable within rcu_read_lock region\n", func_name);
- return -EACCES;
}
- } else if (rcu_lock) {
- env->cur_state->active_rcu_lock = true;
- } else if (rcu_unlock) {
- verbose(env, "unmatched rcu read unlock (kernel function %s)\n", func_name);
- return -EINVAL;
+ } else if (sleepable && env->cur_state->active_rcu_locks) {
+ verbose(env, "kernel func %s is sleepable within rcu_read_lock region\n", func_name);
+ return -EACCES;
+ }
+
+ if (in_rbtree_lock_required_cb(env) && (rcu_lock || rcu_unlock)) {
+ verbose(env, "Calling bpf_rcu_read_{lock,unlock} in unnecessary rbtree callback\n");
+ return -EACCES;
}
if (env->cur_state->active_preempt_locks) {
@@ -19328,7 +19325,7 @@ static bool refsafe(struct bpf_verifier_state *old, struct bpf_verifier_state *c
if (old->active_preempt_locks != cur->active_preempt_locks)
return false;
- if (old->active_rcu_lock != cur->active_rcu_lock)
+ if (old->active_rcu_locks != cur->active_rcu_locks)
return false;
if (!check_ids(old->active_irq_id, cur->active_irq_id, idmap))
diff --git a/tools/testing/selftests/bpf/prog_tests/rcu_read_lock.c b/tools/testing/selftests/bpf/prog_tests/rcu_read_lock.c
index c9f855e5da24..451a5d9ff4cb 100644
--- a/tools/testing/selftests/bpf/prog_tests/rcu_read_lock.c
+++ b/tools/testing/selftests/bpf/prog_tests/rcu_read_lock.c
@@ -28,6 +28,7 @@ static void test_success(void)
bpf_program__set_autoload(skel->progs.two_regions, true);
bpf_program__set_autoload(skel->progs.non_sleepable_1, true);
bpf_program__set_autoload(skel->progs.non_sleepable_2, true);
+ bpf_program__set_autoload(skel->progs.nested_rcu_region, true);
bpf_program__set_autoload(skel->progs.task_trusted_non_rcuptr, true);
bpf_program__set_autoload(skel->progs.rcu_read_lock_subprog, true);
bpf_program__set_autoload(skel->progs.rcu_read_lock_global_subprog, true);
@@ -78,7 +79,6 @@ static const char * const inproper_region_tests[] = {
"non_sleepable_rcu_mismatch",
"inproper_sleepable_helper",
"inproper_sleepable_kfunc",
- "nested_rcu_region",
"rcu_read_lock_global_subprog_lock",
"rcu_read_lock_global_subprog_unlock",
"rcu_read_lock_sleepable_helper_global_subprog",
--
2.47.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH bpf-next v2 2/2] selftests: bpf: Add tests for unbalanced rcu_read_lock
2025-11-17 20:04 [PATCH bpf-next v2 0/2] bpf: Nested rcu critical sections Puranjay Mohan
2025-11-17 20:04 ` [PATCH bpf-next v2 1/2] bpf: support nested " Puranjay Mohan
@ 2025-11-17 20:04 ` Puranjay Mohan
2025-11-22 1:17 ` Eduard Zingerman
2025-11-22 3:20 ` [PATCH bpf-next v2 0/2] bpf: Nested rcu critical sections patchwork-bot+netdevbpf
2 siblings, 1 reply; 6+ messages in thread
From: Puranjay Mohan @ 2025-11-17 20:04 UTC (permalink / raw)
To: bpf
Cc: Puranjay Mohan, kkd, Alexei Starovoitov, Andrii Nakryiko,
Daniel Borkmann, Martin KaFai Lau, Eduard Zingerman,
Puranjay Mohan, kernel-team
As verifier now supports nested rcu critical sections, add new test
cases to make sure unbalanced usage of rcu_read_lock()/unlock() is
rejected.
Signed-off-by: Puranjay Mohan <puranjay@kernel.org>
---
.../selftests/bpf/prog_tests/rcu_read_lock.c | 2 +
.../selftests/bpf/progs/rcu_read_lock.c | 40 +++++++++++++++++++
2 files changed, 42 insertions(+)
diff --git a/tools/testing/selftests/bpf/prog_tests/rcu_read_lock.c b/tools/testing/selftests/bpf/prog_tests/rcu_read_lock.c
index 451a5d9ff4cb..246eb259c08a 100644
--- a/tools/testing/selftests/bpf/prog_tests/rcu_read_lock.c
+++ b/tools/testing/selftests/bpf/prog_tests/rcu_read_lock.c
@@ -79,6 +79,8 @@ static const char * const inproper_region_tests[] = {
"non_sleepable_rcu_mismatch",
"inproper_sleepable_helper",
"inproper_sleepable_kfunc",
+ "nested_rcu_region_unbalanced_1",
+ "nested_rcu_region_unbalanced_2",
"rcu_read_lock_global_subprog_lock",
"rcu_read_lock_global_subprog_unlock",
"rcu_read_lock_sleepable_helper_global_subprog",
diff --git a/tools/testing/selftests/bpf/progs/rcu_read_lock.c b/tools/testing/selftests/bpf/progs/rcu_read_lock.c
index 3a868a199349..d70c28824bbe 100644
--- a/tools/testing/selftests/bpf/progs/rcu_read_lock.c
+++ b/tools/testing/selftests/bpf/progs/rcu_read_lock.c
@@ -278,6 +278,46 @@ int nested_rcu_region(void *ctx)
return 0;
}
+SEC("?fentry.s/" SYS_PREFIX "sys_nanosleep")
+int nested_rcu_region_unbalanced_1(void *ctx)
+{
+ struct task_struct *task, *real_parent;
+
+ /* nested rcu read lock regions */
+ task = bpf_get_current_task_btf();
+ bpf_rcu_read_lock();
+ bpf_rcu_read_lock();
+ real_parent = task->real_parent;
+ if (!real_parent)
+ goto out;
+ (void)bpf_task_storage_get(&map_a, real_parent, 0, 0);
+out:
+ bpf_rcu_read_unlock();
+ bpf_rcu_read_unlock();
+ bpf_rcu_read_unlock();
+ return 0;
+}
+
+SEC("?fentry.s/" SYS_PREFIX "sys_nanosleep")
+int nested_rcu_region_unbalanced_2(void *ctx)
+{
+ struct task_struct *task, *real_parent;
+
+ /* nested rcu read lock regions */
+ task = bpf_get_current_task_btf();
+ bpf_rcu_read_lock();
+ bpf_rcu_read_lock();
+ bpf_rcu_read_lock();
+ real_parent = task->real_parent;
+ if (!real_parent)
+ goto out;
+ (void)bpf_task_storage_get(&map_a, real_parent, 0, 0);
+out:
+ bpf_rcu_read_unlock();
+ bpf_rcu_read_unlock();
+ return 0;
+}
+
SEC("?fentry.s/" SYS_PREFIX "sys_getpgid")
int task_trusted_non_rcuptr(void *ctx)
{
--
2.47.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH bpf-next v2 1/2] bpf: support nested rcu critical sections
2025-11-17 20:04 ` [PATCH bpf-next v2 1/2] bpf: support nested " Puranjay Mohan
@ 2025-11-22 1:13 ` Eduard Zingerman
0 siblings, 0 replies; 6+ messages in thread
From: Eduard Zingerman @ 2025-11-22 1:13 UTC (permalink / raw)
To: Puranjay Mohan, bpf
Cc: kkd, Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
Martin KaFai Lau, Puranjay Mohan, kernel-team
On Mon, 2025-11-17 at 20:04 +0000, Puranjay Mohan wrote:
> Currently, nested rcu critical sections are rejected by the verifier and
> rcu_lock state is managed by a boolean variable. Add support for nested
> rcu critical sections by make active_rcu_locks a counter similar to
> active_preempt_locks. bpf_rcu_read_lock() increments this counter and
> bpf_rcu_read_unlock() decrements it, MEM_RCU -> PTR_UNTRUSTED transition
> happens when active_rcu_locks drops to 0.
>
> Signed-off-by: Puranjay Mohan <puranjay@kernel.org>
> ---
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
[...]
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH bpf-next v2 2/2] selftests: bpf: Add tests for unbalanced rcu_read_lock
2025-11-17 20:04 ` [PATCH bpf-next v2 2/2] selftests: bpf: Add tests for unbalanced rcu_read_lock Puranjay Mohan
@ 2025-11-22 1:17 ` Eduard Zingerman
0 siblings, 0 replies; 6+ messages in thread
From: Eduard Zingerman @ 2025-11-22 1:17 UTC (permalink / raw)
To: Puranjay Mohan, bpf
Cc: kkd, Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
Martin KaFai Lau, Puranjay Mohan, kernel-team
On Mon, 2025-11-17 at 20:04 +0000, Puranjay Mohan wrote:
> As verifier now supports nested rcu critical sections, add new test
> cases to make sure unbalanced usage of rcu_read_lock()/unlock() is
> rejected.
>
> Signed-off-by: Puranjay Mohan <puranjay@kernel.org>
> ---
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
(Although, it would be great to move these tests to RUN_TESTS
infrastructure, at-least partially).
[...]
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH bpf-next v2 0/2] bpf: Nested rcu critical sections
2025-11-17 20:04 [PATCH bpf-next v2 0/2] bpf: Nested rcu critical sections Puranjay Mohan
2025-11-17 20:04 ` [PATCH bpf-next v2 1/2] bpf: support nested " Puranjay Mohan
2025-11-17 20:04 ` [PATCH bpf-next v2 2/2] selftests: bpf: Add tests for unbalanced rcu_read_lock Puranjay Mohan
@ 2025-11-22 3:20 ` patchwork-bot+netdevbpf
2 siblings, 0 replies; 6+ messages in thread
From: patchwork-bot+netdevbpf @ 2025-11-22 3:20 UTC (permalink / raw)
To: Puranjay Mohan
Cc: bpf, kkd, ast, andrii, daniel, martin.lau, eddyz87, puranjay12,
kernel-team
Hello:
This series was applied to bpf/bpf-next.git (master)
by Alexei Starovoitov <ast@kernel.org>:
On Mon, 17 Nov 2025 20:04:08 +0000 you wrote:
> v1: https://lore.kernel.org/bpf/20250916113622.19540-1-puranjay@kernel.org/
> Changes in v1->v2:
> - Move the addition of new tests to a separate patch (Alexei)
> - Avoid incrementing active_rcu_locks at two places (Eduard)
>
> Support nested rcu critical sections by making the boolean flag
> active_rcu_lock a counter and use it to manage rcu critical section
> state. bpf_rcu_read_lock() increments this counter and
> bpf_rcu_read_unlock() decrements it, MEM_RCU -> PTR_UNTRUSTED transition
> happens when active_rcu_locks drops to 0.
>
> [...]
Here is the summary with links:
- [bpf-next,v2,1/2] bpf: support nested rcu critical sections
https://git.kernel.org/bpf/bpf-next/c/4167096cb964
- [bpf-next,v2,2/2] selftests: bpf: Add tests for unbalanced rcu_read_lock
https://git.kernel.org/bpf/bpf-next/c/cf49ec5705a6
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2025-11-22 3:20 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-11-17 20:04 [PATCH bpf-next v2 0/2] bpf: Nested rcu critical sections Puranjay Mohan
2025-11-17 20:04 ` [PATCH bpf-next v2 1/2] bpf: support nested " Puranjay Mohan
2025-11-22 1:13 ` Eduard Zingerman
2025-11-17 20:04 ` [PATCH bpf-next v2 2/2] selftests: bpf: Add tests for unbalanced rcu_read_lock Puranjay Mohan
2025-11-22 1:17 ` Eduard Zingerman
2025-11-22 3:20 ` [PATCH bpf-next v2 0/2] bpf: Nested rcu critical sections patchwork-bot+netdevbpf
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox