summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexei Starovoitov <ast@kernel.org>2026-05-14 04:38:31 +0300
committerAlexei Starovoitov <ast@kernel.org>2026-05-14 04:38:31 +0300
commite651f3ce1364d06d97bb7cc4aa5b23146420a67d (patch)
tree46d5982b8e4ff5d99e4a5e96e200def9aa00dbb6
parent74a9bb761a434ea3be1e0c59cd67b37217eb042c (diff)
parentf0015ffbf40c7c6db148163bd6f8c53f14933b53 (diff)
downloadlinux-e651f3ce1364d06d97bb7cc4aa5b23146420a67d.tar.xz
Merge branch 'bpf-maximum-combined-stack-depth'
Paul Chaignon says: ==================== bpf: Maximum combined stack depth This patchset dumps the maximum combined stack depth in verifier logs and parses it in veristat. Changes in v3: - Increment spec_cnt field in veristat for new MAX_STACK id (AI bot). Changes in v2: - Remove unnecessary max_stack_depth assignment (Eduard). - Fix and test incorrect handling of private stacks. - Add veristat metric (Eduard). ==================== Link: https://patch.msgid.link/cover.1778700777.git.paul.chaignon@gmail.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
-rw-r--r--include/linux/bpf_verifier.h2
-rw-r--r--kernel/bpf/verifier.c6
-rw-r--r--tools/testing/selftests/bpf/progs/verifier_bpf_fastcall.c3
-rw-r--r--tools/testing/selftests/bpf/progs/verifier_private_stack.c15
-rw-r--r--tools/testing/selftests/bpf/veristat.c13
5 files changed, 32 insertions, 7 deletions
diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
index 6f12fc40b682..20c421b43849 100644
--- a/include/linux/bpf_verifier.h
+++ b/include/linux/bpf_verifier.h
@@ -989,6 +989,8 @@ struct bpf_verifier_env {
u32 prev_insn_processed, insn_processed;
/* number of jmps, calls, exits analyzed so far */
u32 prev_jmps_processed, jmps_processed;
+ /* maximum combined stack depth */
+ u32 max_stack_depth;
/* total verification time */
u64 verification_time;
/* maximum number of verifier states kept in 'branching' instructions */
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 82b9531f87f6..76a07f09ab64 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -5177,6 +5177,8 @@ process_func:
}
if (subprog[idx].priv_stack_mode == PRIV_STACK_ADAPTIVE) {
+ if (subprog_depth > env->max_stack_depth)
+ env->max_stack_depth = subprog_depth;
if (subprog_depth > MAX_BPF_STACK) {
verbose(env, "stack size of subprog %d is %d. Too large\n",
idx, subprog_depth);
@@ -5184,6 +5186,8 @@ process_func:
}
} else {
depth += subprog_depth;
+ if (depth > env->max_stack_depth)
+ env->max_stack_depth = depth;
if (depth > MAX_BPF_STACK) {
total = 0;
for (tmp = idx; tmp >= 0; tmp = dinfo[tmp].caller)
@@ -18555,7 +18559,7 @@ static void print_verification_stats(struct bpf_verifier_env *env)
verbose(env, "stack depth %d", env->subprog_info[0].stack_depth);
for (i = 1; i < subprog_cnt; i++)
verbose(env, "+%d", env->subprog_info[i].stack_depth);
- verbose(env, "\n");
+ verbose(env, " max %d\n", env->max_stack_depth);
verbose(env, "insns processed %d", env->subprog_info[0].insn_processed);
for (i = 1; i < subprog_cnt; i++)
if (bpf_subprog_is_global(env, i))
diff --git a/tools/testing/selftests/bpf/progs/verifier_bpf_fastcall.c b/tools/testing/selftests/bpf/progs/verifier_bpf_fastcall.c
index 0d9e167555b5..8d7ff38e4c06 100644
--- a/tools/testing/selftests/bpf/progs/verifier_bpf_fastcall.c
+++ b/tools/testing/selftests/bpf/progs/verifier_bpf_fastcall.c
@@ -799,8 +799,7 @@ __naked int bpf_loop_interaction2(void)
SEC("raw_tp")
__arch_x86_64
-__log_level(4)
-__msg("stack depth 512+0")
+__log_level(4) __msg("stack depth 512+0 max 512")
/* just to print xlated version when debugging */
__xlated("r0 = &(void __percpu *)(r0)")
__success
diff --git a/tools/testing/selftests/bpf/progs/verifier_private_stack.c b/tools/testing/selftests/bpf/progs/verifier_private_stack.c
index c5078face38d..046f7445a458 100644
--- a/tools/testing/selftests/bpf/progs/verifier_private_stack.c
+++ b/tools/testing/selftests/bpf/progs/verifier_private_stack.c
@@ -86,6 +86,7 @@ __naked static void cumulative_stack_depth_subprog(void)
SEC("kprobe")
__description("Private stack, subtree > MAX_BPF_STACK")
__success
+__log_level(4) __msg("stack depth 512+32 max 512")
__arch_x86_64
/* private stack fp for the main prog */
__jited(" movabsq $0x{{.*}}, %r9")
@@ -324,6 +325,8 @@ int private_stack_async_callback_1(void)
SEC("fentry/bpf_fentry_test9")
__description("Private stack, async callback, potential nesting")
__success __retval(0)
+__load_if_JITed()
+__log_level(4) __msg("stack depth 8+0+256+0 max 272")
__arch_x86_64
__jited(" subq $0x100, %rsp")
__arch_arm64
@@ -344,6 +347,18 @@ int private_stack_async_callback_2(void)
return 0;
}
+SEC("fentry/bpf_fentry_test9")
+__description("private stack, max stack depth is private stack")
+__success
+__log_level(4) __msg("stack depth 8+256+0 max 256")
+int private_stack_max_depth(void)
+{
+ int x = 0;
+
+ subprog1(&x);
+ return 0;
+}
+
#else
SEC("kprobe")
diff --git a/tools/testing/selftests/bpf/veristat.c b/tools/testing/selftests/bpf/veristat.c
index 5c82950e6978..a7db6f04f7e1 100644
--- a/tools/testing/selftests/bpf/veristat.c
+++ b/tools/testing/selftests/bpf/veristat.c
@@ -48,6 +48,7 @@ enum stat_id {
SIZE,
JITED_SIZE,
STACK,
+ MAX_STACK,
PROG_TYPE,
ATTACH_TYPE,
MEMORY_PEAK,
@@ -789,13 +790,13 @@ cleanup:
}
static const struct stat_specs default_csv_output_spec = {
- .spec_cnt = 15,
+ .spec_cnt = 16,
.ids = {
FILE_NAME, PROG_NAME, VERDICT, DURATION,
TOTAL_INSNS, TOTAL_STATES, PEAK_STATES,
MAX_STATES_PER_INSN, MARK_READ_MAX_LEN,
SIZE, JITED_SIZE, PROG_TYPE, ATTACH_TYPE,
- STACK, MEMORY_PEAK,
+ STACK, MAX_STACK, MEMORY_PEAK,
},
};
@@ -834,6 +835,7 @@ static struct stat_def {
[SIZE] = { "Program size", {"prog_size"}, },
[JITED_SIZE] = { "Jited size", {"prog_size_jited"}, },
[STACK] = {"Stack depth", {"stack_depth", "stack"}, },
+ [MAX_STACK] = {"Max stack depth", {"max_stack_depth"}, },
[PROG_TYPE] = { "Program type", {"prog_type"}, },
[ATTACH_TYPE] = { "Attach type", {"attach_type", }, },
[MEMORY_PEAK] = { "Peak memory (MiB)", {"mem_peak", }, },
@@ -1023,7 +1025,7 @@ static int parse_verif_log(char * const buf, size_t buf_sz, struct verif_stats *
&s->stats[MARK_READ_MAX_LEN]))
continue;
- if (1 == sscanf(cur, "stack depth %511s", stack))
+ if (2 == sscanf(cur, "stack depth %511s max %ld", stack, &s->stats[MAX_STACK]))
continue;
}
while ((token = strtok_r(cnt++ ? NULL : stack, "+", &state))) {
@@ -2278,6 +2280,7 @@ static int cmp_stat(const struct verif_stats *s1, const struct verif_stats *s2,
case SIZE:
case JITED_SIZE:
case STACK:
+ case MAX_STACK:
case VERDICT:
case DURATION:
case TOTAL_INSNS:
@@ -2512,6 +2515,7 @@ static void prepare_value(const struct verif_stats *s, enum stat_id id,
case MAX_STATES_PER_INSN:
case MARK_READ_MAX_LEN:
case STACK:
+ case MAX_STACK:
case SIZE:
case JITED_SIZE:
case MEMORY_PEAK:
@@ -2602,7 +2606,8 @@ static int parse_stat_value(const char *str, enum stat_id id, struct verif_stats
case SIZE:
case JITED_SIZE:
case MEMORY_PEAK:
- case STACK: {
+ case STACK:
+ case MAX_STACK: {
long val;
int err, n;