summaryrefslogtreecommitdiff
path: root/kernel/bpf
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/bpf')
-rw-r--r--kernel/bpf/inode.c7
-rw-r--r--kernel/bpf/syscall.c24
-rw-r--r--kernel/bpf/verifier.c66
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++;