Merge https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next
[sfrench/cifs-2.6.git] / kernel / bpf / verifier.c
index 8d07493a477c794c6252a5fa5bec6aa483b4d3ee..003f7ba195581de4ad90a77625adbdbc00673d2c 100644 (file)
@@ -1092,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;
 }
@@ -1104,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));
@@ -6918,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) {
@@ -7043,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,
@@ -12338,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);
@@ -12347,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;
@@ -12563,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) {
@@ -12585,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) {
@@ -12675,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: