[PATCH bpf v1 2/2] selftests/bpf: Add tests for bpf_throw lock leak from subprogs
From: Ihor Solodrai
Date: Mon Mar 16 2026 - 20:13:56 EST
Add test cases to ensure the verifier correctly rejects bpf_throw from
subprogs when RCU or preempt locks are held:
* reject_subprog_throw_rcu_lock: always-throwing subprog called while
caller holds bpf_rcu_read_lock
* reject_subprog_rcu_lock_throw: subprog acquires bpf_rcu_read_lock and
then calls bpf_throw
* reject_subprog_throw_preempt_lock: always-throwing subprog called while
caller holds bpf_preempt_disable
Assisted-by: Claude:claude-opus-4-6
Signed-off-by: Ihor Solodrai <ihor.solodrai@xxxxxxxxx>
---
.../selftests/bpf/progs/exceptions_fail.c | 44 +++++++++++++++++++
1 file changed, 44 insertions(+)
diff --git a/tools/testing/selftests/bpf/progs/exceptions_fail.c b/tools/testing/selftests/bpf/progs/exceptions_fail.c
index 1dd2703c7676..9d1c560aac84 100644
--- a/tools/testing/selftests/bpf/progs/exceptions_fail.c
+++ b/tools/testing/selftests/bpf/progs/exceptions_fail.c
@@ -8,6 +8,9 @@
#include "bpf_experimental.h"
extern void bpf_rcu_read_lock(void) __ksym;
+extern void bpf_rcu_read_unlock(void) __ksym;
+extern void bpf_preempt_disable(void) __ksym;
+extern void bpf_preempt_enable(void) __ksym;
#define private(name) SEC(".bss." #name) __hidden __attribute__((aligned(8)))
@@ -346,4 +349,45 @@ int reject_exception_throw_cb_diff(struct __sk_buff *ctx)
return 0;
}
+__noinline static int always_throws(void)
+{
+ bpf_throw(0);
+ return 0;
+}
+
+SEC("?tc")
+__failure __msg("bpf_throw cannot be used inside bpf_rcu_read_lock-ed region")
+int reject_subprog_throw_rcu_lock(void *ctx)
+{
+ bpf_rcu_read_lock();
+ always_throws();
+ bpf_rcu_read_unlock();
+ return 0;
+}
+
+__noinline static int rcu_lock_then_throw(void)
+{
+ bpf_rcu_read_lock();
+ bpf_throw(0);
+ return 0;
+}
+
+SEC("?tc")
+__failure __msg("bpf_throw cannot be used inside bpf_rcu_read_lock-ed region")
+int reject_subprog_rcu_lock_throw(void *ctx)
+{
+ rcu_lock_then_throw();
+ return 0;
+}
+
+SEC("?tc")
+__failure __msg("bpf_throw cannot be used inside bpf_preempt_disable-ed region")
+int reject_subprog_throw_preempt_lock(void *ctx)
+{
+ bpf_preempt_disable();
+ always_throws();
+ bpf_preempt_enable();
+ return 0;
+}
+
char _license[] SEC("license") = "GPL";
--
2.53.0