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

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
...@@ -2588,6 +2588,62 @@ static struct bpf_test tests[] = { ...@@ -2588,6 +2588,62 @@ static struct bpf_test tests[] = {
.result_unpriv = REJECT, .result_unpriv = REJECT,
.result = ACCEPT, .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", "runtime/jit: pass negative index to tail_call",
.insns = { .insns = {
...@@ -2595,11 +2651,12 @@ static struct bpf_test tests[] = { ...@@ -2595,11 +2651,12 @@ static struct bpf_test tests[] = {
BPF_LD_MAP_FD(BPF_REG_2, 0), BPF_LD_MAP_FD(BPF_REG_2, 0),
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
BPF_FUNC_tail_call), BPF_FUNC_tail_call),
BPF_MOV64_IMM(BPF_REG_0, 0), BPF_MOV64_IMM(BPF_REG_0, 2),
BPF_EXIT_INSN(), BPF_EXIT_INSN(),
}, },
.fixup_prog = { 1 }, .fixup_prog = { 1 },
.result = ACCEPT, .result = ACCEPT,
.retval = 2,
}, },
{ {
"runtime/jit: pass > 32bit index to tail_call", "runtime/jit: pass > 32bit index to tail_call",
...@@ -2608,11 +2665,12 @@ static struct bpf_test tests[] = { ...@@ -2608,11 +2665,12 @@ static struct bpf_test tests[] = {
BPF_LD_MAP_FD(BPF_REG_2, 0), BPF_LD_MAP_FD(BPF_REG_2, 0),
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
BPF_FUNC_tail_call), BPF_FUNC_tail_call),
BPF_MOV64_IMM(BPF_REG_0, 0), BPF_MOV64_IMM(BPF_REG_0, 2),
BPF_EXIT_INSN(), BPF_EXIT_INSN(),
}, },
.fixup_prog = { 2 }, .fixup_prog = { 2 },
.result = ACCEPT, .result = ACCEPT,
.retval = 42,
}, },
{ {
"stack pointer arithmetic", "stack pointer arithmetic",
...@@ -11278,16 +11336,61 @@ static int create_map(uint32_t size_value, uint32_t max_elem) ...@@ -11278,16 +11336,61 @@ static int create_map(uint32_t size_value, uint32_t max_elem)
return fd; 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) 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); sizeof(int), 4, 0);
if (fd < 0) if (mfd < 0) {
printf("Failed to create prog array '%s'!\n", strerror(errno)); 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) static int create_map_in_map(void)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment