diff options
| author | David S. Miller <davem@davemloft.net> | 2016-05-04 00:52:29 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2016-05-04 00:52:29 -0400 |
| commit | cba653210056cf47cc1969f831f05ddfb99ee2bd (patch) | |
| tree | 92d93a3eee5b12d77af3696b9da8026e71df5752 /kernel/bpf | |
| parent | 26879da58711aa604a1b866cbeedd7e0f78f90ad (diff) | |
| parent | 7391daf2ffc780679d6ab3fad1db2619e5dd2c2a (diff) | |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
Conflicts:
net/ipv4/ip_gre.c
Minor conflicts between tunnel bug fixes in net and
ipv6 tunnel cleanups in net-next.
Signed-off-by: David S. Miller <davem@davemloft.net>
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 | 76 |
3 files changed, 71 insertions, 36 deletions
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 56f18068b52b..63554b6d4e25 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c | |||
| @@ -249,16 +249,6 @@ static const char * const reg_type_str[] = { | |||
| 249 | [CONST_IMM] = "imm", | 249 | [CONST_IMM] = "imm", |
| 250 | }; | 250 | }; |
| 251 | 251 | ||
| 252 | static const struct { | ||
| 253 | int map_type; | ||
| 254 | int func_id; | ||
| 255 | } func_limit[] = { | ||
| 256 | {BPF_MAP_TYPE_PROG_ARRAY, BPF_FUNC_tail_call}, | ||
| 257 | {BPF_MAP_TYPE_PERF_EVENT_ARRAY, BPF_FUNC_perf_event_read}, | ||
| 258 | {BPF_MAP_TYPE_PERF_EVENT_ARRAY, BPF_FUNC_perf_event_output}, | ||
| 259 | {BPF_MAP_TYPE_STACK_TRACE, BPF_FUNC_get_stackid}, | ||
| 260 | }; | ||
| 261 | |||
| 262 | static void print_verifier_state(struct verifier_env *env) | 252 | static void print_verifier_state(struct verifier_env *env) |
| 263 | { | 253 | { |
| 264 | enum bpf_reg_type t; | 254 | enum bpf_reg_type t; |
| @@ -943,27 +933,52 @@ static int check_func_arg(struct verifier_env *env, u32 regno, | |||
| 943 | 933 | ||
| 944 | static int check_map_func_compatibility(struct bpf_map *map, int func_id) | 934 | static int check_map_func_compatibility(struct bpf_map *map, int func_id) |
| 945 | { | 935 | { |
| 946 | bool bool_map, bool_func; | ||
| 947 | int i; | ||
| 948 | |||
| 949 | if (!map) | 936 | if (!map) |
| 950 | return 0; | 937 | return 0; |
| 951 | 938 | ||
| 952 | for (i = 0; i < ARRAY_SIZE(func_limit); i++) { | 939 | /* We need a two way check, first is from map perspective ... */ |
| 953 | bool_map = (map->map_type == func_limit[i].map_type); | 940 | switch (map->map_type) { |
| 954 | bool_func = (func_id == func_limit[i].func_id); | 941 | case BPF_MAP_TYPE_PROG_ARRAY: |
| 955 | /* only when map & func pair match it can continue. | 942 | if (func_id != BPF_FUNC_tail_call) |
| 956 | * don't allow any other map type to be passed into | 943 | goto error; |
| 957 | * the special func; | 944 | break; |
| 958 | */ | 945 | case BPF_MAP_TYPE_PERF_EVENT_ARRAY: |
| 959 | if (bool_func && bool_map != bool_func) { | 946 | if (func_id != BPF_FUNC_perf_event_read && |
| 960 | verbose("cannot pass map_type %d into func %d\n", | 947 | func_id != BPF_FUNC_perf_event_output) |
| 961 | map->map_type, func_id); | 948 | goto error; |
| 962 | return -EINVAL; | 949 | break; |
| 963 | } | 950 | case BPF_MAP_TYPE_STACK_TRACE: |
| 951 | if (func_id != BPF_FUNC_get_stackid) | ||
| 952 | goto error; | ||
| 953 | break; | ||
| 954 | default: | ||
| 955 | break; | ||
| 956 | } | ||
| 957 | |||
| 958 | /* ... and second from the function itself. */ | ||
| 959 | switch (func_id) { | ||
| 960 | case BPF_FUNC_tail_call: | ||
| 961 | if (map->map_type != BPF_MAP_TYPE_PROG_ARRAY) | ||
| 962 | goto error; | ||
| 963 | break; | ||
| 964 | case BPF_FUNC_perf_event_read: | ||
| 965 | case BPF_FUNC_perf_event_output: | ||
| 966 | if (map->map_type != BPF_MAP_TYPE_PERF_EVENT_ARRAY) | ||
| 967 | goto error; | ||
| 968 | break; | ||
| 969 | case BPF_FUNC_get_stackid: | ||
| 970 | if (map->map_type != BPF_MAP_TYPE_STACK_TRACE) | ||
| 971 | goto error; | ||
| 972 | break; | ||
| 973 | default: | ||
| 974 | break; | ||
| 964 | } | 975 | } |
| 965 | 976 | ||
| 966 | return 0; | 977 | return 0; |
| 978 | error: | ||
| 979 | verbose("cannot pass map_type %d into func %d\n", | ||
| 980 | map->map_type, func_id); | ||
| 981 | return -EINVAL; | ||
| 967 | } | 982 | } |
| 968 | 983 | ||
| 969 | static int check_raw_mode(const struct bpf_func_proto *fn) | 984 | static int check_raw_mode(const struct bpf_func_proto *fn) |
| @@ -2111,15 +2126,18 @@ static int replace_map_fd_with_map_ptr(struct verifier_env *env) | |||
| 2111 | return -E2BIG; | 2126 | return -E2BIG; |
| 2112 | } | 2127 | } |
| 2113 | 2128 | ||
| 2114 | /* remember this map */ | ||
| 2115 | env->used_maps[env->used_map_cnt++] = map; | ||
| 2116 | |||
| 2117 | /* hold the map. If the program is rejected by verifier, | 2129 | /* hold the map. If the program is rejected by verifier, |
| 2118 | * the map will be released by release_maps() or it | 2130 | * the map will be released by release_maps() or it |
| 2119 | * will be used by the valid program until it's unloaded | 2131 | * will be used by the valid program until it's unloaded |
| 2120 | * and all maps are released in free_bpf_prog_info() | 2132 | * and all maps are released in free_bpf_prog_info() |
| 2121 | */ | 2133 | */ |
| 2122 | bpf_map_inc(map, false); | 2134 | map = bpf_map_inc(map, false); |
| 2135 | if (IS_ERR(map)) { | ||
| 2136 | fdput(f); | ||
| 2137 | return PTR_ERR(map); | ||
| 2138 | } | ||
| 2139 | env->used_maps[env->used_map_cnt++] = map; | ||
| 2140 | |||
| 2123 | fdput(f); | 2141 | fdput(f); |
| 2124 | next_insn: | 2142 | next_insn: |
| 2125 | insn++; | 2143 | insn++; |
