aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexei Starovoitov <ast@fb.com>2016-04-27 21:56:21 -0400
committerDavid S. Miller <davem@davemloft.net>2016-04-28 17:29:45 -0400
commit6aff67c85c9e5a4bc99e5211c1bac547936626ca (patch)
tree3be9fa8e180334d6f8e0c5edb5e47f8113f4b2f4
parent92117d8443bc5afacc8d5ba82e541946310f106e (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.c65
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
242static 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
252static void print_verifier_state(struct verifier_env *env) 242static 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
922static int check_map_func_compatibility(struct bpf_map *map, int func_id) 912static 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;
956error:
957 verbose("cannot pass map_type %d into func %d\n",
958 map->map_type, func_id);
959 return -EINVAL;
945} 960}
946 961
947static int check_call(struct verifier_env *env, int func_id) 962static int check_call(struct verifier_env *env, int func_id)