diff options
Diffstat (limited to 'kernel/bpf/verifier.c')
| -rw-r--r-- | kernel/bpf/verifier.c | 66 |
1 files changed, 26 insertions, 40 deletions
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 2cbfba78d3db..2e7f7ab739e4 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -239,6 +239,15 @@ static const char * const reg_type_str[] = { [CONST_IMM] = "imm", }; +static const struct { + int map_type; + int func_id; +} func_limit[] = { + {BPF_MAP_TYPE_PROG_ARRAY, BPF_FUNC_tail_call}, + {BPF_MAP_TYPE_PERF_EVENT_ARRAY, BPF_FUNC_perf_event_read}, + {BPF_MAP_TYPE_PERF_EVENT_ARRAY, BPF_FUNC_perf_event_output}, +}; + static void print_verifier_state(struct verifier_env *env) { enum bpf_reg_type t; @@ -889,44 +898,24 @@ static int check_func_arg(struct verifier_env *env, u32 regno, static int check_map_func_compatibility(struct bpf_map *map, int func_id) { + bool bool_map, bool_func; + int i; + if (!map) return 0; - /* We need a two way check, first is from map perspective ... */ - switch (map->map_type) { - case BPF_MAP_TYPE_PROG_ARRAY: - if (func_id != BPF_FUNC_tail_call) - goto error; - break; - case BPF_MAP_TYPE_PERF_EVENT_ARRAY: - if (func_id != BPF_FUNC_perf_event_read && - func_id != BPF_FUNC_perf_event_output) - goto error; - break; - default: - break; - } - - /* ... and second from the function itself. */ - switch (func_id) { - case BPF_FUNC_tail_call: - if (map->map_type != BPF_MAP_TYPE_PROG_ARRAY) - goto error; - break; - case BPF_FUNC_perf_event_read: - case BPF_FUNC_perf_event_output: - if (map->map_type != BPF_MAP_TYPE_PERF_EVENT_ARRAY) - goto error; - break; - default: - break; + for (i = 0; i < ARRAY_SIZE(func_limit); i++) { + bool_map = (map->map_type == func_limit[i].map_type); + bool_func = (func_id == func_limit[i].func_id); + /* only when map & func pair match it can continue. + * don't allow any other map type to be passed into + * the special func; + */ + if (bool_func && bool_map != bool_func) + return -EINVAL; } return 0; -error: - verbose("cannot pass map_type %d into func %d\n", - map->map_type, func_id); - return -EINVAL; } static int check_call(struct verifier_env *env, int func_id) @@ -1359,7 +1348,6 @@ static int check_ld_abs(struct verifier_env *env, struct bpf_insn *insn) } if (insn->dst_reg != BPF_REG_0 || insn->off != 0 || - BPF_SIZE(insn->code) == BPF_DW || (mode == BPF_ABS && insn->src_reg != BPF_REG_0)) { verbose("BPF_LD_ABS uses reserved fields\n"); return -EINVAL; @@ -2015,6 +2003,7 @@ static int replace_map_fd_with_map_ptr(struct verifier_env *env) if (IS_ERR(map)) { verbose("fd %d is not pointing to valid bpf_map\n", insn->imm); + fdput(f); return PTR_ERR(map); } @@ -2034,18 +2023,15 @@ static int replace_map_fd_with_map_ptr(struct verifier_env *env) return -E2BIG; } + /* remember this map */ + env->used_maps[env->used_map_cnt++] = map; + /* hold the map. If the program is rejected by verifier, * the map will be released by release_maps() or it * will be used by the valid program until it's unloaded * and all maps are released in free_bpf_prog_info() */ - map = bpf_map_inc(map, false); - if (IS_ERR(map)) { - fdput(f); - return PTR_ERR(map); - } - env->used_maps[env->used_map_cnt++] = map; - + bpf_map_inc(map, false); fdput(f); next_insn: insn++; |
