OSDN Git Service

bpf: Teach stack depth check about async callbacks.
authorAlexei Starovoitov <ast@kernel.org>
Thu, 15 Jul 2021 00:54:15 +0000 (17:54 -0700)
committerDaniel Borkmann <daniel@iogearbox.net>
Thu, 15 Jul 2021 20:31:10 +0000 (22:31 +0200)
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
include/linux/bpf_verifier.h
kernel/bpf/verifier.c

index 242d0b1..b847e1c 100644 (file)
@@ -406,6 +406,7 @@ struct bpf_subprog_info {
        bool has_tail_call;
        bool tail_call_reachable;
        bool has_ld_abs;
+       bool is_async_cb;
 };
 
 /* single container for all structs
index ab06256..344ee67 100644 (file)
@@ -3709,6 +3709,8 @@ process_func:
 continue_func:
        subprog_end = subprog[idx + 1].start;
        for (; i < subprog_end; i++) {
+               int next_insn;
+
                if (!bpf_pseudo_call(insn + i) && !bpf_pseudo_func(insn + i))
                        continue;
                /* remember insn and function to return to */
@@ -3716,13 +3718,22 @@ continue_func:
                ret_prog[frame] = idx;
 
                /* find the callee */
-               i = i + insn[i].imm + 1;
-               idx = find_subprog(env, i);
+               next_insn = i + insn[i].imm + 1;
+               idx = find_subprog(env, next_insn);
                if (idx < 0) {
                        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;
+                       }
+                        /* async callbacks don't increase bpf prog stack size */
+                       continue;
+               }
+               i = next_insn;
 
                if (subprog[idx].has_tail_call)
                        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;
 
                /* 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,
                                         *insn_idx, subprog);
                if (!async_cb)