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: Alexei Starovoitov <ast@kernel.org> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Acked-by: Andrii Nakryiko <andrii@kernel.org> Acked-by: Toke Høiland-Jørgensen <toke@redhat.com> Link: https://lore.kernel.org/bpf/20210715005417.78572-10-alexei.starovoitov@gmail.com
This commit is contained in:
parent
bfc6bb74e4
commit
7ddc80a476
2 changed files with 16 additions and 3 deletions
|
@ -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 @@ process_func:
|
||||||
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 @@ continue_func:
|
||||||
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;
|
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;
|
||||||
|
}
|
||||||
|
/* 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
|
||||||
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)
|
||||||
|
|
Loading…
Add table
Reference in a new issue