Merge branch 'bpf-follow-up-fixes-for-stack-argument-support'

Yonghong Song says:

====================
bpf: Follow-up fixes for stack argument support

Commit cd59fa185a ("bpf: Support stack arguments for BPF functions and kfuncs")
added stack argument support for bpf functions and kfuncs. This patch set
is to fix various issues related to stack arguments, mainly include:
  - Validate outgoing stack args when btf_prepare_func_args fails
  - Fix arg_track_join log to use sa prefix for stack arg slots
  - Clean up redundant stack arg checks for non-JITed programs

Changelog:
  v2 -> v3:
    - v2: https://lore.kernel.org/bpf/20260515014958.1186132-1-yonghong.song@linux.dev/
    - Add additional fix (fix arg_track_join log, fix exception with outgoing stack
      arguments, some cleanup, etc.).
  v1 -> v2:
    - v1: https://lore.kernel.org/bpf/20260514184827.1619863-1-yonghong.song@linux.dev/
    - Remove 'Reported-by: Sashiko <sashiko-bot@kernel.org>'.
    - Add proper fix tag.
====================

Link: https://patch.msgid.link/20260515225035.821178-1-yonghong.song@linux.dev
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
Alexei Starovoitov 2026-05-16 17:46:17 -07:00
commit 50d00ea660
7 changed files with 84 additions and 8 deletions

View File

@ -2609,7 +2609,7 @@ struct bpf_prog *__bpf_prog_select_runtime(struct bpf_verifier_env *env, struct
goto finalize;
if (IS_ENABLED(CONFIG_BPF_JIT_ALWAYS_ON) ||
bpf_prog_has_kfunc_call(fp) || (env && env->subprog_info[0].stack_arg_cnt))
bpf_prog_has_kfunc_call(fp))
jit_needed = true;
if (!bpf_prog_select_interpreter(fp))

View File

@ -1407,7 +1407,7 @@ int bpf_fixup_call_args(struct bpf_verifier_env *env)
verbose(env, "calling kernel functions are not allowed in non-JITed programs\n");
return -EINVAL;
}
for (i = 1; i < env->subprog_cnt; i++) {
for (i = 0; i < env->subprog_cnt; i++) {
if (bpf_in_stack_arg_cnt(&env->subprog_info[i])) {
verbose(env, "stack args are not supported in non-JITed programs\n");
return -EINVAL;

View File

@ -806,7 +806,9 @@ static bool arg_track_join(struct bpf_verifier_env *env, int idx, int target, in
return true;
verbose(env, "arg JOIN insn %d -> %d ", idx, target);
if (r >= 0)
if (r >= MAX_BPF_REG)
verbose(env, "sa%d: ", r - MAX_BPF_REG);
else if (r >= 0)
verbose(env, "r%d: ", r);
else
verbose(env, "fp%+d: ", r * 8);

View File

@ -9118,11 +9118,17 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, int subprog,
struct bpf_func_state *caller = cur_func(env);
struct bpf_verifier_log *log = &env->log;
u32 i;
int ret;
int ret, err;
ret = btf_prepare_func_args(env, subprog);
if (ret)
if (ret) {
if (bpf_in_stack_arg_cnt(sub) > 0) {
err = check_outgoing_stack_args(env, caller, sub->arg_cnt);
if (err)
return err;
}
return ret;
}
ret = check_outgoing_stack_args(env, caller, sub->arg_cnt);
if (ret)

View File

@ -21,6 +21,10 @@ int subprog_pruning_call_before_load_6args(int a, int b, int c, int d, int e, in
return a + b + c + d + e + f;
}
void subprog_bad_ptr_7args(long *a, int b, int c, int d, int e, int f, int g)
{
}
#else
int subprog_bad_order_6args(void)
@ -38,4 +42,8 @@ int subprog_pruning_call_before_load_6args(void)
return 0;
}
void subprog_bad_ptr_7args(void)
{
}
#endif

View File

@ -114,8 +114,10 @@ __naked void stack_arg_gap_at_minus8(void)
SEC("tc")
__description("stack_arg: pruning with different stack arg types")
__failure
__failure __log_level(2)
__flag(BPF_F_TEST_STATE_FREQ)
__msg("arg JOIN insn 9 -> 10 r1: fp0-8 + _ => fp0-8|fp0+0")
__msg("arg JOIN insn 9 -> 10 sa0: fp0-8 + _ => fp0-8|fp0+0")
__msg("R{{[0-9]}} invalid mem access 'scalar'")
__naked void stack_arg_pruning_type_mismatch(void)
{
@ -152,7 +154,7 @@ __naked void stack_arg_pruning_type_mismatch(void)
SEC("tc")
__description("stack_arg: release_reference invalidates stack arg slot")
__failure
__msg("R{{[0-9]}} !read_ok")
__msg("callee expects 6 args, stack arg1 is not initialized")
__naked void stack_arg_release_ref(void)
{
asm volatile (
@ -201,7 +203,7 @@ __naked void stack_arg_release_ref(void)
SEC("tc")
__description("stack_arg: pkt pointer in stack arg slot invalidated after pull_data")
__failure
__msg("R{{[0-9]}} !read_ok")
__msg("callee expects 6 args, stack arg1 is not initialized")
__naked void stack_arg_stale_pkt_ptr(void)
{
asm volatile (

View File

@ -112,6 +112,64 @@ __naked void stack_arg_pruning_load_after_call(void)
);
}
/*
* "bad_ptr": the first arg is 'long *', which is not a recognized pointer
* type for static subprogs (not ctx, dynptr, or tagged). btf_prepare_func_args()
* sets arg_cnt = 7 / stack_arg_cnt = 2, then fails with -EINVAL. The subprog
* is marked unreliable but the call still proceeds for static subprogs.
*/
__noinline __used __naked
static void subprog_bad_ptr_7args(long *a, int b, int c, int d, int e, int f, int g)
{
asm volatile (
"r0 = *(u64 *)(r11 + 8);"
"r1 = *(u64 *)(r11 + 16);"
"exit;"
::: __clobber_all
);
}
SEC("tc")
__description("stack_arg: read without caller write")
__failure
__msg("callee expects 7 args, stack arg1 is not initialized")
__btf_func_path("btf__verifier_stack_arg_order.bpf.o")
__naked void stack_arg_read_without_write_1(void)
{
asm volatile (
"r1 = 0;"
"r2 = 0;"
"r3 = 0;"
"r4 = 0;"
"r5 = 0;"
"call subprog_bad_ptr_7args;"
"exit;"
::: __clobber_all
);
}
SEC("tc")
__description("stack_arg: read with not-initialized caller write")
__failure
__msg("R0 !read_ok")
__btf_func_path("btf__verifier_stack_arg_order.bpf.o")
__naked void stack_arg_read_without_write_2(void)
{
asm volatile (
"r1 = 0;"
"r2 = 0;"
"r3 = 0;"
"r4 = 0;"
"r5 = 0;"
"*(u64 *)(r11 - 8) = 0;"
"*(u64 *)(r11 - 16) = 0;"
"call subprog_bad_ptr_7args;"
"call subprog_bad_ptr_7args;"
"exit;"
::: __clobber_all
);
}
#else
SEC("socket")