* [PATCH bpf-next v2 0/2] bpf: Compare iterator types during state pruning @ 2026-08-11 3:59 Ning Ding 2026-08-11 3:59 ` [PATCH bpf-next v2 1/2] " Ning Ding 2026-08-11 3:59 ` [PATCH bpf-next v2 2/2] selftests/bpf: Test RCU iterator " Ning Ding 0 siblings, 2 replies; 4+ messages in thread From: Ning Ding @ 2026-08-11 3:59 UTC (permalink / raw) To: bpf Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi, Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa, Emil Tsalapatis, Ihor Solodrai, Shuah Khan, Ning Ding, Chuyi Zhou, linux-kernel, linux-kselftest Iterator stack slots can be marked MEM_RCU or PTR_UNTRUSTED. The STACK_ITER check in stacksafe() does not compare this type, so state pruning can treat these states as equal and prune an unsafe path. Compare the type and add a test where RCU protection has a gap. --- Changes in v2: - Convert the regression test to inline assembly so its verifier-sensitive control-flow layout is stable. - Add Eduard Zingerman's Acked-by tag to patch 1. v1: https://lore.kernel.org/bpf/20260807004320.134069-1-dingning04@gmail.com/ Ning Ding (2): bpf: Compare iterator types during state pruning selftests/bpf: Test RCU iterator state pruning kernel/bpf/states.c | 3 +- .../selftests/bpf/progs/iters_task_failure.c | 46 +++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) -- 2.43.0 ^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH bpf-next v2 1/2] bpf: Compare iterator types during state pruning 2026-08-11 3:59 [PATCH bpf-next v2 0/2] bpf: Compare iterator types during state pruning Ning Ding @ 2026-08-11 3:59 ` Ning Ding 2026-08-11 3:59 ` [PATCH bpf-next v2 2/2] selftests/bpf: Test RCU iterator " Ning Ding 1 sibling, 0 replies; 4+ messages in thread From: Ning Ding @ 2026-08-11 3:59 UTC (permalink / raw) To: bpf Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi, Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa, Emil Tsalapatis, Ihor Solodrai, Shuah Khan, Ning Ding, Chuyi Zhou, linux-kernel, linux-kselftest An iterator stack slot can be MEM_RCU or PTR_UNTRUSTED. These states must not be equal, or the verifier can prune an unsafe path. Compare the pointer type for STACK_ITER slots. Fixes: dfab99df147b ("bpf: teach the verifier to enforce css_iter and task_iter in RCU CS") Signed-off-by: Ning Ding <dingning04@gmail.com> Acked-by: Eduard Zingerman <eddyz87@gmail.com> --- kernel/bpf/states.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/bpf/states.c b/kernel/bpf/states.c index ea2153cf28d0a..4e6aafad33bd2 100644 --- a/kernel/bpf/states.c +++ b/kernel/bpf/states.c @@ -812,7 +812,8 @@ static bool stacksafe(struct bpf_verifier_env *env, struct bpf_func_state *old, * infinite loop check triggering, see * iter_active_depths_differ() */ - if (old_reg->iter.btf != cur_reg->iter.btf || + if (old_reg->type != cur_reg->type || + old_reg->iter.btf != cur_reg->iter.btf || old_reg->iter.btf_id != cur_reg->iter.btf_id || old_reg->iter.state != cur_reg->iter.state || /* ignore {old_reg,cur_reg}->iter.depth, see above */ -- 2.43.0 ^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH bpf-next v2 2/2] selftests/bpf: Test RCU iterator state pruning 2026-08-11 3:59 [PATCH bpf-next v2 0/2] bpf: Compare iterator types during state pruning Ning Ding 2026-08-11 3:59 ` [PATCH bpf-next v2 1/2] " Ning Ding @ 2026-08-11 3:59 ` Ning Ding 2026-08-11 4:41 ` bot+bpf-ci 1 sibling, 1 reply; 4+ messages in thread From: Ning Ding @ 2026-08-11 3:59 UTC (permalink / raw) To: bpf Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi, Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa, Emil Tsalapatis, Ihor Solodrai, Shuah Khan, Ning Ding, Chuyi Zhou, linux-kernel, linux-kselftest Add a path where RCU protection reaches zero and then starts again. The iterator is untrusted after this gap and must be rejected. Signed-off-by: Ning Ding <dingning04@gmail.com> --- .../selftests/bpf/progs/iters_task_failure.c | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/tools/testing/selftests/bpf/progs/iters_task_failure.c b/tools/testing/selftests/bpf/progs/iters_task_failure.c index fe3663dedbe14..566a1d3dffeab 100644 --- a/tools/testing/selftests/bpf/progs/iters_task_failure.c +++ b/tools/testing/selftests/bpf/progs/iters_task_failure.c @@ -61,6 +61,52 @@ int BPF_PROG(iter_tasks_lock_and_unlock) return 0; } +SEC("?fentry.s/" SYS_PREFIX "sys_getpgid") +__failure __msg("expected an RCU CS when using bpf_iter_task_next") +__flag(BPF_F_TEST_STATE_FREQ) +int BPF_PROG(iter_tasks_rcu_state_pruning) +{ + struct bpf_iter_task it; + + asm volatile ( + "call %[bpf_rcu_read_lock];" + "r1 = %[it];" + "r2 = 0;" + "r3 = 0;" /* BPF_TASK_ITER_ALL_PROCS */ + "call %[bpf_iter_task_new];" + + "call %[bpf_get_prandom_u32];" + "if w0 == 0 goto unprotected_%=;" + + /* Keep the outer RCU lock active on the straight-line path. */ + "call %[bpf_rcu_read_lock];" + "call %[bpf_rcu_read_unlock];" + "goto merge_%=;" + + "unprotected_%=:" + /* Create an unprotected gap on the taken path. */ + "call %[bpf_rcu_read_unlock];" + "call %[bpf_rcu_read_lock];" + + "merge_%=: r1 = %[it];" + "call %[bpf_iter_task_next];" + "r1 = %[it];" + "call %[bpf_iter_task_destroy];" + "call %[bpf_rcu_read_unlock];" + : + : __imm_ptr(it), + __imm(bpf_get_prandom_u32), + __imm(bpf_iter_task_new), + __imm(bpf_iter_task_next), + __imm(bpf_iter_task_destroy), + __imm(bpf_rcu_read_lock), + __imm(bpf_rcu_read_unlock) + : __clobber_common + ); + + return 0; +} + SEC("?fentry.s/" SYS_PREFIX "sys_getpgid") __failure __msg("expected an RCU CS when using bpf_iter_css_next") int BPF_PROG(iter_css_lock_and_unlock) -- 2.43.0 ^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH bpf-next v2 2/2] selftests/bpf: Test RCU iterator state pruning 2026-08-11 3:59 ` [PATCH bpf-next v2 2/2] selftests/bpf: Test RCU iterator " Ning Ding @ 2026-08-11 4:41 ` bot+bpf-ci 0 siblings, 0 replies; 4+ messages in thread From: bot+bpf-ci @ 2026-08-11 4:41 UTC (permalink / raw) To: dingning04, bpf Cc: ast, daniel, andrii, eddyz87, memxor, martin.lau, song, yonghong.song, jolsa, emil, ihor.solodrai, shuah, dingning04, zhouchuyi, linux-kernel, linux-kselftest, ast, andrii, daniel, martin.lau, eddyz87, yonghong.song, clm, ihor.solodrai [-- Attachment #1: Type: text/plain, Size: 2553 bytes --] > selftests/bpf: Test RCU iterator state pruning > > Add a path where RCU protection reaches zero and then starts again. > The iterator is untrusted after this gap and must be rejected. > > Signed-off-by: Ning Ding <dingning04@gmail.com> This isn't a bug, but could the changelog mention why BPF_F_TEST_STATE_FREQ is needed and that both arms deliberately converge with the same RCU lock depth, so a future reader knows what keeps this test meaningful? > diff --git a/tools/testing/selftests/bpf/progs/iters_task_failure.c b/tools/testing/selftests/bpf/progs/iters_task_failure.c > index fe3663dedbe1..566a1d3dffea 100644 > --- a/tools/testing/selftests/bpf/progs/iters_task_failure.c > +++ b/tools/testing/selftests/bpf/progs/iters_task_failure.c > @@ -61,6 +61,52 @@ int BPF_PROG(iter_tasks_lock_and_unlock) > return 0; > } > > +SEC("?fentry.s/" SYS_PREFIX "sys_getpgid") > +__failure __msg("expected an RCU CS when using bpf_iter_task_next") > +__flag(BPF_F_TEST_STATE_FREQ) > +int BPF_PROG(iter_tasks_rcu_state_pruning) > +{ > + struct bpf_iter_task it; > + > + asm volatile ( > + "call %[bpf_rcu_read_lock];" > + "r1 = %[it];" > + "r2 = 0;" > + "r3 = 0;" /* BPF_TASK_ITER_ALL_PROCS */ > + "call %[bpf_iter_task_new];" > + > + "call %[bpf_get_prandom_u32];" > + "if w0 == 0 goto unprotected_%=;" > + > + /* Keep the outer RCU lock active on the straight-line path. */ > + "call %[bpf_rcu_read_lock];" > + "call %[bpf_rcu_read_unlock];" This isn't a bug, but would it help to say what the nested lock/unlock pair is for here - e.g. that it scratches the caller-saved registers so the only state difference at merge_ is the iterator's MEM_RCU vs PTR_UNTRUSTED type? > + "goto merge_%=;" > + > + "unprotected_%=:" > + /* Create an unprotected gap on the taken path. */ > + "call %[bpf_rcu_read_unlock];" > + "call %[bpf_rcu_read_lock];" > + > + "merge_%=: r1 = %[it];" > + "call %[bpf_iter_task_next];" > + "r1 = %[it];" > + "call %[bpf_iter_task_destroy];" > + "call %[bpf_rcu_read_unlock];" > + : > + : __imm_ptr(it), > + __imm(bpf_get_prandom_u32), > + __imm(bpf_iter_task_new), > + __imm(bpf_iter_task_next), > + __imm(bpf_iter_task_destroy), > + __imm(bpf_rcu_read_lock), > + __imm(bpf_rcu_read_unlock) > + : __clobber_common > + ); > + > + return 0; > +} > + --- 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/31457825387 ^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-08-11 4:41 UTC | newest] Thread overview: 4+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-08-11 3:59 [PATCH bpf-next v2 0/2] bpf: Compare iterator types during state pruning Ning Ding 2026-08-11 3:59 ` [PATCH bpf-next v2 1/2] " Ning Ding 2026-08-11 3:59 ` [PATCH bpf-next v2 2/2] selftests/bpf: Test RCU iterator " Ning Ding 2026-08-11 4:41 ` 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