Merge git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next
[platform/kernel/linux-rpi.git] / kernel / bpf / verifier.c
index c56e3fc..f9096b0 100644 (file)
@@ -234,6 +234,12 @@ static bool bpf_pseudo_call(const struct bpf_insn *insn)
               insn->src_reg == BPF_PSEUDO_CALL;
 }
 
+static bool bpf_pseudo_func(const struct bpf_insn *insn)
+{
+       return insn->code == (BPF_LD | BPF_IMM | BPF_DW) &&
+              insn->src_reg == BPF_PSEUDO_FUNC;
+}
+
 struct bpf_call_arg_meta {
        struct bpf_map *map_ptr;
        bool raw_mode;
@@ -248,6 +254,7 @@ struct bpf_call_arg_meta {
        u32 btf_id;
        struct btf *ret_btf;
        u32 ret_btf_id;
+       u32 subprogno;
 };
 
 struct btf *btf_vmlinux;
@@ -390,6 +397,24 @@ __printf(3, 4) static void verbose_linfo(struct bpf_verifier_env *env,
        env->prev_linfo = linfo;
 }
 
+static void verbose_invalid_scalar(struct bpf_verifier_env *env,
+                                  struct bpf_reg_state *reg,
+                                  struct tnum *range, const char *ctx,
+                                  const char *reg_name)
+{
+       char tn_buf[48];
+
+       verbose(env, "At %s the register %s ", ctx, reg_name);
+       if (!tnum_is_unknown(reg->var_off)) {
+               tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off);
+               verbose(env, "has value %s", tn_buf);
+       } else {
+               verbose(env, "has unknown scalar value");
+       }
+       tnum_strn(tn_buf, sizeof(tn_buf), *range);
+       verbose(env, " should have been in %s\n", tn_buf);
+}
+
 static bool type_is_pkt_pointer(enum bpf_reg_type type)
 {
        return type == PTR_TO_PACKET ||
@@ -409,6 +434,7 @@ static bool reg_type_not_null(enum bpf_reg_type type)
        return type == PTR_TO_SOCKET ||
                type == PTR_TO_TCP_SOCK ||
                type == PTR_TO_MAP_VALUE ||
+               type == PTR_TO_MAP_KEY ||
                type == PTR_TO_SOCK_COMMON;
 }
 
@@ -451,7 +477,8 @@ static bool arg_type_may_be_null(enum bpf_arg_type type)
               type == ARG_PTR_TO_MEM_OR_NULL ||
               type == ARG_PTR_TO_CTX_OR_NULL ||
               type == ARG_PTR_TO_SOCKET_OR_NULL ||
-              type == ARG_PTR_TO_ALLOC_MEM_OR_NULL;
+              type == ARG_PTR_TO_ALLOC_MEM_OR_NULL ||
+              type == ARG_PTR_TO_STACK_OR_NULL;
 }
 
 /* Determine whether the function releases some resources allocated by another
@@ -541,6 +568,8 @@ static const char * const reg_type_str[] = {
        [PTR_TO_RDONLY_BUF_OR_NULL] = "rdonly_buf_or_null",
        [PTR_TO_RDWR_BUF]       = "rdwr_buf",
        [PTR_TO_RDWR_BUF_OR_NULL] = "rdwr_buf_or_null",
+       [PTR_TO_FUNC]           = "func",
+       [PTR_TO_MAP_KEY]        = "map_key",
 };
 
 static char slot_type_char[] = {
@@ -612,6 +641,7 @@ static void print_verifier_state(struct bpf_verifier_env *env,
                        if (type_is_pkt_pointer(t))
                                verbose(env, ",r=%d", reg->range);
                        else if (t == CONST_PTR_TO_MAP ||
+                                t == PTR_TO_MAP_KEY ||
                                 t == PTR_TO_MAP_VALUE ||
                                 t == PTR_TO_MAP_VALUE_OR_NULL)
                                verbose(env, ",ks=%d,vs=%d",
@@ -1519,7 +1549,7 @@ static int add_subprog(struct bpf_verifier_env *env, int off)
        }
        ret = find_subprog(env, off);
        if (ret >= 0)
-               return 0;
+               return ret;
        if (env->subprog_cnt >= BPF_MAX_SUBPROGS) {
                verbose(env, "too many subprograms\n");
                return -E2BIG;
@@ -1527,7 +1557,7 @@ static int add_subprog(struct bpf_verifier_env *env, int off)
        env->subprog_info[env->subprog_cnt++].start = off;
        sort(env->subprog_info, env->subprog_cnt,
             sizeof(env->subprog_info[0]), cmp_subprogs, NULL);
-       return 0;
+       return env->subprog_cnt - 1;
 }
 
 static int check_subprogs(struct bpf_verifier_env *env)
@@ -1544,6 +1574,19 @@ static int check_subprogs(struct bpf_verifier_env *env)
 
        /* determine subprog starts. The end is one before the next starts */
        for (i = 0; i < insn_cnt; i++) {
+               if (bpf_pseudo_func(insn + i)) {
+                       if (!env->bpf_capable) {
+                               verbose(env,
+                                       "function pointers are allowed for CAP_BPF and CAP_SYS_ADMIN\n");
+                               return -EPERM;
+                       }
+                       ret = add_subprog(env, i + insn[i].imm + 1);
+                       if (ret < 0)
+                               return ret;
+                       /* remember subprog */
+                       insn[i + 1].imm = ret;
+                       continue;
+               }
                if (!bpf_pseudo_call(insn + i))
                        continue;
                if (!env->bpf_capable) {
@@ -2295,6 +2338,8 @@ static bool is_spillable_regtype(enum bpf_reg_type type)
        case PTR_TO_PERCPU_BTF_ID:
        case PTR_TO_MEM:
        case PTR_TO_MEM_OR_NULL:
+       case PTR_TO_FUNC:
+       case PTR_TO_MAP_KEY:
                return true;
        default:
                return false;
@@ -2899,6 +2944,10 @@ static int __check_mem_access(struct bpf_verifier_env *env, int regno,
 
        reg = &cur_regs(env)[regno];
        switch (reg->type) {
+       case PTR_TO_MAP_KEY:
+               verbose(env, "invalid access to map key, key_size=%d off=%d size=%d\n",
+                       mem_size, off, size);
+               break;
        case PTR_TO_MAP_VALUE:
                verbose(env, "invalid access to map value, value_size=%d off=%d size=%d\n",
                        mem_size, off, size);
@@ -3304,6 +3353,9 @@ static int check_ptr_alignment(struct bpf_verifier_env *env,
        case PTR_TO_FLOW_KEYS:
                pointer_desc = "flow keys ";
                break;
+       case PTR_TO_MAP_KEY:
+               pointer_desc = "key ";
+               break;
        case PTR_TO_MAP_VALUE:
                pointer_desc = "value ";
                break;
@@ -3405,7 +3457,7 @@ process_func:
 continue_func:
        subprog_end = subprog[idx + 1].start;
        for (; i < subprog_end; i++) {
-               if (!bpf_pseudo_call(insn + i))
+               if (!bpf_pseudo_call(insn + i) && !bpf_pseudo_func(insn + i))
                        continue;
                /* remember insn and function to return to */
                ret_insn[frame] = i + 1;
@@ -3842,7 +3894,19 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn
        /* for access checks, reg->off is just part of off */
        off += reg->off;
 
-       if (reg->type == PTR_TO_MAP_VALUE) {
+       if (reg->type == PTR_TO_MAP_KEY) {
+               if (t == BPF_WRITE) {
+                       verbose(env, "write to change key R%d not allowed\n", regno);
+                       return -EACCES;
+               }
+
+               err = check_mem_region_access(env, regno, off, size,
+                                             reg->map_ptr->key_size, false);
+               if (err)
+                       return err;
+               if (value_regno >= 0)
+                       mark_reg_unknown(env, regs, value_regno);
+       } else if (reg->type == PTR_TO_MAP_VALUE) {
                if (t == BPF_WRITE && value_regno >= 0 &&
                    is_pointer_value(env, value_regno)) {
                        verbose(env, "R%d leaks addr into map\n", value_regno);
@@ -4258,6 +4322,9 @@ static int check_helper_mem_access(struct bpf_verifier_env *env, int regno,
        case PTR_TO_PACKET_META:
                return check_packet_access(env, regno, reg->off, access_size,
                                           zero_size_allowed);
+       case PTR_TO_MAP_KEY:
+               return check_mem_region_access(env, regno, reg->off, access_size,
+                                              reg->map_ptr->key_size, false);
        case PTR_TO_MAP_VALUE:
                if (check_map_access_type(env, regno, reg->off, access_size,
                                          meta && meta->raw_mode ? BPF_WRITE :
@@ -4474,6 +4541,7 @@ static const struct bpf_reg_types map_key_value_types = {
                PTR_TO_STACK,
                PTR_TO_PACKET,
                PTR_TO_PACKET_META,
+               PTR_TO_MAP_KEY,
                PTR_TO_MAP_VALUE,
        },
 };
@@ -4505,6 +4573,7 @@ static const struct bpf_reg_types mem_types = {
                PTR_TO_STACK,
                PTR_TO_PACKET,
                PTR_TO_PACKET_META,
+               PTR_TO_MAP_KEY,
                PTR_TO_MAP_VALUE,
                PTR_TO_MEM,
                PTR_TO_RDONLY_BUF,
@@ -4517,6 +4586,7 @@ static const struct bpf_reg_types int_ptr_types = {
                PTR_TO_STACK,
                PTR_TO_PACKET,
                PTR_TO_PACKET_META,
+               PTR_TO_MAP_KEY,
                PTR_TO_MAP_VALUE,
        },
 };
@@ -4529,6 +4599,8 @@ static const struct bpf_reg_types const_map_ptr_types = { .types = { CONST_PTR_T
 static const struct bpf_reg_types btf_ptr_types = { .types = { PTR_TO_BTF_ID } };
 static const struct bpf_reg_types spin_lock_types = { .types = { PTR_TO_MAP_VALUE } };
 static const struct bpf_reg_types percpu_btf_ptr_types = { .types = { PTR_TO_PERCPU_BTF_ID } };
+static const struct bpf_reg_types func_ptr_types = { .types = { PTR_TO_FUNC } };
+static const struct bpf_reg_types stack_ptr_types = { .types = { PTR_TO_STACK } };
 
 static const struct bpf_reg_types *compatible_reg_types[__BPF_ARG_TYPE_MAX] = {
        [ARG_PTR_TO_MAP_KEY]            = &map_key_value_types,
@@ -4557,6 +4629,8 @@ static const struct bpf_reg_types *compatible_reg_types[__BPF_ARG_TYPE_MAX] = {
        [ARG_PTR_TO_INT]                = &int_ptr_types,
        [ARG_PTR_TO_LONG]               = &int_ptr_types,
        [ARG_PTR_TO_PERCPU_BTF_ID]      = &percpu_btf_ptr_types,
+       [ARG_PTR_TO_FUNC]               = &func_ptr_types,
+       [ARG_PTR_TO_STACK_OR_NULL]      = &stack_ptr_types,
 };
 
 static int check_reg_type(struct bpf_verifier_env *env, u32 regno,
@@ -4738,6 +4812,8 @@ skip_type_check:
                        verbose(env, "verifier internal error\n");
                        return -EFAULT;
                }
+       } else if (arg_type == ARG_PTR_TO_FUNC) {
+               meta->subprogno = reg->subprogno;
        } else if (arg_type_is_mem_ptr(arg_type)) {
                /* The access to this pointer is only checked when we hit the
                 * next is_mem_size argument below.
@@ -5258,13 +5334,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) {
@@ -5273,14 +5355,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",
@@ -5335,11 +5409,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);
 
@@ -5347,7 +5419,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");
@@ -5358,6 +5430,92 @@ static int check_func_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
        return 0;
 }
 
+int map_set_for_each_callback_args(struct bpf_verifier_env *env,
+                                  struct bpf_func_state *caller,
+                                  struct bpf_func_state *callee)
+{
+       /* bpf_for_each_map_elem(struct bpf_map *map, void *callback_fn,
+        *      void *callback_ctx, u64 flags);
+        * callback_fn(struct bpf_map *map, void *key, void *value,
+        *      void *callback_ctx);
+        */
+       callee->regs[BPF_REG_1] = caller->regs[BPF_REG_1];
+
+       callee->regs[BPF_REG_2].type = PTR_TO_MAP_KEY;
+       __mark_reg_known_zero(&callee->regs[BPF_REG_2]);
+       callee->regs[BPF_REG_2].map_ptr = caller->regs[BPF_REG_1].map_ptr;
+
+       callee->regs[BPF_REG_3].type = PTR_TO_MAP_VALUE;
+       __mark_reg_known_zero(&callee->regs[BPF_REG_3]);
+       callee->regs[BPF_REG_3].map_ptr = caller->regs[BPF_REG_1].map_ptr;
+
+       /* pointer to stack or null */
+       callee->regs[BPF_REG_4] = caller->regs[BPF_REG_3];
+
+       /* unused */
+       __mark_reg_not_init(env, &callee->regs[BPF_REG_5]);
+       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 set_map_elem_callback_state(struct bpf_verifier_env *env,
+                                      struct bpf_func_state *caller,
+                                      struct bpf_func_state *callee,
+                                      int insn_idx)
+{
+       struct bpf_insn_aux_data *insn_aux = &env->insn_aux_data[insn_idx];
+       struct bpf_map *map;
+       int err;
+
+       if (bpf_map_ptr_poisoned(insn_aux)) {
+               verbose(env, "tail_call abusing map_ptr\n");
+               return -EINVAL;
+       }
+
+       map = BPF_MAP_PTR(insn_aux->map_ptr_state);
+       if (!map->ops->map_set_for_each_callback_args ||
+           !map->ops->map_for_each_callback) {
+               verbose(env, "callback function not allowed for map\n");
+               return -ENOTSUPP;
+       }
+
+       err = map->ops->map_set_for_each_callback_args(env, caller, callee);
+       if (err)
+               return err;
+
+       callee->in_callback_fn = true;
+       return 0;
+}
+
 static int prepare_func_exit(struct bpf_verifier_env *env, int *insn_idx)
 {
        struct bpf_verifier_state *state = env->cur_state;
@@ -5380,8 +5538,22 @@ static int prepare_func_exit(struct bpf_verifier_env *env, int *insn_idx)
 
        state->curframe--;
        caller = state->frame[state->curframe];
-       /* return to the caller whatever r0 had in the callee */
-       caller->regs[BPF_REG_0] = *r0;
+       if (callee->in_callback_fn) {
+               /* enforce R0 return value range [0, 1]. */
+               struct tnum range = tnum_range(0, 1);
+
+               if (r0->type != SCALAR_VALUE) {
+                       verbose(env, "R0 not a scalar value\n");
+                       return -EACCES;
+               }
+               if (!tnum_in(range, r0->var_off)) {
+                       verbose_invalid_scalar(env, r0, &range, "callback return", "R0");
+                       return -EINVAL;
+               }
+       } else {
+               /* return to the caller whatever r0 had in the callee */
+               caller->regs[BPF_REG_0] = *r0;
+       }
 
        /* Transfer references to the caller */
        err = transfer_reference_state(caller, callee);
@@ -5436,7 +5608,9 @@ record_func_map(struct bpf_verifier_env *env, struct bpf_call_arg_meta *meta,
            func_id != BPF_FUNC_map_delete_elem &&
            func_id != BPF_FUNC_map_push_elem &&
            func_id != BPF_FUNC_map_pop_elem &&
-           func_id != BPF_FUNC_map_peek_elem)
+           func_id != BPF_FUNC_map_peek_elem &&
+           func_id != BPF_FUNC_for_each_map_elem &&
+           func_id != BPF_FUNC_redirect_map)
                return 0;
 
        if (map == NULL) {
@@ -5517,15 +5691,18 @@ static int check_reference_leak(struct bpf_verifier_env *env)
        return state->acquired_refs ? -EINVAL : 0;
 }
 
-static int check_helper_call(struct bpf_verifier_env *env, int func_id, int insn_idx)
+static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
+                            int *insn_idx_p)
 {
        const struct bpf_func_proto *fn = NULL;
        struct bpf_reg_state *regs;
        struct bpf_call_arg_meta meta;
+       int insn_idx = *insn_idx_p;
        bool changes_data;
-       int i, err;
+       int i, err, func_id;
 
        /* find function prototype */
+       func_id = insn->imm;
        if (func_id < 0 || func_id >= __BPF_FUNC_MAX_ID) {
                verbose(env, "invalid func %s#%d\n", func_id_name(func_id),
                        func_id);
@@ -5571,7 +5748,7 @@ static int check_helper_call(struct bpf_verifier_env *env, int func_id, int insn
 
        meta.func_id = func_id;
        /* check args */
-       for (i = 0; i < 5; i++) {
+       for (i = 0; i < MAX_BPF_FUNC_REG_ARGS; i++) {
                err = check_func_arg(env, i, &meta, fn);
                if (err)
                        return err;
@@ -5621,6 +5798,13 @@ static int check_helper_call(struct bpf_verifier_env *env, int func_id, int insn
                return -EINVAL;
        }
 
+       if (func_id == BPF_FUNC_for_each_map_elem) {
+               err = __check_func_call(env, insn, insn_idx_p, meta.subprogno,
+                                       set_map_elem_callback_state);
+               if (err < 0)
+                       return -EINVAL;
+       }
+
        /* reset caller saved regs */
        for (i = 0; i < CALLER_SAVED_REGS; i++) {
                mark_reg_not_init(env, regs, caller_saved[i]);
@@ -5874,6 +6058,19 @@ static int retrieve_ptr_limit(const struct bpf_reg_state *ptr_reg,
                else
                        *ptr_limit = -off;
                return 0;
+       case PTR_TO_MAP_KEY:
+               /* Currently, this code is not exercised as the only use
+                * is bpf_for_each_map_elem() helper which requires
+                * bpf_capble. The code has been tested manually for
+                * future use.
+                */
+               if (mask_to_left) {
+                       *ptr_limit = ptr_reg->umax_value + ptr_reg->off;
+               } else {
+                       off = ptr_reg->smin_value + ptr_reg->off;
+                       *ptr_limit = ptr_reg->map_ptr->key_size - off;
+               }
+               return 0;
        case PTR_TO_MAP_VALUE:
                if (mask_to_left) {
                        *ptr_limit = ptr_reg->umax_value + ptr_reg->off;
@@ -5904,7 +6101,7 @@ static int update_alu_sanitation_state(struct bpf_insn_aux_data *aux,
             aux->alu_limit != alu_limit))
                return -EACCES;
 
-       /* Corresponding fixup done in fixup_bpf_calls(). */
+       /* Corresponding fixup done in do_misc_fixups(). */
        aux->alu_state = alu_state;
        aux->alu_limit = alu_limit;
        return 0;
@@ -6075,6 +6272,7 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
                verbose(env, "R%d pointer arithmetic on %s prohibited\n",
                        dst, reg_type_str[ptr_reg->type]);
                return -EACCES;
+       case PTR_TO_MAP_KEY:
        case PTR_TO_MAP_VALUE:
                if (!env->allow_ptr_leaks && !known && (smin_val < 0) != (smax_val < 0)) {
                        verbose(env, "R%d has unknown scalar with mixed signed bounds, pointer arithmetic with it prohibited for !root\n",
@@ -8254,6 +8452,24 @@ static int check_ld_imm(struct bpf_verifier_env *env, struct bpf_insn *insn)
                return 0;
        }
 
+       if (insn->src_reg == BPF_PSEUDO_FUNC) {
+               struct bpf_prog_aux *aux = env->prog->aux;
+               u32 subprogno = insn[1].imm;
+
+               if (!aux->func_info) {
+                       verbose(env, "missing btf func_info\n");
+                       return -EINVAL;
+               }
+               if (aux->func_info_aux[subprogno].linkage != BTF_FUNC_STATIC) {
+                       verbose(env, "callback function not static\n");
+                       return -EINVAL;
+               }
+
+               dst_reg->type = PTR_TO_FUNC;
+               dst_reg->subprogno = subprogno;
+               return 0;
+       }
+
        map = env->used_maps[aux->map_index];
        mark_reg_known_zero(env, regs, insn->dst_reg);
        dst_reg->map_ptr = map;
@@ -8482,17 +8698,7 @@ static int check_return_code(struct bpf_verifier_env *env)
        }
 
        if (!tnum_in(range, reg->var_off)) {
-               char tn_buf[48];
-
-               verbose(env, "At program exit the register R0 ");
-               if (!tnum_is_unknown(reg->var_off)) {
-                       tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off);
-                       verbose(env, "has value %s", tn_buf);
-               } else {
-                       verbose(env, "has unknown scalar value");
-               }
-               tnum_strn(tn_buf, sizeof(tn_buf), range);
-               verbose(env, " should have been in %s\n", tn_buf);
+               verbose_invalid_scalar(env, reg, &range, "program exit", "R0");
                return -EINVAL;
        }
 
@@ -8619,6 +8825,27 @@ static int push_insn(int t, int w, int e, struct bpf_verifier_env *env,
        return DONE_EXPLORING;
 }
 
+static int visit_func_call_insn(int t, int insn_cnt,
+                               struct bpf_insn *insns,
+                               struct bpf_verifier_env *env,
+                               bool visit_callee)
+{
+       int ret;
+
+       ret = push_insn(t, t + 1, FALLTHROUGH, env, false);
+       if (ret)
+               return ret;
+
+       if (t + 1 < insn_cnt)
+               init_explored_state(env, t + 1);
+       if (visit_callee) {
+               init_explored_state(env, t);
+               ret = push_insn(t, t + insns[t].imm + 1, BRANCH,
+                               env, false);
+       }
+       return ret;
+}
+
 /* Visits the instruction at index t and returns one of the following:
  *  < 0 - an error occurred
  *  DONE_EXPLORING - the instruction was fully explored
@@ -8629,6 +8856,9 @@ static int visit_insn(int t, int insn_cnt, struct bpf_verifier_env *env)
        struct bpf_insn *insns = env->prog->insnsi;
        int ret;
 
+       if (bpf_pseudo_func(insns + t))
+               return visit_func_call_insn(t, insn_cnt, insns, env, true);
+
        /* All non-branch instructions have a single fall-through edge. */
        if (BPF_CLASS(insns[t].code) != BPF_JMP &&
            BPF_CLASS(insns[t].code) != BPF_JMP32)
@@ -8639,18 +8869,8 @@ static int visit_insn(int t, int insn_cnt, struct bpf_verifier_env *env)
                return DONE_EXPLORING;
 
        case BPF_CALL:
-               ret = push_insn(t, t + 1, FALLTHROUGH, env, false);
-               if (ret)
-                       return ret;
-
-               if (t + 1 < insn_cnt)
-                       init_explored_state(env, t + 1);
-               if (insns[t].src_reg == BPF_PSEUDO_CALL) {
-                       init_explored_state(env, t);
-                       ret = push_insn(t, t + insns[t].imm + 1, BRANCH,
-                                       env, false);
-               }
-               return ret;
+               return visit_func_call_insn(t, insn_cnt, insns, env,
+                                           insns[t].src_reg == BPF_PSEUDO_CALL);
 
        case BPF_JA:
                if (BPF_SRC(insns[t].code) != BPF_K)
@@ -9259,6 +9479,7 @@ static bool regsafe(struct bpf_reg_state *rold, struct bpf_reg_state *rcur,
                         */
                        return false;
                }
+       case PTR_TO_MAP_KEY:
        case PTR_TO_MAP_VALUE:
                /* If the new min/max/var_off satisfy the old ones and
                 * everything else matches, we are OK.
@@ -10105,10 +10326,9 @@ static int do_check(struct bpf_verifier_env *env)
                                if (insn->src_reg == BPF_PSEUDO_CALL)
                                        err = check_func_call(env, insn, &env->insn_idx);
                                else
-                                       err = check_helper_call(env, insn->imm, env->insn_idx);
+                                       err = check_helper_call(env, insn, &env->insn_idx);
                                if (err)
                                        return err;
-
                        } else if (opcode == BPF_JA) {
                                if (BPF_SRC(insn->code) != BPF_K ||
                                    insn->imm != 0 ||
@@ -10537,6 +10757,12 @@ static int resolve_pseudo_ldimm64(struct bpf_verifier_env *env)
                                goto next_insn;
                        }
 
+                       if (insn[0].src_reg == BPF_PSEUDO_FUNC) {
+                               aux = &env->insn_aux_data[i];
+                               aux->ptr_type = PTR_TO_FUNC;
+                               goto next_insn;
+                       }
+
                        /* In final convert_pseudo_ld_imm64() step, this is
                         * converted into regular 64-bit imm load insn.
                         */
@@ -10669,9 +10895,13 @@ static void convert_pseudo_ld_imm64(struct bpf_verifier_env *env)
        int insn_cnt = env->prog->len;
        int i;
 
-       for (i = 0; i < insn_cnt; i++, insn++)
-               if (insn->code == (BPF_LD | BPF_IMM | BPF_DW))
-                       insn->src_reg = 0;
+       for (i = 0; i < insn_cnt; i++, insn++) {
+               if (insn->code != (BPF_LD | BPF_IMM | BPF_DW))
+                       continue;
+               if (insn->src_reg == BPF_PSEUDO_FUNC)
+                       continue;
+               insn->src_reg = 0;
+       }
 }
 
 /* single env->prog->insni[off] instruction was replaced with the range
@@ -11310,6 +11540,12 @@ static int jit_subprogs(struct bpf_verifier_env *env)
                return 0;
 
        for (i = 0, insn = prog->insnsi; i < prog->len; i++, insn++) {
+               if (bpf_pseudo_func(insn)) {
+                       env->insn_aux_data[i].call_imm = insn->imm;
+                       /* subprog is encoded in insn[1].imm */
+                       continue;
+               }
+
                if (!bpf_pseudo_call(insn))
                        continue;
                /* Upon error here we cannot fall back to interpreter but
@@ -11439,6 +11675,12 @@ static int jit_subprogs(struct bpf_verifier_env *env)
        for (i = 0; i < env->subprog_cnt; i++) {
                insn = func[i]->insnsi;
                for (j = 0; j < func[i]->len; j++, insn++) {
+                       if (bpf_pseudo_func(insn)) {
+                               subprog = insn[1].imm;
+                               insn[0].imm = (u32)(long)func[subprog]->bpf_func;
+                               insn[1].imm = ((u64)(long)func[subprog]->bpf_func) >> 32;
+                               continue;
+                       }
                        if (!bpf_pseudo_call(insn))
                                continue;
                        subprog = insn->off;
@@ -11484,6 +11726,11 @@ static int jit_subprogs(struct bpf_verifier_env *env)
         * later look the same as if they were interpreted only.
         */
        for (i = 0, insn = prog->insnsi; i < prog->len; i++, insn++) {
+               if (bpf_pseudo_func(insn)) {
+                       insn[0].imm = env->insn_aux_data[i].call_imm;
+                       insn[1].imm = find_subprog(env, i + insn[0].imm + 1);
+                       continue;
+               }
                if (!bpf_pseudo_call(insn))
                        continue;
                insn->off = env->insn_aux_data[i].call_imm;
@@ -11548,6 +11795,14 @@ static int fixup_call_args(struct bpf_verifier_env *env)
                return -EINVAL;
        }
        for (i = 0; i < prog->len; i++, insn++) {
+               if (bpf_pseudo_func(insn)) {
+                       /* When JIT fails the progs with callback calls
+                        * have to be rejected, since interpreter doesn't support them yet.
+                        */
+                       verbose(env, "callbacks are not allowed in non-JITed programs\n");
+                       return -EINVAL;
+               }
+
                if (!bpf_pseudo_call(insn))
                        continue;
                depth = get_callee_stack_depth(env, insn, i);
@@ -11560,12 +11815,10 @@ static int fixup_call_args(struct bpf_verifier_env *env)
        return err;
 }
 
-/* fixup insn->imm field of bpf_call instructions
- * and inline eligible helpers as explicit sequence of BPF instructions
- *
- * this function is called after eBPF program passed verification
+/* Do various post-verification rewrites in a single program pass.
+ * These rewrites simplify JIT and interpreter implementations.
  */
-static int fixup_bpf_calls(struct bpf_verifier_env *env)
+static int do_misc_fixups(struct bpf_verifier_env *env)
 {
        struct bpf_prog *prog = env->prog;
        bool expect_blinding = bpf_jit_blinding_enabled(prog);
@@ -11580,6 +11833,7 @@ static int fixup_bpf_calls(struct bpf_verifier_env *env)
        int i, ret, cnt, delta = 0;
 
        for (i = 0; i < insn_cnt; i++, insn++) {
+               /* Make divide-by-zero exceptions impossible. */
                if (insn->code == (BPF_ALU64 | BPF_MOD | BPF_X) ||
                    insn->code == (BPF_ALU64 | BPF_DIV | BPF_X) ||
                    insn->code == (BPF_ALU | BPF_MOD | BPF_X) ||
@@ -11620,6 +11874,7 @@ static int fixup_bpf_calls(struct bpf_verifier_env *env)
                        continue;
                }
 
+               /* Implement LD_ABS and LD_IND with a rewrite, if supported by the program type. */
                if (BPF_CLASS(insn->code) == BPF_LD &&
                    (BPF_MODE(insn->code) == BPF_ABS ||
                     BPF_MODE(insn->code) == BPF_IND)) {
@@ -11639,6 +11894,7 @@ static int fixup_bpf_calls(struct bpf_verifier_env *env)
                        continue;
                }
 
+               /* Rewrite pointer arithmetic to mitigate speculation attacks. */
                if (insn->code == (BPF_ALU64 | BPF_ADD | BPF_X) ||
                    insn->code == (BPF_ALU64 | BPF_SUB | BPF_X)) {
                        const u8 code_add = BPF_ALU64 | BPF_ADD | BPF_X;
@@ -11787,7 +12043,8 @@ static int fixup_bpf_calls(struct bpf_verifier_env *env)
                     insn->imm == BPF_FUNC_map_delete_elem ||
                     insn->imm == BPF_FUNC_map_push_elem   ||
                     insn->imm == BPF_FUNC_map_pop_elem    ||
-                    insn->imm == BPF_FUNC_map_peek_elem)) {
+                    insn->imm == BPF_FUNC_map_peek_elem   ||
+                    insn->imm == BPF_FUNC_redirect_map)) {
                        aux = &env->insn_aux_data[i + delta];
                        if (bpf_map_ptr_poisoned(aux))
                                goto patch_call_imm;
@@ -11829,6 +12086,9 @@ static int fixup_bpf_calls(struct bpf_verifier_env *env)
                                     (int (*)(struct bpf_map *map, void *value))NULL));
                        BUILD_BUG_ON(!__same_type(ops->map_peek_elem,
                                     (int (*)(struct bpf_map *map, void *value))NULL));
+                       BUILD_BUG_ON(!__same_type(ops->map_redirect,
+                                    (int (*)(struct bpf_map *map, u32 ifindex, u64 flags))NULL));
+
 patch_map_ops_generic:
                        switch (insn->imm) {
                        case BPF_FUNC_map_lookup_elem:
@@ -11855,11 +12115,16 @@ patch_map_ops_generic:
                                insn->imm = BPF_CAST_CALL(ops->map_peek_elem) -
                                            __bpf_call_base;
                                continue;
+                       case BPF_FUNC_redirect_map:
+                               insn->imm = BPF_CAST_CALL(ops->map_redirect) -
+                                           __bpf_call_base;
+                               continue;
                        }
 
                        goto patch_call_imm;
                }
 
+               /* Implement bpf_jiffies64 inline. */
                if (prog->jit_requested && BITS_PER_LONG == 64 &&
                    insn->imm == BPF_FUNC_jiffies64) {
                        struct bpf_insn ld_jiffies_addr[2] = {
@@ -12670,7 +12935,7 @@ skip_full_check:
                ret = convert_ctx_accesses(env);
 
        if (ret == 0)
-               ret = fixup_bpf_calls(env);
+               ret = do_misc_fixups(env);
 
        /* do 32-bit optimization after insn patching has done so those patched
         * insns could be handled correctly.