Skip to content

Commit 518584c

Browse files
etsalKernel Patches Daemon
authored andcommitted
bpf: Bump maximum runtime call stack depth to 16
The BPF verifier currently limits the maximum runtime call stack to 8 frames. Larger BPF programs like sched-ext schedulers routinely fail verification because they exceed this limit, even as they use very little actual stack space for each frame. Bump the maximum runtime call stack depth to 16 stack frames. Also adjust selftests that assume the max runtime call stack depth is 8. This patch does not change the verification time limit of 8 stack frames. Static functions that are inlined for verification purposes still only go 8 frames deep to avoid changing the verifier's internal data structures used for verification. These data structures only support holding information on up to 8 stack frames. Global functions are each verified in isolation, so the old 8 stack frame limit now only applies to call stacks composed entirely of static function calls. This patch also does not adjust the actual maximum stack size of 512. CHANGELOG ========= v1 -> v2 (https://lore.kernel.org/bpf/DG510ANGXEZH.BJ9EMMKHP5WT@etsalapatis.com) - Adjust patch to only increase the runtime stack depth, leaving the verification-time stack depth unchanged (Alexei) Signed-off-by: Emil Tsalapatis <emil@etsalapatis.com>
1 parent b0043d3 commit 518584c

File tree

3 files changed

+78
-17
lines changed

3 files changed

+78
-17
lines changed

include/linux/bpf_verifier.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,8 @@ struct bpf_func_state {
321321
int allocated_stack;
322322
};
323323

324-
#define MAX_CALL_FRAMES 8
324+
#define MAX_CALL_FRAMES 8 /* How many frames we can verify at the same time */
325+
#define MAX_CALL_DEPTH 16 /* How deep of a stack we can have at runtime */
325326

326327
/* instruction history flags, used in bpf_jmp_history_entry.flags field */
327328
enum {

kernel/bpf/verifier.c

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6660,17 +6660,17 @@ static int round_up_stack_depth(struct bpf_verifier_env *env, int stack_depth)
66606660
* and recursively walk all callees that given function can call.
66616661
* Ignore jump and exit insns.
66626662
* Since recursion is prevented by check_cfg() this algorithm
6663-
* only needs a local stack of MAX_CALL_FRAMES to remember callsites
6663+
* only needs a local stack of MAX_CALL_DEPTH to remember callsites
66646664
*/
66656665
static int check_max_stack_depth_subprog(struct bpf_verifier_env *env, int idx,
66666666
bool priv_stack_supported)
66676667
{
66686668
struct bpf_subprog_info *subprog = env->subprog_info;
66696669
struct bpf_insn *insn = env->prog->insnsi;
6670-
int depth = 0, frame = 0, i, subprog_end, subprog_depth;
6670+
int depth = 0, frame = 0, calldepth = 0, i, subprog_end, subprog_depth;
66716671
bool tail_call_reachable = false;
6672-
int ret_insn[MAX_CALL_FRAMES];
6673-
int ret_prog[MAX_CALL_FRAMES];
6672+
int ret_insn[MAX_CALL_DEPTH];
6673+
int ret_prog[MAX_CALL_DEPTH];
66746674
int j;
66756675

66766676
i = subprog[idx].start;
@@ -6724,7 +6724,7 @@ static int check_max_stack_depth_subprog(struct bpf_verifier_env *env, int idx,
67246724
depth += subprog_depth;
67256725
if (depth > MAX_BPF_STACK) {
67266726
verbose(env, "combined stack size of %d calls is %d. Too large\n",
6727-
frame + 1, depth);
6727+
calldepth + 1, depth);
67286728
return -EACCES;
67296729
}
67306730
}
@@ -6740,7 +6740,7 @@ static int check_max_stack_depth_subprog(struct bpf_verifier_env *env, int idx,
67406740
continue;
67416741
if (subprog[idx].is_cb)
67426742
err = true;
6743-
for (int c = 0; c < frame && !err; c++) {
6743+
for (int c = 0; c < calldepth && !err; c++) {
67446744
if (subprog[ret_prog[c]].is_cb) {
67456745
err = true;
67466746
break;
@@ -6757,8 +6757,8 @@ static int check_max_stack_depth_subprog(struct bpf_verifier_env *env, int idx,
67576757
if (!bpf_pseudo_call(insn + i) && !bpf_pseudo_func(insn + i))
67586758
continue;
67596759
/* remember insn and function to return to */
6760-
ret_insn[frame] = i + 1;
6761-
ret_prog[frame] = idx;
6760+
ret_insn[calldepth] = i + 1;
6761+
ret_prog[calldepth] = idx;
67626762

67636763
/* find the callee */
67646764
next_insn = i + insn[i].imm + 1;
@@ -6786,7 +6786,17 @@ static int check_max_stack_depth_subprog(struct bpf_verifier_env *env, int idx,
67866786
if (subprog[idx].has_tail_call)
67876787
tail_call_reachable = true;
67886788

6789-
frame++;
6789+
if (!subprog_is_global(env, sidx))
6790+
frame++;
6791+
calldepth++;
6792+
/* Total call depth including globals */
6793+
if (calldepth >= MAX_CALL_DEPTH) {
6794+
verbose(env, "total call depth is %d frames, too deep\n",
6795+
calldepth);
6796+
return -E2BIG;
6797+
}
6798+
6799+
/* Total stack frames in use (globals not included). */
67906800
if (frame >= MAX_CALL_FRAMES) {
67916801
verbose(env, "the call stack of %d frames is too deep !\n",
67926802
frame);
@@ -6800,7 +6810,7 @@ static int check_max_stack_depth_subprog(struct bpf_verifier_env *env, int idx,
68006810
* tail call counter throughout bpf2bpf calls combined with tailcalls
68016811
*/
68026812
if (tail_call_reachable)
6803-
for (j = 0; j < frame; j++) {
6813+
for (j = 0; j < calldepth; j++) {
68046814
if (subprog[ret_prog[j]].is_exception_cb) {
68056815
verbose(env, "cannot tail call within exception cb\n");
68066816
return -EINVAL;
@@ -6813,13 +6823,15 @@ static int check_max_stack_depth_subprog(struct bpf_verifier_env *env, int idx,
68136823
/* end of for() loop means the last insn of the 'subprog'
68146824
* was reached. Doesn't matter whether it was JA or EXIT
68156825
*/
6816-
if (frame == 0)
6826+
if (calldepth == 0)
68176827
return 0;
68186828
if (subprog[idx].priv_stack_mode != PRIV_STACK_ADAPTIVE)
68196829
depth -= round_up_stack_depth(env, subprog[idx].stack_depth);
6820-
frame--;
6821-
i = ret_insn[frame];
6822-
idx = ret_prog[frame];
6830+
if (!subprog_is_global(env, idx))
6831+
frame--;
6832+
calldepth--;
6833+
i = ret_insn[calldepth];
6834+
idx = ret_prog[calldepth];
68236835
goto continue_func;
68246836
}
68256837

tools/testing/selftests/bpf/progs/test_global_func3.c

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,57 @@ int f8(struct __sk_buff *skb)
5353
return f7(skb);
5454
}
5555

56+
__attribute__ ((noinline))
57+
int f9(struct __sk_buff *skb)
58+
{
59+
return f8(skb);
60+
}
61+
62+
__attribute__ ((noinline))
63+
int f10(struct __sk_buff *skb)
64+
{
65+
return f9(skb);
66+
}
67+
68+
__attribute__ ((noinline))
69+
int f11(struct __sk_buff *skb)
70+
{
71+
return f10(skb);
72+
}
73+
74+
__attribute__ ((noinline))
75+
int f12(struct __sk_buff *skb)
76+
{
77+
return f11(skb);
78+
}
79+
80+
__attribute__ ((noinline))
81+
int f13(struct __sk_buff *skb)
82+
{
83+
return f12(skb);
84+
}
85+
86+
__attribute__ ((noinline))
87+
int f14(struct __sk_buff *skb)
88+
{
89+
return f13(skb);
90+
}
91+
92+
__attribute__ ((noinline))
93+
int f15(struct __sk_buff *skb)
94+
{
95+
return f14(skb);
96+
}
97+
98+
__attribute__ ((noinline))
99+
int f16(struct __sk_buff *skb)
100+
{
101+
return f15(skb);
102+
}
103+
56104
SEC("tc")
57-
__failure __msg("the call stack of 8 frames")
105+
__failure __msg("total call depth is 16 frames, too deep")
58106
int global_func3(struct __sk_buff *skb)
59107
{
60-
return f8(skb);
108+
return f16(skb);
61109
}

0 commit comments

Comments
 (0)