Skip to content

Commit 6c21285

Browse files
theihorAlexei Starovoitov
authored andcommitted
bpf: Fix exception exit lock checking for subprogs
process_bpf_exit_full() passes check_lock = !curframe to check_resource_leak(), which is false in cases when bpf_throw() is called from a static subprog. This makes check_resource_leak() to skip validation of active_rcu_locks, active_preempt_locks, and active_irq_id on exception exits from subprogs. At runtime bpf_throw() unwinds the stack via ORC without releasing any user-acquired locks, which may cause various issues as the result. Fix by setting check_lock = true for exception exits regardless of curframe, since exceptions bypass all intermediate frame cleanup. Update the error message prefix to "bpf_throw" for exception exits to distinguish them from normal BPF_EXIT. Fix reject_subprog_with_rcu_read_lock test which was previously passing for the wrong reason. Test program returned directly from the subprog call without closing the RCU section, so the error was triggered by the unclosed RCU lock on normal exit, not by bpf_throw. Update __msg annotations for affected tests to match the new "bpf_throw" error prefix. The spin_lock case is not affected because they are already checked [1] at the call site in do_check_insn() before bpf_throw can run. [1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/kernel/bpf/verifier.c?h=v7.0-rc4#n21098 Assisted-by: Claude:claude-opus-4-6 Fixes: f18b03f ("bpf: Implement BPF exceptions") Signed-off-by: Ihor Solodrai <[email protected]> Acked-by: Yonghong Song <[email protected]> Acked-by: Kumar Kartikeya Dwivedi <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexei Starovoitov <[email protected]>
1 parent 146bd2a commit 6c21285

2 files changed

Lines changed: 8 additions & 4 deletions

File tree

kernel/bpf/verifier.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20911,7 +20911,8 @@ static int process_bpf_exit_full(struct bpf_verifier_env *env,
2091120911
* state when it exits.
2091220912
*/
2091320913
int err = check_resource_leak(env, exception_exit,
20914-
!env->cur_state->curframe,
20914+
exception_exit || !env->cur_state->curframe,
20915+
exception_exit ? "bpf_throw" :
2091520916
"BPF_EXIT instruction in main prog");
2091620917
if (err)
2091720918
return err;

tools/testing/selftests/bpf/progs/exceptions_fail.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "bpf_experimental.h"
99

1010
extern void bpf_rcu_read_lock(void) __ksym;
11+
extern void bpf_rcu_read_unlock(void) __ksym;
1112

1213
#define private(name) SEC(".bss." #name) __hidden __attribute__((aligned(8)))
1314

@@ -131,7 +132,7 @@ int reject_subprog_with_lock(void *ctx)
131132
}
132133

133134
SEC("?tc")
134-
__failure __msg("BPF_EXIT instruction in main prog cannot be used inside bpf_rcu_read_lock-ed region")
135+
__failure __msg("bpf_throw cannot be used inside bpf_rcu_read_lock-ed region")
135136
int reject_with_rcu_read_lock(void *ctx)
136137
{
137138
bpf_rcu_read_lock();
@@ -147,11 +148,13 @@ __noinline static int throwing_subprog(struct __sk_buff *ctx)
147148
}
148149

149150
SEC("?tc")
150-
__failure __msg("BPF_EXIT instruction in main prog cannot be used inside bpf_rcu_read_lock-ed region")
151+
__failure __msg("bpf_throw cannot be used inside bpf_rcu_read_lock-ed region")
151152
int reject_subprog_with_rcu_read_lock(void *ctx)
152153
{
153154
bpf_rcu_read_lock();
154-
return throwing_subprog(ctx);
155+
throwing_subprog(ctx);
156+
bpf_rcu_read_unlock();
157+
return 0;
155158
}
156159

157160
static bool rbless(struct bpf_rb_node *n1, const struct bpf_rb_node *n2)

0 commit comments

Comments
 (0)