summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorWeiming Shi <bestswngs@gmail.com>2026-10-25 18:52:49 -0700
committerAlexei Starovoitov <ast@kernel.org>2026-10-26 04:16:01 +0000
commit90aedf8854c05713c02b381c41c59081b5cedbcc (patch)
tree2b5cb0c825b5990bf73b25c392f3adf66e1e30d5 /kernel
parent00d2cdf1637e340e66fa30900363a35af12fabd8 (diff)
downloadlinux-90aedf8854c05713c02b381c41c59081b5cedbcc.tar.gz
linux-90aedf8854c05713c02b381c41c59081b5cedbcc.zip
bpf: Validate stack arg reads against caller state
check_stack_arg_read() bounds a stack argument index with the callee's BTF-derived argument count, then uses the index in the caller's stack_arg_regs[] array. The array's actual logical length is recorded in caller->out_stack_arg_cnt, so the bound and indexed object can diverge. A crafted BPF_PROG_LOAD can use an argument mismatch to mark a static subprogram's BTF information unreliable. Later calls return from btf_check_subprog_call() before check_outgoing_stack_args(), while check_func_call() continues the static call on -EINVAL. The callee can then read a slot that the caller never allocated or initialized. The earlier commit 4286f5deee14 ("bpf: Validate outgoing stack args when btf_prepare_func_args fails") closed this hole for the first call, but not for later calls after the subprogram has been marked unreliable. Callbacks have a related problem. The verifier can make incoming stack arguments readable from outgoing slots at the helper call site. However, helpers and kfuncs invoke callbacks through an ABI that passes at most five arguments, so the runtime callback receives no stack arguments. Async callback verification can also reach check_stack_arg_read() without a caller frame. On x86-64, KASAN reports the direct-call out-of-bounds copy as: BUG: KASAN: slab-out-of-bounds in check_load_mem+0xb51/0xc60 Read of size 80 at addr ffff8881009af550 by task poc/131 Call Trace: check_stack_arg_read at kernel/bpf/verifier.c:4234 (inlined by) check_load_mem at kernel/bpf/verifier.c:6645 do_check_common at kernel/bpf/verifier.c:19568 bpf_check at kernel/bpf/verifier.c:21318 bpf_prog_load at kernel/bpf/syscall.c:3134 Reject callback subprograms with incoming stack arguments before their state is pushed. For direct calls, retrieve the slot with bpf_get_spilled_stack_arg(), which validates the index against the caller's out_stack_arg_cnt and rejects uninitialized slots before copying the register state. Fixes: 0f6bd5e7a804 ("bpf: Support stack arguments for bpf functions") Reported-by: <co+eada64ce90ecebce@bugs.sh> Signed-off-by: Weiming Shi <bestswngs@gmail.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org> Link: https://patch.msgid.link/20261026015250.1674676-1-bestswngs@gmail.com
Diffstat (limited to 'kernel')
-rw-r--r--kernel/bpf/verifier.c11
1 files changed, 10 insertions, 1 deletions
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index c223bf3bc9cd..a0a5f075d201 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -4666,7 +4666,12 @@ static int check_stack_arg_read(struct bpf_verifier_env *env, struct bpf_func_st
}
caller = vstate->frame[vstate->curframe - 1];
- arg = &caller->stack_arg_regs[spi];
+ arg = bpf_get_spilled_stack_arg(spi, caller);
+ if (!arg) {
+ verbose(env, "invalid read from uninitialized stack arg off %d\n", off);
+ return -EACCES;
+ }
+
cur = vstate->frame[vstate->curframe];
bpf_diag_mod_begin(env, &cur->regs[dst_regno], arg, BPF_DIAG_MOD_WRITE);
cur->regs[dst_regno] = *arg;
@@ -11451,6 +11456,10 @@ static int push_callback_call(struct bpf_verifier_env *env, struct bpf_insn *ins
err = btf_check_subprog_call(env, subprog);
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