diff options
Diffstat (limited to 'kernel/bpf')
| -rw-r--r-- | kernel/bpf/inode.c | 7 | ||||
| -rw-r--r-- | kernel/bpf/syscall.c | 24 | ||||
| -rw-r--r-- | kernel/bpf/verifier.c | 66 |
3 files changed, 33 insertions, 64 deletions
diff --git a/kernel/bpf/inode.c b/kernel/bpf/inode.c index d1a7646f79c5..5a8a797d50b7 100644 --- a/kernel/bpf/inode.c +++ b/kernel/bpf/inode.c @@ -31,10 +31,10 @@ static void *bpf_any_get(void *raw, enum bpf_type type) { switch (type) { case BPF_TYPE_PROG: - raw = bpf_prog_inc(raw); + atomic_inc(&((struct bpf_prog *)raw)->aux->refcnt); break; case BPF_TYPE_MAP: - raw = bpf_map_inc(raw, true); + bpf_map_inc(raw, true); break; default: WARN_ON_ONCE(1); @@ -277,8 +277,7 @@ static void *bpf_obj_do_get(const struct filename *pathname, goto out; raw = bpf_any_get(inode->i_private, *type); - if (!IS_ERR(raw)) - touch_atime(&path); + touch_atime(&path); path_put(&path); return raw; diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 4e32cc94edd9..3b39550d8485 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -181,18 +181,11 @@ struct bpf_map *__bpf_map_get(struct fd f) return f.file->private_data; } -/* prog's and map's refcnt limit */ -#define BPF_MAX_REFCNT 32768 - -struct bpf_map *bpf_map_inc(struct bpf_map *map, bool uref) +void bpf_map_inc(struct bpf_map *map, bool uref) { - if (atomic_inc_return(&map->refcnt) > BPF_MAX_REFCNT) { - atomic_dec(&map->refcnt); - return ERR_PTR(-EBUSY); - } + atomic_inc(&map->refcnt); if (uref) atomic_inc(&map->usercnt); - return map; } struct bpf_map *bpf_map_get_with_uref(u32 ufd) @@ -204,7 +197,7 @@ struct bpf_map *bpf_map_get_with_uref(u32 ufd) if (IS_ERR(map)) return map; - map = bpf_map_inc(map, true); + bpf_map_inc(map, true); fdput(f); return map; @@ -587,15 +580,6 @@ static struct bpf_prog *__bpf_prog_get(struct fd f) return f.file->private_data; } -struct bpf_prog *bpf_prog_inc(struct bpf_prog *prog) -{ - if (atomic_inc_return(&prog->aux->refcnt) > BPF_MAX_REFCNT) { - atomic_dec(&prog->aux->refcnt); - return ERR_PTR(-EBUSY); - } - return prog; -} - /* called by sockets/tracing/seccomp before attaching program to an event * pairs with bpf_prog_put() */ @@ -608,7 +592,7 @@ struct bpf_prog *bpf_prog_get(u32 ufd) if (IS_ERR(prog)) return prog; - prog = bpf_prog_inc(prog); + atomic_inc(&prog->aux->refcnt); fdput(f); return prog; 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++; |
