Commit 7ddc80a4 authored by Alexei Starovoitov's avatar Alexei Starovoitov Committed by Daniel Borkmann

bpf: Teach stack depth check about async callbacks.

Teach max stack depth checking algorithm about async callbacks
that don't increase bpf program stack size.
Also add sanity check that bpf_tail_call didn't sneak into async cb.
It's impossible, since PTR_TO_CTX is not available in async cb,
hence the program cannot contain bpf_tail_call(ctx,...);
Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
Acked-by: default avatarAndrii Nakryiko <andrii@kernel.org>
Acked-by: default avatarToke Høiland-Jørgensen <toke@redhat.com>
Link: https://lore.kernel.org/bpf/20210715005417.78572-10-alexei.starovoitov@gmail.com
parent bfc6bb74
...@@ -406,6 +406,7 @@ struct bpf_subprog_info { ...@@ -406,6 +406,7 @@ struct bpf_subprog_info {
bool has_tail_call; bool has_tail_call;
bool tail_call_reachable; bool tail_call_reachable;
bool has_ld_abs; bool has_ld_abs;
bool is_async_cb;
}; };
/* single container for all structs /* single container for all structs
......
...@@ -3709,6 +3709,8 @@ static int check_max_stack_depth(struct bpf_verifier_env *env) ...@@ -3709,6 +3709,8 @@ static int check_max_stack_depth(struct bpf_verifier_env *env)
continue_func: continue_func:
subprog_end = subprog[idx + 1].start; subprog_end = subprog[idx + 1].start;
for (; i < subprog_end; i++) { for (; i < subprog_end; i++) {
int next_insn;
if (!bpf_pseudo_call(insn + i) && !bpf_pseudo_func(insn + i)) if (!bpf_pseudo_call(insn + i) && !bpf_pseudo_func(insn + i))
continue; continue;
/* remember insn and function to return to */ /* remember insn and function to return to */
...@@ -3716,13 +3718,22 @@ static int check_max_stack_depth(struct bpf_verifier_env *env) ...@@ -3716,13 +3718,22 @@ static int check_max_stack_depth(struct bpf_verifier_env *env)
ret_prog[frame] = idx; ret_prog[frame] = idx;
/* find the callee */ /* find the callee */
i = i + insn[i].imm + 1; next_insn = i + insn[i].imm + 1;
idx = find_subprog(env, i); idx = find_subprog(env, next_insn);
if (idx < 0) { if (idx < 0) {
WARN_ONCE(1, "verifier bug. No program starts at insn %d\n", WARN_ONCE(1, "verifier bug. No program starts at insn %d\n",
i); next_insn);
return -EFAULT;
}
if (subprog[idx].is_async_cb) {
if (subprog[idx].has_tail_call) {
verbose(env, "verifier bug. subprog has tail_call and async cb\n");
return -EFAULT; return -EFAULT;
} }
/* async callbacks don't increase bpf prog stack size */
continue;
}
i = next_insn;
if (subprog[idx].has_tail_call) if (subprog[idx].has_tail_call)
tail_call_reachable = true; tail_call_reachable = true;
...@@ -5761,6 +5772,7 @@ static int __check_func_call(struct bpf_verifier_env *env, struct bpf_insn *insn ...@@ -5761,6 +5772,7 @@ static int __check_func_call(struct bpf_verifier_env *env, struct bpf_insn *insn
struct bpf_verifier_state *async_cb; struct bpf_verifier_state *async_cb;
/* there is no real recursion here. timer callbacks are async */ /* there is no real recursion here. timer callbacks are async */
env->subprog_info[subprog].is_async_cb = true;
async_cb = push_async_cb(env, env->subprog_info[subprog].start, async_cb = push_async_cb(env, env->subprog_info[subprog].start,
*insn_idx, subprog); *insn_idx, subprog);
if (!async_cb) if (!async_cb)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment