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

Commit b33eb735 authored by Daniel Borkmann's avatar Daniel Borkmann Committed by Alexei Starovoitov
Browse files

bpf: add tail call tests to test_verifier



One of the downsides of the test_bpf module was that since being
in kernel space, it couldn't test-run tail calls. Now that the
test_verifier has the ability to perform run-time tests, populate
the prog array so we actually jump into other BPF programs and
can check all corner cases. Most useful in combination with JITs.

Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
Acked-by: default avatarAlexei Starovoitov <ast@kernel.org>
Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parent fe8d662a
Loading
Loading
Loading
Loading
+110 −7
Original line number Diff line number Diff line
@@ -2588,6 +2588,62 @@ static struct bpf_test tests[] = {
		.result_unpriv = REJECT,
		.result = ACCEPT,
	},
	{
		"runtime/jit: tail_call within bounds, prog once",
		.insns = {
			BPF_MOV64_IMM(BPF_REG_3, 0),
			BPF_LD_MAP_FD(BPF_REG_2, 0),
			BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
				     BPF_FUNC_tail_call),
			BPF_MOV64_IMM(BPF_REG_0, 1),
			BPF_EXIT_INSN(),
		},
		.fixup_prog = { 1 },
		.result = ACCEPT,
		.retval = 42,
	},
	{
		"runtime/jit: tail_call within bounds, prog loop",
		.insns = {
			BPF_MOV64_IMM(BPF_REG_3, 1),
			BPF_LD_MAP_FD(BPF_REG_2, 0),
			BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
				     BPF_FUNC_tail_call),
			BPF_MOV64_IMM(BPF_REG_0, 1),
			BPF_EXIT_INSN(),
		},
		.fixup_prog = { 1 },
		.result = ACCEPT,
		.retval = 41,
	},
	{
		"runtime/jit: tail_call within bounds, no prog",
		.insns = {
			BPF_MOV64_IMM(BPF_REG_3, 2),
			BPF_LD_MAP_FD(BPF_REG_2, 0),
			BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
				     BPF_FUNC_tail_call),
			BPF_MOV64_IMM(BPF_REG_0, 1),
			BPF_EXIT_INSN(),
		},
		.fixup_prog = { 1 },
		.result = ACCEPT,
		.retval = 1,
	},
	{
		"runtime/jit: tail_call out of bounds",
		.insns = {
			BPF_MOV64_IMM(BPF_REG_3, 256),
			BPF_LD_MAP_FD(BPF_REG_2, 0),
			BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
				     BPF_FUNC_tail_call),
			BPF_MOV64_IMM(BPF_REG_0, 2),
			BPF_EXIT_INSN(),
		},
		.fixup_prog = { 1 },
		.result = ACCEPT,
		.retval = 2,
	},
	{
		"runtime/jit: pass negative index to tail_call",
		.insns = {
@@ -2595,11 +2651,12 @@ static struct bpf_test tests[] = {
			BPF_LD_MAP_FD(BPF_REG_2, 0),
			BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
				     BPF_FUNC_tail_call),
			BPF_MOV64_IMM(BPF_REG_0, 0),
			BPF_MOV64_IMM(BPF_REG_0, 2),
			BPF_EXIT_INSN(),
		},
		.fixup_prog = { 1 },
		.result = ACCEPT,
		.retval = 2,
	},
	{
		"runtime/jit: pass > 32bit index to tail_call",
@@ -2608,11 +2665,12 @@ static struct bpf_test tests[] = {
			BPF_LD_MAP_FD(BPF_REG_2, 0),
			BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
				     BPF_FUNC_tail_call),
			BPF_MOV64_IMM(BPF_REG_0, 0),
			BPF_MOV64_IMM(BPF_REG_0, 2),
			BPF_EXIT_INSN(),
		},
		.fixup_prog = { 2 },
		.result = ACCEPT,
		.retval = 42,
	},
	{
		"stack pointer arithmetic",
@@ -11278,16 +11336,61 @@ static int create_map(uint32_t size_value, uint32_t max_elem)
	return fd;
}

static int create_prog_dummy1(void)
{
	struct bpf_insn prog[] = {
		BPF_MOV64_IMM(BPF_REG_0, 42),
		BPF_EXIT_INSN(),
	};

	return bpf_load_program(BPF_PROG_TYPE_SOCKET_FILTER, prog,
				ARRAY_SIZE(prog), "GPL", 0, NULL, 0);
}

static int create_prog_dummy2(int mfd, int idx)
{
	struct bpf_insn prog[] = {
		BPF_MOV64_IMM(BPF_REG_3, idx),
		BPF_LD_MAP_FD(BPF_REG_2, mfd),
		BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
			     BPF_FUNC_tail_call),
		BPF_MOV64_IMM(BPF_REG_0, 41),
		BPF_EXIT_INSN(),
	};

	return bpf_load_program(BPF_PROG_TYPE_SOCKET_FILTER, prog,
				ARRAY_SIZE(prog), "GPL", 0, NULL, 0);
}

static int create_prog_array(void)
{
	int fd;
	int p1key = 0, p2key = 1;
	int mfd, p1fd, p2fd;

	fd = bpf_create_map(BPF_MAP_TYPE_PROG_ARRAY, sizeof(int),
	mfd = bpf_create_map(BPF_MAP_TYPE_PROG_ARRAY, sizeof(int),
			     sizeof(int), 4, 0);
	if (fd < 0)
	if (mfd < 0) {
		printf("Failed to create prog array '%s'!\n", strerror(errno));
		return -1;
	}

	return fd;
	p1fd = create_prog_dummy1();
	p2fd = create_prog_dummy2(mfd, p2key);
	if (p1fd < 0 || p2fd < 0)
		goto out;
	if (bpf_map_update_elem(mfd, &p1key, &p1fd, BPF_ANY) < 0)
		goto out;
	if (bpf_map_update_elem(mfd, &p2key, &p2fd, BPF_ANY) < 0)
		goto out;
	close(p2fd);
	close(p1fd);

	return mfd;
out:
	close(p2fd);
	close(p1fd);
	close(mfd);
	return -1;
}

static int create_map_in_map(void)