Skip to content

Commit

Permalink
bpf: Selftest to verify mixing bpf2bpf calls and tailcalls with insn …
Browse files Browse the repository at this point in the history
…patch

This adds some extra noise to the tailcall_bpf2bpf4 tests that will cause
verify to patch insns. This then moves around subprog start/end insn
index and poke descriptor insn index to ensure that verify and JIT will
continue to track these correctly.

If done correctly verifier should pass this program same as before and
JIT should emit tail call logic.

Signed-off-by: John Fastabend <[email protected]>
Signed-off-by: Alexei Starovoitov <[email protected]>
Signed-off-by: Daniel Borkmann <[email protected]>
Link: https://lore.kernel.org/bpf/[email protected]
  • Loading branch information
jrfastab authored and borkmann committed Jul 9, 2021
1 parent f263a81 commit 1fb5ba2
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 10 deletions.
36 changes: 26 additions & 10 deletions tools/testing/selftests/bpf/prog_tests/tailcalls.c
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,8 @@ static void test_tailcall_bpf2bpf_3(void)
bpf_object__close(obj);
}

#include "tailcall_bpf2bpf4.skel.h"

/* test_tailcall_bpf2bpf_4 checks that tailcall counter is correctly preserved
* across tailcalls combined with bpf2bpf calls. for making sure that tailcall
* counter behaves correctly, bpf program will go through following flow:
Expand All @@ -727,10 +729,15 @@ static void test_tailcall_bpf2bpf_3(void)
* the loop begins. At the end of the test make sure that the global counter is
* equal to 31, because tailcall counter includes the first two tailcalls
* whereas global counter is incremented only on loop presented on flow above.
*
* The noise parameter is used to insert bpf_map_update calls into the logic
* to force verifier to patch instructions. This allows us to ensure jump
* logic remains correct with instruction movement.
*/
static void test_tailcall_bpf2bpf_4(void)
static void test_tailcall_bpf2bpf_4(bool noise)
{
int err, map_fd, prog_fd, main_fd, data_fd, i, val;
int err, map_fd, prog_fd, main_fd, data_fd, i;
struct tailcall_bpf2bpf4__bss val;
struct bpf_map *prog_array, *data_map;
struct bpf_program *prog;
struct bpf_object *obj;
Expand Down Expand Up @@ -774,11 +781,6 @@ static void test_tailcall_bpf2bpf_4(void)
goto out;
}

err = bpf_prog_test_run(main_fd, 1, &pkt_v4, sizeof(pkt_v4), 0,
&duration, &retval, NULL);
CHECK(err || retval != sizeof(pkt_v4) * 3, "tailcall", "err %d errno %d retval %d\n",
err, errno, retval);

data_map = bpf_object__find_map_by_name(obj, "tailcall.bss");
if (CHECK_FAIL(!data_map || !bpf_map__is_internal(data_map)))
return;
Expand All @@ -787,10 +789,22 @@ static void test_tailcall_bpf2bpf_4(void)
if (CHECK_FAIL(map_fd < 0))
return;

i = 0;
val.noise = noise;
val.count = 0;
err = bpf_map_update_elem(data_fd, &i, &val, BPF_ANY);
if (CHECK_FAIL(err))
goto out;

err = bpf_prog_test_run(main_fd, 1, &pkt_v4, sizeof(pkt_v4), 0,
&duration, &retval, NULL);
CHECK(err || retval != sizeof(pkt_v4) * 3, "tailcall", "err %d errno %d retval %d\n",
err, errno, retval);

i = 0;
err = bpf_map_lookup_elem(data_fd, &i, &val);
CHECK(err || val != 31, "tailcall count", "err %d errno %d count %d\n",
err, errno, val);
CHECK(err || val.count != 31, "tailcall count", "err %d errno %d count %d\n",
err, errno, val.count);

out:
bpf_object__close(obj);
Expand All @@ -815,5 +829,7 @@ void test_tailcalls(void)
if (test__start_subtest("tailcall_bpf2bpf_3"))
test_tailcall_bpf2bpf_3();
if (test__start_subtest("tailcall_bpf2bpf_4"))
test_tailcall_bpf2bpf_4();
test_tailcall_bpf2bpf_4(false);
if (test__start_subtest("tailcall_bpf2bpf_5"))
test_tailcall_bpf2bpf_4(true);
}
18 changes: 18 additions & 0 deletions tools/testing/selftests/bpf/progs/tailcall_bpf2bpf4.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>

struct {
__uint(type, BPF_MAP_TYPE_ARRAY);
__uint(max_entries, 1);
__uint(key_size, sizeof(__u32));
__uint(value_size, sizeof(__u32));
} nop_table SEC(".maps");

struct {
__uint(type, BPF_MAP_TYPE_PROG_ARRAY);
__uint(max_entries, 3);
Expand All @@ -10,10 +17,21 @@ struct {
} jmp_table SEC(".maps");

int count = 0;
int noise = 0;

__always_inline int subprog_noise(void)
{
__u32 key = 0;

bpf_map_lookup_elem(&nop_table, &key);
return 0;
}

__noinline
int subprog_tail_2(struct __sk_buff *skb)
{
if (noise)
subprog_noise();
bpf_tail_call_static(skb, &jmp_table, 2);
return skb->len * 3;
}
Expand Down

0 comments on commit 1fb5ba2

Please sign in to comment.