diff options
author | Alexei Starovoitov <ast@fb.com> | 2016-04-27 21:56:21 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-04-28 17:29:45 -0400 |
commit | 6aff67c85c9e5a4bc99e5211c1bac547936626ca (patch) | |
tree | 3be9fa8e180334d6f8e0c5edb5e47f8113f4b2f4 | |
parent | 92117d8443bc5afacc8d5ba82e541946310f106e (diff) |
bpf: fix check_map_func_compatibility logic
The commit 35578d798400 ("bpf: Implement function bpf_perf_event_read() that get the selected hardware PMU conuter")
introduced clever way to check bpf_helper<->map_type compatibility.
Later on commit a43eec304259 ("bpf: introduce bpf_perf_event_output() helper") adjusted
the logic and inadvertently broke it.
Get rid of the clever bool compare and go back to two-way check
from map and from helper perspective.
Fixes: a43eec304259 ("bpf: introduce bpf_perf_event_output() helper")
Reported-by: Jann Horn <jannh@google.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | kernel/bpf/verifier.c | 65 |
1 files changed, 40 insertions, 25 deletions
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 89bcaa0966da..c5c17a62f509 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c | |||
@@ -239,16 +239,6 @@ static const char * const reg_type_str[] = { | |||
239 | [CONST_IMM] = "imm", | 239 | [CONST_IMM] = "imm", |
240 | }; | 240 | }; |
241 | 241 | ||
242 | static const struct { | ||
243 | int map_type; | ||
244 | int func_id; | ||
245 | } func_limit[] = { | ||
246 | {BPF_MAP_TYPE_PROG_ARRAY, BPF_FUNC_tail_call}, | ||
247 | {BPF_MAP_TYPE_PERF_EVENT_ARRAY, BPF_FUNC_perf_event_read}, | ||
248 | {BPF_MAP_TYPE_PERF_EVENT_ARRAY, BPF_FUNC_perf_event_output}, | ||
249 | {BPF_MAP_TYPE_STACK_TRACE, BPF_FUNC_get_stackid}, | ||
250 | }; | ||
251 | |||
252 | static void print_verifier_state(struct verifier_env *env) | 242 | static void print_verifier_state(struct verifier_env *env) |
253 | { | 243 | { |
254 | enum bpf_reg_type t; | 244 | enum bpf_reg_type t; |
@@ -921,27 +911,52 @@ static int check_func_arg(struct verifier_env *env, u32 regno, | |||
921 | 911 | ||
922 | static int check_map_func_compatibility(struct bpf_map *map, int func_id) | 912 | static int check_map_func_compatibility(struct bpf_map *map, int func_id) |
923 | { | 913 | { |
924 | bool bool_map, bool_func; | ||
925 | int i; | ||
926 | |||
927 | if (!map) | 914 | if (!map) |
928 | return 0; | 915 | return 0; |
929 | 916 | ||
930 | for (i = 0; i < ARRAY_SIZE(func_limit); i++) { | 917 | /* We need a two way check, first is from map perspective ... */ |
931 | bool_map = (map->map_type == func_limit[i].map_type); | 918 | switch (map->map_type) { |
932 | bool_func = (func_id == func_limit[i].func_id); | 919 | case BPF_MAP_TYPE_PROG_ARRAY: |
933 | /* only when map & func pair match it can continue. | 920 | if (func_id != BPF_FUNC_tail_call) |
934 | * don't allow any other map type to be passed into | 921 | goto error; |
935 | * the special func; | 922 | break; |
936 | */ | 923 | case BPF_MAP_TYPE_PERF_EVENT_ARRAY: |
937 | if (bool_func && bool_map != bool_func) { | 924 | if (func_id != BPF_FUNC_perf_event_read && |
938 | verbose("cannot pass map_type %d into func %d\n", | 925 | func_id != BPF_FUNC_perf_event_output) |
939 | map->map_type, func_id); | 926 | goto error; |
940 | return -EINVAL; | 927 | break; |
941 | } | 928 | case BPF_MAP_TYPE_STACK_TRACE: |
929 | if (func_id != BPF_FUNC_get_stackid) | ||
930 | goto error; | ||
931 | break; | ||
932 | default: | ||
933 | break; | ||
934 | } | ||
935 | |||
936 | /* ... and second from the function itself. */ | ||
937 | switch (func_id) { | ||
938 | case BPF_FUNC_tail_call: | ||
939 | if (map->map_type != BPF_MAP_TYPE_PROG_ARRAY) | ||
940 | goto error; | ||
941 | break; | ||
942 | case BPF_FUNC_perf_event_read: | ||
943 | case BPF_FUNC_perf_event_output: | ||
944 | if (map->map_type != BPF_MAP_TYPE_PERF_EVENT_ARRAY) | ||
945 | goto error; | ||
946 | break; | ||
947 | case BPF_FUNC_get_stackid: | ||
948 | if (map->map_type != BPF_MAP_TYPE_STACK_TRACE) | ||
949 | goto error; | ||
950 | break; | ||
951 | default: | ||
952 | break; | ||
942 | } | 953 | } |
943 | 954 | ||
944 | return 0; | 955 | return 0; |
956 | error: | ||
957 | verbose("cannot pass map_type %d into func %d\n", | ||
958 | map->map_type, func_id); | ||
959 | return -EINVAL; | ||
945 | } | 960 | } |
946 | 961 | ||
947 | static int check_call(struct verifier_env *env, int func_id) | 962 | static int check_call(struct verifier_env *env, int func_id) |