[PATCH] bpf: reject stack-argument callback subprograms

Jérémy Jean <[email protected]>
Newsgroups org.kernel.vger.linux-kselftest,org.kernel.vger.bpf,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
Helper callbacks enter BPF subprograms through bpf_callback_t, whose
runtime ABI supplies five arguments. BTF validation nevertheless permits
static callback subprograms to declare more than five arguments when JIT
stack arguments are supported.

This lets verifier state for a callback use outgoing stack argument slots
prepared at the helper call site. The helper does not pass those slots. On
x86-64, callback loads of arguments seven and later therefore read the
helper native frame instead of the synthetic values checked by the
verifier. KASAN reports a slab OOB write.

Reject callback subprograms with incoming stack arguments when processing
callback calls. Add a verifier regression test using bpf_loop() and a
nine-argument callback.

Fixes: 0f6bd5e7a804 ("bpf: Support stack arguments for bpf functions")
Assisted-by: Codex:gpt-5
Signed-off-by: Jérémy Jean <[email protected]>
---
 kernel/bpf/verifier.c                         |  4 +++
 .../selftests/bpf/progs/verifier_stack_arg.c  | 33 +++++++++++++++++++
 2 files changed, 37 insertions(+)

diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index fdc5fbb1f78c..29aa4911c7f7 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -9285,6 +9285,10 @@ static int push_callback_call(struct bpf_verifier_env *env, struct bpf_insn *ins
 	err = btf_check_subprog_call(env, subprog, caller->regs);
 	if (err == -EFAULT)
 		return err;
+	if (bpf_in_stack_arg_cnt(&env->subprog_info[subprog])) {
+		verbose(env, "callback subprog cannot have stack args\n");
+		return -EINVAL;
+	}
 
 	/* set_callee_state is used for direct subprog calls, but we are
 	 * interested in validating only BPF helpers that can call subprogs as
diff --git a/tools/testing/selftests/bpf/progs/verifier_stack_arg.c b/tools/testing/selftests/bpf/progs/verifier_stack_arg.c
index 7e0ce5db28a0..5acc3b63ca84 100644
--- a/tools/testing/selftests/bpf/progs/verifier_stack_arg.c
+++ b/tools/testing/selftests/bpf/progs/verifier_stack_arg.c
@@ -27,6 +27,13 @@ static int subprog_7args(int a, int b, int c, int d, int e, int f, int g)
 	return a + b + c + d + e + f + g;
 }
 
+__noinline __used
+static int callback_9args(__u32 index, void *ctx, long a3, long a4,
+			  long a5, long a6, long a7, long a8, long a9)
+{
+	return a9;
+}
+
 __noinline __used
 static long subprog_deref_arg6(long a, long b, long c, long d, long e, long *f)
 {
@@ -79,6 +86,32 @@ __naked void stack_arg_two_subprogs(void)
 	);
 }
 
+SEC("tc")
+__description("stack_arg: callback with incoming stack args")
+__failure
+__msg("callback subprog cannot have stack args")
+__naked void stack_arg_callback_many_args(void)
+{
+	asm volatile (
+		"r6 = 0;"
+		"*(u64 *)(r11 - 32) = 0;"
+		"*(u64 *)(r11 - 24) = 0;"
+		"*(u64 *)(r11 - 16) = 0;"
+		"*(u64 *)(r11 - 8) = 0;"
+		"r1 = 1;"
+		"r2 = %[callback_9args];"
+		"r3 = 0;"
+		"r4 = 0;"
+		"call %[bpf_loop];"
+		"r0 = 0;"
+		"exit;"
+		:
+		: __imm_ptr(callback_9args),
+		  __imm(bpf_loop)
+		: __clobber_all
+	);
+}
+
 SEC("tc")
 __description("stack_arg: read from uninitialized stack arg slot")
 __failure
-- 
2.47.3
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.