bpf: refactor fixup_bpf_calls()
authorAlexei Starovoitov <ast@fb.com>
Thu, 16 Mar 2017 01:26:40 +0000 (18:26 -0700)
committerDavid S. Miller <davem@davemloft.net>
Fri, 17 Mar 2017 03:44:11 +0000 (20:44 -0700)
reduce indent and make it iterate over instructions similar to
convert_ctx_accesses(). Also convert hard BUG_ON into soft verifier error.

Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Acked-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
kernel/bpf/verifier.c

index e41da6c570530726929c427c8c414e3e82d74c61..5dfa9b8111da9209b1e003a044428ad244e591b4 100644 (file)
@@ -3233,59 +3233,53 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env)
        return 0;
 }
 
-/* fixup insn->imm field of bpf_call instructions:
- * if (insn->imm == BPF_FUNC_map_lookup_elem)
- *      insn->imm = bpf_map_lookup_elem - __bpf_call_base;
- * else if (insn->imm == BPF_FUNC_map_update_elem)
- *      insn->imm = bpf_map_update_elem - __bpf_call_base;
- * else ...
+/* fixup insn->imm field of bpf_call instructions
  *
  * this function is called after eBPF program passed verification
  */
-static void fixup_bpf_calls(struct bpf_prog *prog)
+static int fixup_bpf_calls(struct bpf_verifier_env *env)
 {
+       struct bpf_prog *prog = env->prog;
+       struct bpf_insn *insn = prog->insnsi;
        const struct bpf_func_proto *fn;
+       const int insn_cnt = prog->len;
        int i;
 
-       for (i = 0; i < prog->len; i++) {
-               struct bpf_insn *insn = &prog->insnsi[i];
+       for (i = 0; i < insn_cnt; i++, insn++) {
+               if (insn->code != (BPF_JMP | BPF_CALL))
+                       continue;
 
-               if (insn->code == (BPF_JMP | BPF_CALL)) {
-                       /* we reach here when program has bpf_call instructions
-                        * and it passed bpf_check(), means that
-                        * ops->get_func_proto must have been supplied, check it
+               if (insn->imm == BPF_FUNC_get_route_realm)
+                       prog->dst_needed = 1;
+               if (insn->imm == BPF_FUNC_get_prandom_u32)
+                       bpf_user_rnd_init_once();
+               if (insn->imm == BPF_FUNC_xdp_adjust_head)
+                       prog->xdp_adjust_head = 1;
+               if (insn->imm == BPF_FUNC_tail_call) {
+                       /* mark bpf_tail_call as different opcode to avoid
+                        * conditional branch in the interpeter for every normal
+                        * call and to prevent accidental JITing by JIT compiler
+                        * that doesn't support bpf_tail_call yet
                         */
-                       BUG_ON(!prog->aux->ops->get_func_proto);
-
-                       if (insn->imm == BPF_FUNC_get_route_realm)
-                               prog->dst_needed = 1;
-                       if (insn->imm == BPF_FUNC_get_prandom_u32)
-                               bpf_user_rnd_init_once();
-                       if (insn->imm == BPF_FUNC_xdp_adjust_head)
-                               prog->xdp_adjust_head = 1;
-                       if (insn->imm == BPF_FUNC_tail_call) {
-                               /* mark bpf_tail_call as different opcode
-                                * to avoid conditional branch in
-                                * interpeter for every normal call
-                                * and to prevent accidental JITing by
-                                * JIT compiler that doesn't support
-                                * bpf_tail_call yet
-                                */
-                               insn->imm = 0;
-                               insn->code |= BPF_X;
-                               continue;
-                       }
+                       insn->imm = 0;
+                       insn->code |= BPF_X;
+                       continue;
+               }
 
-                       fn = prog->aux->ops->get_func_proto(insn->imm);
-                       /* all functions that have prototype and verifier allowed
-                        * programs to call them, must be real in-kernel functions
-                        */
-                       BUG_ON(!fn->func);
-                       insn->imm = fn->func - __bpf_call_base;
+               fn = prog->aux->ops->get_func_proto(insn->imm);
+               /* all functions that have prototype and verifier allowed
+                * programs to call them, must be real in-kernel functions
+                */
+               if (!fn->func) {
+                       verbose("kernel subsystem misconfigured func %s#%d\n",
+                               func_id_name(insn->imm), insn->imm);
+                       return -EFAULT;
                }
+               insn->imm = fn->func - __bpf_call_base;
        }
-}
 
+       return 0;
+}
 
 static void free_states(struct bpf_verifier_env *env)
 {
@@ -3383,7 +3377,7 @@ skip_full_check:
                ret = convert_ctx_accesses(env);
 
        if (ret == 0)
-               fixup_bpf_calls(env->prog);
+               ret = fixup_bpf_calls(env);
 
        if (log_level && log_len >= log_size - 1) {
                BUG_ON(log_len >= log_size);