diff mbox

[net,2/3] bpf: fix check_map_func_compatibility logic

Message ID 1461808582-1452466-3-git-send-email-ast@fb.com
State Accepted, archived
Delegated to: David Miller
Headers show

Commit Message

Alexei Starovoitov April 28, 2016, 1:56 a.m. UTC
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>
---
 kernel/bpf/verifier.c | 65 +++++++++++++++++++++++++++++++--------------------
 1 file changed, 40 insertions(+), 25 deletions(-)

Comments

Jann Horn April 28, 2016, 9:31 a.m. UTC | #1
On Thu, Apr 28, 2016 at 3:56 AM, Alexei Starovoitov <ast@fb.com> wrote:
> 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>
> ---
>  kernel/bpf/verifier.c | 65 +++++++++++++++++++++++++++++++--------------------
>  1 file 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
[...]
> +       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;
> +       case BPF_MAP_TYPE_STACK_TRACE:
> +               if (func_id != BPF_FUNC_get_stackid)
> +                       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;
> +       case BPF_FUNC_get_stackid:
> +               if (map->map_type != BPF_MAP_TYPE_STACK_TRACE)
> +                       goto error;
> +               break;
> +       default:
> +               break;
>         }

Looks good to me.
diff mbox

Patch

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[] = {
 	[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},
-	{BPF_MAP_TYPE_STACK_TRACE, BPF_FUNC_get_stackid},
-};
-
 static void print_verifier_state(struct verifier_env *env)
 {
 	enum bpf_reg_type t;
@@ -921,27 +911,52 @@  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;
 
-	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) {
-			verbose("cannot pass map_type %d into func %d\n",
-				map->map_type, func_id);
-			return -EINVAL;
-		}
+	/* 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;
+	case BPF_MAP_TYPE_STACK_TRACE:
+		if (func_id != BPF_FUNC_get_stackid)
+			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;
+	case BPF_FUNC_get_stackid:
+		if (map->map_type != BPF_MAP_TYPE_STACK_TRACE)
+			goto error;
+		break;
+	default:
+		break;
 	}
 
 	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)