bpf: Refactor check_func_call() to allow callback function
authorYonghong Song <yhs@fb.com>
Fri, 26 Feb 2021 20:49:23 +0000 (12:49 -0800)
committerAlexei Starovoitov <ast@kernel.org>
Fri, 26 Feb 2021 21:23:52 +0000 (13:23 -0800)
Later proposed bpf_for_each_map_elem() helper has callback
function as one of its arguments. This patch refactored
check_func_call() to permit callback function which sets
callee state. Different callback functions may have
different callee states.
There is no functionality change for this patch.

Signed-off-by: Yonghong Song <yhs@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Acked-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20210226204923.3884627-1-yhs@fb.com
kernel/bpf/verifier.c

index 7194980..97e772f 100644 (file)
@@ -5249,13 +5249,19 @@ static void clear_caller_saved_regs(struct bpf_verifier_env *env,
        }
 }
 
-static int check_func_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
-                          int *insn_idx)
+typedef int (*set_callee_state_fn)(struct bpf_verifier_env *env,
+                                  struct bpf_func_state *caller,
+                                  struct bpf_func_state *callee,
+                                  int insn_idx);
+
+static int __check_func_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
+                            int *insn_idx, int subprog,
+                            set_callee_state_fn set_callee_state_cb)
 {
        struct bpf_verifier_state *state = env->cur_state;
        struct bpf_func_info_aux *func_info_aux;
        struct bpf_func_state *caller, *callee;
-       int i, err, subprog, target_insn;
+       int err;
        bool is_global = false;
 
        if (state->curframe + 1 >= MAX_CALL_FRAMES) {
@@ -5264,14 +5270,6 @@ static int check_func_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
                return -E2BIG;
        }
 
-       target_insn = *insn_idx + insn->imm;
-       subprog = find_subprog(env, target_insn + 1);
-       if (subprog < 0) {
-               verbose(env, "verifier bug. No program starts at insn %d\n",
-                       target_insn + 1);
-               return -EFAULT;
-       }
-
        caller = state->frame[state->curframe];
        if (state->frame[state->curframe + 1]) {
                verbose(env, "verifier bug. Frame %d already allocated\n",
@@ -5326,11 +5324,9 @@ static int check_func_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
        if (err)
                return err;
 
-       /* copy r1 - r5 args that callee can access.  The copy includes parent
-        * pointers, which connects us up to the liveness chain
-        */
-       for (i = BPF_REG_1; i <= BPF_REG_5; i++)
-               callee->regs[i] = caller->regs[i];
+       err = set_callee_state_cb(env, caller, callee, *insn_idx);
+       if (err)
+               return err;
 
        clear_caller_saved_regs(env, caller->regs);
 
@@ -5338,7 +5334,7 @@ static int check_func_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
        state->curframe++;
 
        /* and go analyze first insn of the callee */
-       *insn_idx = target_insn;
+       *insn_idx = env->subprog_info[subprog].start - 1;
 
        if (env->log.level & BPF_LOG_LEVEL) {
                verbose(env, "caller:\n");
@@ -5349,6 +5345,36 @@ static int check_func_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
        return 0;
 }
 
+static int set_callee_state(struct bpf_verifier_env *env,
+                           struct bpf_func_state *caller,
+                           struct bpf_func_state *callee, int insn_idx)
+{
+       int i;
+
+       /* copy r1 - r5 args that callee can access.  The copy includes parent
+        * pointers, which connects us up to the liveness chain
+        */
+       for (i = BPF_REG_1; i <= BPF_REG_5; i++)
+               callee->regs[i] = caller->regs[i];
+       return 0;
+}
+
+static int check_func_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
+                          int *insn_idx)
+{
+       int subprog, target_insn;
+
+       target_insn = *insn_idx + insn->imm + 1;
+       subprog = find_subprog(env, target_insn);
+       if (subprog < 0) {
+               verbose(env, "verifier bug. No program starts at insn %d\n",
+                       target_insn);
+               return -EFAULT;
+       }
+
+       return __check_func_call(env, insn, insn_idx, subprog, set_callee_state);
+}
+
 static int prepare_func_exit(struct bpf_verifier_env *env, int *insn_idx)
 {
        struct bpf_verifier_state *state = env->cur_state;