Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6aff67c8 authored by Alexei Starovoitov's avatar Alexei Starovoitov Committed by David S. Miller
Browse files

bpf: fix check_map_func_compatibility logic



The commit 35578d79 ("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 a43eec30 ("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: a43eec30 ("bpf: introduce bpf_perf_event_output() helper")
Reported-by: default avatarJann Horn <jannh@google.com>
Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 92117d84
Loading
Loading
Loading
Loading
+40 −25
Original line number Diff line number Diff line
@@ -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)