Merge https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next
[sfrench/cifs-2.6.git] / kernel / bpf / verifier.c
index 096fdac701654f7e23a9766ba47115debb0ef7b1..003f7ba195581de4ad90a77625adbdbc00673d2c 100644 (file)
@@ -427,6 +427,7 @@ static void verbose_invalid_scalar(struct bpf_verifier_env *env,
 
 static bool type_is_pkt_pointer(enum bpf_reg_type type)
 {
+       type = base_type(type);
        return type == PTR_TO_PACKET ||
               type == PTR_TO_PACKET_META;
 }
@@ -456,10 +457,9 @@ static bool reg_may_point_to_spin_lock(const struct bpf_reg_state *reg)
 
 static bool reg_type_may_be_refcounted_or_null(enum bpf_reg_type type)
 {
-       return base_type(type) == PTR_TO_SOCKET ||
-               base_type(type) == PTR_TO_TCP_SOCK ||
-               base_type(type) == PTR_TO_MEM ||
-               base_type(type) == PTR_TO_BTF_ID;
+       type = base_type(type);
+       return type == PTR_TO_SOCKET || type == PTR_TO_TCP_SOCK ||
+               type == PTR_TO_MEM || type == PTR_TO_BTF_ID;
 }
 
 static bool type_is_rdonly_mem(u32 type)
@@ -467,25 +467,11 @@ static bool type_is_rdonly_mem(u32 type)
        return type & MEM_RDONLY;
 }
 
-static bool arg_type_may_be_refcounted(enum bpf_arg_type type)
-{
-       return type == ARG_PTR_TO_SOCK_COMMON;
-}
-
 static bool type_may_be_null(u32 type)
 {
        return type & PTR_MAYBE_NULL;
 }
 
-static bool may_be_acquire_function(enum bpf_func_id func_id)
-{
-       return func_id == BPF_FUNC_sk_lookup_tcp ||
-               func_id == BPF_FUNC_sk_lookup_udp ||
-               func_id == BPF_FUNC_skc_lookup_tcp ||
-               func_id == BPF_FUNC_map_lookup_elem ||
-               func_id == BPF_FUNC_ringbuf_reserve;
-}
-
 static bool is_acquire_function(enum bpf_func_id func_id,
                                const struct bpf_map *map)
 {
@@ -518,6 +504,26 @@ static bool is_ptr_cast_function(enum bpf_func_id func_id)
                func_id == BPF_FUNC_skc_to_tcp_request_sock;
 }
 
+static bool is_dynptr_ref_function(enum bpf_func_id func_id)
+{
+       return func_id == BPF_FUNC_dynptr_data;
+}
+
+static bool helper_multiple_ref_obj_use(enum bpf_func_id func_id,
+                                       const struct bpf_map *map)
+{
+       int ref_obj_uses = 0;
+
+       if (is_ptr_cast_function(func_id))
+               ref_obj_uses++;
+       if (is_acquire_function(func_id, map))
+               ref_obj_uses++;
+       if (is_dynptr_ref_function(func_id))
+               ref_obj_uses++;
+
+       return ref_obj_uses > 1;
+}
+
 static bool is_cmpxchg_insn(const struct bpf_insn *insn)
 {
        return BPF_CLASS(insn->code) == BPF_STX &&
@@ -1086,6 +1092,7 @@ static int acquire_reference_state(struct bpf_verifier_env *env, int insn_idx)
        id = ++env->id_gen;
        state->refs[new_ofs].id = id;
        state->refs[new_ofs].insn_idx = insn_idx;
+       state->refs[new_ofs].callback_ref = state->in_callback_fn ? state->frameno : 0;
 
        return id;
 }
@@ -1098,6 +1105,9 @@ static int release_reference_state(struct bpf_func_state *state, int ptr_id)
        last_idx = state->acquired_refs - 1;
        for (i = 0; i < state->acquired_refs; i++) {
                if (state->refs[i].id == ptr_id) {
+                       /* Cannot release caller references in callbacks */
+                       if (state->in_callback_fn && state->refs[i].callback_ref != state->frameno)
+                               return -EINVAL;
                        if (last_idx && i != last_idx)
                                memcpy(&state->refs[i], &state->refs[last_idx],
                                       sizeof(*state->refs));
@@ -6066,6 +6076,9 @@ skip_type_check:
                        return -EACCES;
                }
                meta->mem_size = reg->var_off.value;
+               err = mark_chain_precision(env, regno);
+               if (err)
+                       return err;
                break;
        case ARG_PTR_TO_INT:
        case ARG_PTR_TO_LONG:
@@ -6453,33 +6466,6 @@ static bool check_arg_pair_ok(const struct bpf_func_proto *fn)
        return true;
 }
 
-static bool check_refcount_ok(const struct bpf_func_proto *fn, int func_id)
-{
-       int count = 0;
-
-       if (arg_type_may_be_refcounted(fn->arg1_type))
-               count++;
-       if (arg_type_may_be_refcounted(fn->arg2_type))
-               count++;
-       if (arg_type_may_be_refcounted(fn->arg3_type))
-               count++;
-       if (arg_type_may_be_refcounted(fn->arg4_type))
-               count++;
-       if (arg_type_may_be_refcounted(fn->arg5_type))
-               count++;
-
-       /* A reference acquiring function cannot acquire
-        * another refcounted ptr.
-        */
-       if (may_be_acquire_function(func_id) && count)
-               return false;
-
-       /* We only support one arg being unreferenced at the moment,
-        * which is sufficient for the helper functions we have right now.
-        */
-       return count <= 1;
-}
-
 static bool check_btf_id_ok(const struct bpf_func_proto *fn)
 {
        int i;
@@ -6498,13 +6484,11 @@ static bool check_btf_id_ok(const struct bpf_func_proto *fn)
        return true;
 }
 
-static int check_func_proto(const struct bpf_func_proto *fn, int func_id,
-                           struct bpf_call_arg_meta *meta)
+static int check_func_proto(const struct bpf_func_proto *fn, int func_id)
 {
        return check_raw_mode_ok(fn) &&
               check_arg_pair_ok(fn) &&
-              check_btf_id_ok(fn) &&
-              check_refcount_ok(fn, func_id) ? 0 : -EINVAL;
+              check_btf_id_ok(fn) ? 0 : -EINVAL;
 }
 
 /* Packet data might have moved, any old PTR_TO_PACKET[_META,_END]
@@ -6938,10 +6922,17 @@ static int prepare_func_exit(struct bpf_verifier_env *env, int *insn_idx)
                caller->regs[BPF_REG_0] = *r0;
        }
 
-       /* Transfer references to the caller */
-       err = copy_reference_state(caller, callee);
-       if (err)
-               return err;
+       /* callback_fn frame should have released its own additions to parent's
+        * reference state at this point, or check_reference_leak would
+        * complain, hence it must be the same as the caller. There is no need
+        * to copy it back.
+        */
+       if (!callee->in_callback_fn) {
+               /* Transfer references to the caller */
+               err = copy_reference_state(caller, callee);
+               if (err)
+                       return err;
+       }
 
        *insn_idx = callee->callsite + 1;
        if (env->log.level & BPF_LOG_LEVEL) {
@@ -7030,8 +7021,7 @@ record_func_key(struct bpf_verifier_env *env, struct bpf_call_arg_meta *meta,
        struct bpf_insn_aux_data *aux = &env->insn_aux_data[insn_idx];
        struct bpf_reg_state *regs = cur_regs(env), *reg;
        struct bpf_map *map = meta->map_ptr;
-       struct tnum range;
-       u64 val;
+       u64 val, max;
        int err;
 
        if (func_id != BPF_FUNC_tail_call)
@@ -7041,10 +7031,11 @@ record_func_key(struct bpf_verifier_env *env, struct bpf_call_arg_meta *meta,
                return -EINVAL;
        }
 
-       range = tnum_range(0, map->max_entries - 1);
        reg = &regs[BPF_REG_3];
+       val = reg->var_off.value;
+       max = map->max_entries;
 
-       if (!register_is_const(reg) || !tnum_in(range, reg->var_off)) {
+       if (!(register_is_const(reg) && val < max)) {
                bpf_map_key_store(aux, BPF_MAP_KEY_POISON);
                return 0;
        }
@@ -7052,8 +7043,6 @@ record_func_key(struct bpf_verifier_env *env, struct bpf_call_arg_meta *meta,
        err = mark_chain_precision(env, BPF_REG_3);
        if (err)
                return err;
-
-       val = reg->var_off.value;
        if (bpf_map_key_unseen(aux))
                bpf_map_key_store(aux, val);
        else if (!bpf_map_key_poisoned(aux) &&
@@ -7065,13 +7054,20 @@ record_func_key(struct bpf_verifier_env *env, struct bpf_call_arg_meta *meta,
 static int check_reference_leak(struct bpf_verifier_env *env)
 {
        struct bpf_func_state *state = cur_func(env);
+       bool refs_lingering = false;
        int i;
 
+       if (state->frameno && !state->in_callback_fn)
+               return 0;
+
        for (i = 0; i < state->acquired_refs; i++) {
+               if (state->in_callback_fn && state->refs[i].callback_ref != state->frameno)
+                       continue;
                verbose(env, "Unreleased reference id=%d alloc_insn=%d\n",
                        state->refs[i].id, state->refs[i].insn_idx);
+               refs_lingering = true;
        }
-       return state->acquired_refs ? -EINVAL : 0;
+       return refs_lingering ? -EINVAL : 0;
 }
 
 static int check_bpf_snprintf_call(struct bpf_verifier_env *env,
@@ -7218,7 +7214,7 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
        memset(&meta, 0, sizeof(meta));
        meta.pkt_access = fn->pkt_access;
 
-       err = check_func_proto(fn, func_id, &meta);
+       err = check_func_proto(fn, func_id);
        if (err) {
                verbose(env, "kernel subsystem misconfigured func %s#%d\n",
                        func_id_name(func_id), func_id);
@@ -7343,6 +7339,23 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
                        }
                }
                break;
+       case BPF_FUNC_dynptr_data:
+               for (i = 0; i < MAX_BPF_FUNC_REG_ARGS; i++) {
+                       if (arg_type_is_dynptr(fn->arg_type[i])) {
+                               if (meta.ref_obj_id) {
+                                       verbose(env, "verifier internal error: meta.ref_obj_id already set\n");
+                                       return -EFAULT;
+                               }
+                               /* Find the id of the dynptr we're tracking the reference of */
+                               meta.ref_obj_id = stack_slot_get_id(env, &regs[BPF_REG_1 + i]);
+                               break;
+                       }
+               }
+               if (i == MAX_BPF_FUNC_REG_ARGS) {
+                       verbose(env, "verifier internal error: no dynptr in bpf_dynptr_data()\n");
+                       return -EFAULT;
+               }
+               break;
        }
 
        if (err)
@@ -7359,13 +7372,17 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
 
        /* update return register (already marked as written above) */
        ret_type = fn->ret_type;
-       ret_flag = type_flag(fn->ret_type);
-       if (ret_type == RET_INTEGER) {
+       ret_flag = type_flag(ret_type);
+
+       switch (base_type(ret_type)) {
+       case RET_INTEGER:
                /* sets type to SCALAR_VALUE */
                mark_reg_unknown(env, regs, BPF_REG_0);
-       } else if (ret_type == RET_VOID) {
+               break;
+       case RET_VOID:
                regs[BPF_REG_0].type = NOT_INIT;
-       } else if (base_type(ret_type) == RET_PTR_TO_MAP_VALUE) {
+               break;
+       case RET_PTR_TO_MAP_VALUE:
                /* There is no offset yet applied, variable or fixed */
                mark_reg_known_zero(env, regs, BPF_REG_0);
                /* remember map_ptr, so that check_map_access()
@@ -7384,20 +7401,26 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
                    map_value_has_spin_lock(meta.map_ptr)) {
                        regs[BPF_REG_0].id = ++env->id_gen;
                }
-       } else if (base_type(ret_type) == RET_PTR_TO_SOCKET) {
+               break;
+       case RET_PTR_TO_SOCKET:
                mark_reg_known_zero(env, regs, BPF_REG_0);
                regs[BPF_REG_0].type = PTR_TO_SOCKET | ret_flag;
-       } else if (base_type(ret_type) == RET_PTR_TO_SOCK_COMMON) {
+               break;
+       case RET_PTR_TO_SOCK_COMMON:
                mark_reg_known_zero(env, regs, BPF_REG_0);
                regs[BPF_REG_0].type = PTR_TO_SOCK_COMMON | ret_flag;
-       } else if (base_type(ret_type) == RET_PTR_TO_TCP_SOCK) {
+               break;
+       case RET_PTR_TO_TCP_SOCK:
                mark_reg_known_zero(env, regs, BPF_REG_0);
                regs[BPF_REG_0].type = PTR_TO_TCP_SOCK | ret_flag;
-       } else if (base_type(ret_type) == RET_PTR_TO_ALLOC_MEM) {
+               break;
+       case RET_PTR_TO_ALLOC_MEM:
                mark_reg_known_zero(env, regs, BPF_REG_0);
                regs[BPF_REG_0].type = PTR_TO_MEM | ret_flag;
                regs[BPF_REG_0].mem_size = meta.mem_size;
-       } else if (base_type(ret_type) == RET_PTR_TO_MEM_OR_BTF_ID) {
+               break;
+       case RET_PTR_TO_MEM_OR_BTF_ID:
+       {
                const struct btf_type *t;
 
                mark_reg_known_zero(env, regs, BPF_REG_0);
@@ -7429,7 +7452,10 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
                        regs[BPF_REG_0].btf = meta.ret_btf;
                        regs[BPF_REG_0].btf_id = meta.ret_btf_id;
                }
-       } else if (base_type(ret_type) == RET_PTR_TO_BTF_ID) {
+               break;
+       }
+       case RET_PTR_TO_BTF_ID:
+       {
                struct btf *ret_btf;
                int ret_btf_id;
 
@@ -7450,7 +7476,9 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
                }
                regs[BPF_REG_0].btf = ret_btf;
                regs[BPF_REG_0].btf_id = ret_btf_id;
-       } else {
+               break;
+       }
+       default:
                verbose(env, "unknown return type %u of func %s#%d\n",
                        base_type(ret_type), func_id_name(func_id), func_id);
                return -EINVAL;
@@ -7459,7 +7487,13 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
        if (type_may_be_null(regs[BPF_REG_0].type))
                regs[BPF_REG_0].id = ++env->id_gen;
 
-       if (is_ptr_cast_function(func_id)) {
+       if (helper_multiple_ref_obj_use(func_id, meta.map_ptr)) {
+               verbose(env, "verifier internal error: func %s#%d sets ref_obj_id more than once\n",
+                       func_id_name(func_id), func_id);
+               return -EFAULT;
+       }
+
+       if (is_ptr_cast_function(func_id) || is_dynptr_ref_function(func_id)) {
                /* For release_reference() */
                regs[BPF_REG_0].ref_obj_id = meta.ref_obj_id;
        } else if (is_acquire_function(func_id, meta.map_ptr)) {
@@ -7471,21 +7505,6 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
                regs[BPF_REG_0].id = id;
                /* For release_reference() */
                regs[BPF_REG_0].ref_obj_id = id;
-       } else if (func_id == BPF_FUNC_dynptr_data) {
-               int dynptr_id = 0, i;
-
-               /* Find the id of the dynptr we're acquiring a reference to */
-               for (i = 0; i < MAX_BPF_FUNC_REG_ARGS; i++) {
-                       if (arg_type_is_dynptr(fn->arg_type[i])) {
-                               if (dynptr_id) {
-                                       verbose(env, "verifier internal error: multiple dynptr args in func\n");
-                                       return -EFAULT;
-                               }
-                               dynptr_id = stack_slot_get_id(env, &regs[BPF_REG_1 + i]);
-                       }
-               }
-               /* For release_reference() */
-               regs[BPF_REG_0].ref_obj_id = dynptr_id;
        }
 
        do_refine_retval_range(regs, fn->ret_type, func_id, &meta);
@@ -7584,6 +7603,11 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
                        func_name);
                return -EACCES;
        }
+       if (*kfunc_flags & KF_DESTRUCTIVE && !capable(CAP_SYS_BOOT)) {
+               verbose(env, "destructive kfunc calls require CAP_SYS_BOOT capabilities\n");
+               return -EACCES;
+       }
+
        acq = *kfunc_flags & KF_ACQUIRE;
 
        /* Check the arguments */
@@ -12332,6 +12356,16 @@ static int do_check(struct bpf_verifier_env *env)
                                        return -EINVAL;
                                }
 
+                               /* We must do check_reference_leak here before
+                                * prepare_func_exit to handle the case when
+                                * state->curframe > 0, it may be a callback
+                                * function, for which reference_state must
+                                * match caller reference state when it exits.
+                                */
+                               err = check_reference_leak(env);
+                               if (err)
+                                       return err;
+
                                if (state->curframe) {
                                        /* exit from nested function */
                                        err = prepare_func_exit(env, &env->insn_idx);
@@ -12341,10 +12375,6 @@ static int do_check(struct bpf_verifier_env *env)
                                        continue;
                                }
 
-                               err = check_reference_leak(env);
-                               if (err)
-                                       return err;
-
                                err = check_return_code(env);
                                if (err)
                                        return err;
@@ -12557,14 +12587,6 @@ err_put:
        return err;
 }
 
-static int check_map_prealloc(struct bpf_map *map)
-{
-       return (map->map_type != BPF_MAP_TYPE_HASH &&
-               map->map_type != BPF_MAP_TYPE_PERCPU_HASH &&
-               map->map_type != BPF_MAP_TYPE_HASH_OF_MAPS) ||
-               !(map->map_flags & BPF_F_NO_PREALLOC);
-}
-
 static bool is_tracing_prog_type(enum bpf_prog_type type)
 {
        switch (type) {
@@ -12579,50 +12601,12 @@ static bool is_tracing_prog_type(enum bpf_prog_type type)
        }
 }
 
-static bool is_preallocated_map(struct bpf_map *map)
-{
-       if (!check_map_prealloc(map))
-               return false;
-       if (map->inner_map_meta && !check_map_prealloc(map->inner_map_meta))
-               return false;
-       return true;
-}
-
 static int check_map_prog_compatibility(struct bpf_verifier_env *env,
                                        struct bpf_map *map,
                                        struct bpf_prog *prog)
 
 {
        enum bpf_prog_type prog_type = resolve_prog_type(prog);
-       /*
-        * Validate that trace type programs use preallocated hash maps.
-        *
-        * For programs attached to PERF events this is mandatory as the
-        * perf NMI can hit any arbitrary code sequence.
-        *
-        * All other trace types using preallocated hash maps are unsafe as
-        * well because tracepoint or kprobes can be inside locked regions
-        * of the memory allocator or at a place where a recursion into the
-        * memory allocator would see inconsistent state.
-        *
-        * On RT enabled kernels run-time allocation of all trace type
-        * programs is strictly prohibited due to lock type constraints. On
-        * !RT kernels it is allowed for backwards compatibility reasons for
-        * now, but warnings are emitted so developers are made aware of
-        * the unsafety and can fix their programs before this is enforced.
-        */
-       if (is_tracing_prog_type(prog_type) && !is_preallocated_map(map)) {
-               if (prog_type == BPF_PROG_TYPE_PERF_EVENT) {
-                       verbose(env, "perf_event programs can only use preallocated hash map\n");
-                       return -EINVAL;
-               }
-               if (IS_ENABLED(CONFIG_PREEMPT_RT)) {
-                       verbose(env, "trace type programs can only use preallocated hash map\n");
-                       return -EINVAL;
-               }
-               WARN_ONCE(1, "trace type BPF program uses run-time allocation\n");
-               verbose(env, "trace type programs with run-time allocated hash maps are unsafe. Switch to preallocated hash maps.\n");
-       }
 
        if (map_value_has_spin_lock(map)) {
                if (prog_type == BPF_PROG_TYPE_SOCKET_FILTER) {
@@ -12669,12 +12653,6 @@ static int check_map_prog_compatibility(struct bpf_verifier_env *env,
                case BPF_MAP_TYPE_LRU_PERCPU_HASH:
                case BPF_MAP_TYPE_ARRAY_OF_MAPS:
                case BPF_MAP_TYPE_HASH_OF_MAPS:
-                       if (!is_preallocated_map(map)) {
-                               verbose(env,
-                                       "Sleepable programs can only use preallocated maps\n");
-                               return -EINVAL;
-                       }
-                       break;
                case BPF_MAP_TYPE_RINGBUF:
                case BPF_MAP_TYPE_INODE_STORAGE:
                case BPF_MAP_TYPE_SK_STORAGE: