diff options
-rw-r--r-- | include/linux/bpf.h | 3 | ||||
-rw-r--r-- | kernel/bpf/inode.c | 7 | ||||
-rw-r--r-- | kernel/bpf/syscall.c | 24 | ||||
-rw-r--r-- | kernel/bpf/verifier.c | 11 |
4 files changed, 33 insertions, 12 deletions
diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 21ee41b92e8a..f1d5c5acc8dd 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h | |||
@@ -171,12 +171,13 @@ void bpf_register_prog_type(struct bpf_prog_type_list *tl); | |||
171 | void bpf_register_map_type(struct bpf_map_type_list *tl); | 171 | void bpf_register_map_type(struct bpf_map_type_list *tl); |
172 | 172 | ||
173 | struct bpf_prog *bpf_prog_get(u32 ufd); | 173 | struct bpf_prog *bpf_prog_get(u32 ufd); |
174 | struct bpf_prog *bpf_prog_inc(struct bpf_prog *prog); | ||
174 | void bpf_prog_put(struct bpf_prog *prog); | 175 | void bpf_prog_put(struct bpf_prog *prog); |
175 | void bpf_prog_put_rcu(struct bpf_prog *prog); | 176 | void bpf_prog_put_rcu(struct bpf_prog *prog); |
176 | 177 | ||
177 | struct bpf_map *bpf_map_get_with_uref(u32 ufd); | 178 | struct bpf_map *bpf_map_get_with_uref(u32 ufd); |
178 | struct bpf_map *__bpf_map_get(struct fd f); | 179 | struct bpf_map *__bpf_map_get(struct fd f); |
179 | void bpf_map_inc(struct bpf_map *map, bool uref); | 180 | struct bpf_map *bpf_map_inc(struct bpf_map *map, bool uref); |
180 | void bpf_map_put_with_uref(struct bpf_map *map); | 181 | void bpf_map_put_with_uref(struct bpf_map *map); |
181 | void bpf_map_put(struct bpf_map *map); | 182 | void bpf_map_put(struct bpf_map *map); |
182 | int bpf_map_precharge_memlock(u32 pages); | 183 | int bpf_map_precharge_memlock(u32 pages); |
diff --git a/kernel/bpf/inode.c b/kernel/bpf/inode.c index f2ece3c174a5..8f94ca1860cf 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) | |||
31 | { | 31 | { |
32 | switch (type) { | 32 | switch (type) { |
33 | case BPF_TYPE_PROG: | 33 | case BPF_TYPE_PROG: |
34 | atomic_inc(&((struct bpf_prog *)raw)->aux->refcnt); | 34 | raw = bpf_prog_inc(raw); |
35 | break; | 35 | break; |
36 | case BPF_TYPE_MAP: | 36 | case BPF_TYPE_MAP: |
37 | bpf_map_inc(raw, true); | 37 | raw = bpf_map_inc(raw, true); |
38 | break; | 38 | break; |
39 | default: | 39 | default: |
40 | WARN_ON_ONCE(1); | 40 | WARN_ON_ONCE(1); |
@@ -297,7 +297,8 @@ static void *bpf_obj_do_get(const struct filename *pathname, | |||
297 | goto out; | 297 | goto out; |
298 | 298 | ||
299 | raw = bpf_any_get(inode->i_private, *type); | 299 | raw = bpf_any_get(inode->i_private, *type); |
300 | touch_atime(&path); | 300 | if (!IS_ERR(raw)) |
301 | touch_atime(&path); | ||
301 | 302 | ||
302 | path_put(&path); | 303 | path_put(&path); |
303 | return raw; | 304 | return raw; |
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index adc5e4bd74f8..cf5e9f7ad13a 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c | |||
@@ -218,11 +218,18 @@ struct bpf_map *__bpf_map_get(struct fd f) | |||
218 | return f.file->private_data; | 218 | return f.file->private_data; |
219 | } | 219 | } |
220 | 220 | ||
221 | void bpf_map_inc(struct bpf_map *map, bool uref) | 221 | /* prog's and map's refcnt limit */ |
222 | #define BPF_MAX_REFCNT 32768 | ||
223 | |||
224 | struct bpf_map *bpf_map_inc(struct bpf_map *map, bool uref) | ||
222 | { | 225 | { |
223 | atomic_inc(&map->refcnt); | 226 | if (atomic_inc_return(&map->refcnt) > BPF_MAX_REFCNT) { |
227 | atomic_dec(&map->refcnt); | ||
228 | return ERR_PTR(-EBUSY); | ||
229 | } | ||
224 | if (uref) | 230 | if (uref) |
225 | atomic_inc(&map->usercnt); | 231 | atomic_inc(&map->usercnt); |
232 | return map; | ||
226 | } | 233 | } |
227 | 234 | ||
228 | struct bpf_map *bpf_map_get_with_uref(u32 ufd) | 235 | struct bpf_map *bpf_map_get_with_uref(u32 ufd) |
@@ -234,7 +241,7 @@ struct bpf_map *bpf_map_get_with_uref(u32 ufd) | |||
234 | if (IS_ERR(map)) | 241 | if (IS_ERR(map)) |
235 | return map; | 242 | return map; |
236 | 243 | ||
237 | bpf_map_inc(map, true); | 244 | map = bpf_map_inc(map, true); |
238 | fdput(f); | 245 | fdput(f); |
239 | 246 | ||
240 | return map; | 247 | return map; |
@@ -658,6 +665,15 @@ static struct bpf_prog *__bpf_prog_get(struct fd f) | |||
658 | return f.file->private_data; | 665 | return f.file->private_data; |
659 | } | 666 | } |
660 | 667 | ||
668 | struct bpf_prog *bpf_prog_inc(struct bpf_prog *prog) | ||
669 | { | ||
670 | if (atomic_inc_return(&prog->aux->refcnt) > BPF_MAX_REFCNT) { | ||
671 | atomic_dec(&prog->aux->refcnt); | ||
672 | return ERR_PTR(-EBUSY); | ||
673 | } | ||
674 | return prog; | ||
675 | } | ||
676 | |||
661 | /* called by sockets/tracing/seccomp before attaching program to an event | 677 | /* called by sockets/tracing/seccomp before attaching program to an event |
662 | * pairs with bpf_prog_put() | 678 | * pairs with bpf_prog_put() |
663 | */ | 679 | */ |
@@ -670,7 +686,7 @@ struct bpf_prog *bpf_prog_get(u32 ufd) | |||
670 | if (IS_ERR(prog)) | 686 | if (IS_ERR(prog)) |
671 | return prog; | 687 | return prog; |
672 | 688 | ||
673 | atomic_inc(&prog->aux->refcnt); | 689 | prog = bpf_prog_inc(prog); |
674 | fdput(f); | 690 | fdput(f); |
675 | 691 | ||
676 | return prog; | 692 | return prog; |
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index db2574e7b8b0..89bcaa0966da 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c | |||
@@ -2049,15 +2049,18 @@ static int replace_map_fd_with_map_ptr(struct verifier_env *env) | |||
2049 | return -E2BIG; | 2049 | return -E2BIG; |
2050 | } | 2050 | } |
2051 | 2051 | ||
2052 | /* remember this map */ | ||
2053 | env->used_maps[env->used_map_cnt++] = map; | ||
2054 | |||
2055 | /* hold the map. If the program is rejected by verifier, | 2052 | /* hold the map. If the program is rejected by verifier, |
2056 | * the map will be released by release_maps() or it | 2053 | * the map will be released by release_maps() or it |
2057 | * will be used by the valid program until it's unloaded | 2054 | * will be used by the valid program until it's unloaded |
2058 | * and all maps are released in free_bpf_prog_info() | 2055 | * and all maps are released in free_bpf_prog_info() |
2059 | */ | 2056 | */ |
2060 | bpf_map_inc(map, false); | 2057 | map = bpf_map_inc(map, false); |
2058 | if (IS_ERR(map)) { | ||
2059 | fdput(f); | ||
2060 | return PTR_ERR(map); | ||
2061 | } | ||
2062 | env->used_maps[env->used_map_cnt++] = map; | ||
2063 | |||
2061 | fdput(f); | 2064 | fdput(f); |
2062 | next_insn: | 2065 | next_insn: |
2063 | insn++; | 2066 | insn++; |