]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
bpf: Avoid putting struct bpf_scc_callchain variables on the stack
authorYonghong Song <yonghong.song@linux.dev>
Thu, 3 Jul 2025 14:11:17 +0000 (07:11 -0700)
committerAlexei Starovoitov <ast@kernel.org>
Fri, 4 Jul 2025 02:31:30 +0000 (19:31 -0700)
Add a 'struct bpf_scc_callchain callchain_buf' field in bpf_verifier_env.
This way, the previous bpf_scc_callchain local variables can be
replaced by taking address of env->callchain_buf. This can reduce stack
usage and fix the following error:
    kernel/bpf/verifier.c:19921:12: error: stack frame size (1368) exceeds limit (1280) in 'do_check'
        [-Werror,-Wframe-larger-than]

Reported-by: Arnd Bergmann <arnd@kernel.org>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Yonghong Song <yonghong.song@linux.dev>
Link: https://lore.kernel.org/r/20250703141117.1485108-1-yonghong.song@linux.dev
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
include/linux/bpf_verifier.h
kernel/bpf/verifier.c

index 7e459e839f8b4d3abb76fe025f64d701decf3368..94defa405c85e33665a539668f5ad662ff2ba6b5 100644 (file)
@@ -841,6 +841,7 @@ struct bpf_verifier_env {
        char tmp_str_buf[TMP_STR_BUF_LEN];
        struct bpf_insn insn_buf[INSN_BUF_SIZE];
        struct bpf_insn epilogue_buf[INSN_BUF_SIZE];
+       struct bpf_scc_callchain callchain_buf;
        /* array of pointers to bpf_scc_info indexed by SCC id */
        struct bpf_scc_info **scc_info;
        u32 scc_cnt;
index 92dba3c9664f38bf7647794dcabbe8cfef2ce999..0f6cc22756955bfc411609736742c34696f4f2d9 100644 (file)
@@ -1914,19 +1914,19 @@ static char *format_callchain(struct bpf_verifier_env *env, struct bpf_scc_callc
  */
 static int maybe_enter_scc(struct bpf_verifier_env *env, struct bpf_verifier_state *st)
 {
-       struct bpf_scc_callchain callchain;
+       struct bpf_scc_callchain *callchain = &env->callchain_buf;
        struct bpf_scc_visit *visit;
 
-       if (!compute_scc_callchain(env, st, &callchain))
+       if (!compute_scc_callchain(env, st, callchain))
                return 0;
-       visit = scc_visit_lookup(env, &callchain);
-       visit = visit ?: scc_visit_alloc(env, &callchain);
+       visit = scc_visit_lookup(env, callchain);
+       visit = visit ?: scc_visit_alloc(env, callchain);
        if (!visit)
                return -ENOMEM;
        if (!visit->entry_state) {
                visit->entry_state = st;
                if (env->log.level & BPF_LOG_LEVEL2)
-                       verbose(env, "SCC enter %s\n", format_callchain(env, &callchain));
+                       verbose(env, "SCC enter %s\n", format_callchain(env, callchain));
        }
        return 0;
 }
@@ -1939,21 +1939,21 @@ static int propagate_backedges(struct bpf_verifier_env *env, struct bpf_scc_visi
  */
 static int maybe_exit_scc(struct bpf_verifier_env *env, struct bpf_verifier_state *st)
 {
-       struct bpf_scc_callchain callchain;
+       struct bpf_scc_callchain *callchain = &env->callchain_buf;
        struct bpf_scc_visit *visit;
 
-       if (!compute_scc_callchain(env, st, &callchain))
+       if (!compute_scc_callchain(env, st, callchain))
                return 0;
-       visit = scc_visit_lookup(env, &callchain);
+       visit = scc_visit_lookup(env, callchain);
        if (!visit) {
                verifier_bug(env, "scc exit: no visit info for call chain %s",
-                            format_callchain(env, &callchain));
+                            format_callchain(env, callchain));
                return -EFAULT;
        }
        if (visit->entry_state != st)
                return 0;
        if (env->log.level & BPF_LOG_LEVEL2)
-               verbose(env, "SCC exit %s\n", format_callchain(env, &callchain));
+               verbose(env, "SCC exit %s\n", format_callchain(env, callchain));
        visit->entry_state = NULL;
        env->num_backedges -= visit->num_backedges;
        visit->num_backedges = 0;
@@ -1968,22 +1968,22 @@ static int add_scc_backedge(struct bpf_verifier_env *env,
                            struct bpf_verifier_state *st,
                            struct bpf_scc_backedge *backedge)
 {
-       struct bpf_scc_callchain callchain;
+       struct bpf_scc_callchain *callchain = &env->callchain_buf;
        struct bpf_scc_visit *visit;
 
-       if (!compute_scc_callchain(env, st, &callchain)) {
+       if (!compute_scc_callchain(env, st, callchain)) {
                verifier_bug(env, "add backedge: no SCC in verification path, insn_idx %d",
                             st->insn_idx);
                return -EFAULT;
        }
-       visit = scc_visit_lookup(env, &callchain);
+       visit = scc_visit_lookup(env, callchain);
        if (!visit) {
                verifier_bug(env, "add backedge: no visit info for call chain %s",
-                            format_callchain(env, &callchain));
+                            format_callchain(env, callchain));
                return -EFAULT;
        }
        if (env->log.level & BPF_LOG_LEVEL2)
-               verbose(env, "SCC backedge %s\n", format_callchain(env, &callchain));
+               verbose(env, "SCC backedge %s\n", format_callchain(env, callchain));
        backedge->next = visit->backedges;
        visit->backedges = backedge;
        visit->num_backedges++;
@@ -1999,12 +1999,12 @@ static int add_scc_backedge(struct bpf_verifier_env *env,
 static bool incomplete_read_marks(struct bpf_verifier_env *env,
                                  struct bpf_verifier_state *st)
 {
-       struct bpf_scc_callchain callchain;
+       struct bpf_scc_callchain *callchain = &env->callchain_buf;
        struct bpf_scc_visit *visit;
 
-       if (!compute_scc_callchain(env, st, &callchain))
+       if (!compute_scc_callchain(env, st, callchain))
                return false;
-       visit = scc_visit_lookup(env, &callchain);
+       visit = scc_visit_lookup(env, callchain);
        if (!visit)
                return false;
        return !!visit->backedges;