bpf: increase bpf test coverage
Subsystems (7)
Alexei Starovoitov
maintainercover bpf: increase bpf test coverage
BPF verifier has 700+ tests used to check correctness of the verifier. Beyond checking the verifier log tell kernel to run accepted programs as well via bpf_prog_test_run() command. That improves quality of the tests and increases bpf test coverage.
Alexei Starovoitov (2):
bpf: allow socket_filter programs to use bpf_prog_test_run selftests/bpf: make test_verifier run most programs
kernel/bpf/syscall.c | 2 ++ net/core/filter.c | 1 + tools/testing/selftests/bpf/test_verifier.c | 50 ++++++++++++++++++++++++++++- 3 files changed, 52 insertions(+), 1 deletion(-)
Signature · 1 line
2.9.5
Alexei Starovoitov
maintainerPATCH 1/2 bpf: allow socket_filter programs to use bpf_prog_test_run
in order to improve test coverage allow socket_filter program type to be run via bpf_prog_test_run command.
Since such programs can be loaded by non-root tighten permissions for bpf_prog_test_run to be root only
to avoid surprises.
--- kernel/bpf/syscall.c | 2 ++ net/core/filter.c | 1 + 2 files changed, 3 insertions(+)
kernel/bpf/syscall.c +2 -0
@@ -1504,6 +1504,8 @@ static int bpf_prog_test_run(const union bpf_attr *attr,struct bpf_prog *prog;int ret = -ENOTSUPP ; +if (!capable (CAP_SYS_ADMIN )) +return -EPERM ;if (CHECK_ATTR (BPF_PROG_TEST_RUN ))return -EINVAL ;
net/core/filter.c +1 -0
@@ -4526,6 +4526,7 @@ const struct bpf_verifier_ops sk_filter_verifier_ops = { };const struct bpf_prog_ops sk_filter_prog_ops = { + .test_run = bpf_prog_test_run_skb, };const struct bpf_verifier_ops tc_cls_act_verifier_ops = {
Signature · 1 line
2.9.5
Alexei Starovoitov
maintainerPATCH 2/2 selftests/bpf: make test_verifier run most programs
In reply to Alexei Starovoitovto improve test coverage make test_verifier run all successfully loaded programs on 64-byte zero initialized data.
For clsbpf and xdp it means empty 64-byte packet.
For lwt and socket_filters it's 64-byte packet where skb->data points after L2.
--- tools/testing/selftests/bpf/test_verifier.c | 50 ++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-)
tools/testing/selftests/bpf/test_verifier.c +49 -1
@@ -29,6 +29,7 @@#include <linux/filter.h> #include <linux/bpf_perf_event.h> #include <linux/bpf.h> +#include <linux/if_ether.h> #include <bpf/bpf.h>
@@ -49,6 +50,8 @@#define MAX_INSNS 512#define MAX_FIXUPS 8#define MAX_NR_MAPS 4 +#define POINTER_VALUE 0xcafe4all +#define TEST_DATA_LEN 64#define F_NEEDS_EFFICIENT_UNALIGNED_ACCESS (1 << 0)#define F_LOAD_WITH_STRICT_ALIGNMENT (1 << 1)
@@ -62,6 +65,7 @@ struct bpf_test {int fixup_map_in_map[MAX_FIXUPS ];const char *errstr;const char *errstr_unpriv; +uint32_t retval;enum {UNDEF ,ACCEPT ,
@@ -95,6 +99,7 @@ static struct bpf_test tests[] = { BPF_EXIT_INSN(), }, .result = ACCEPT, + .retval =-3 , }, { "unreachable",
@@ -210,6 +215,7 @@ static struct bpf_test tests[] = { BPF_EXIT_INSN(), }, .result = ACCEPT, + .retval =1 , }, { "test8 ld_imm64",
@@ -477,6 +483,7 @@ static struct bpf_test tests[] = { .errstr_unpriv = "R0 leaks addr", .result = ACCEPT, .result_unpriv = REJECT, + .retval = POINTER_VALUE, }, { "check valid spill/fill, skb mark",
@@ -763,6 +770,7 @@ static struct bpf_test tests[] = { .errstr_unpriv = "R1 pointer comparison", .result_unpriv = REJECT, .result = ACCEPT, + .retval = -ENOENT, }, { "jump test 4",
@@ -1783,6 +1791,7 @@ static struct bpf_test tests[] = { BPF_EXIT_INSN(), }, .result = ACCEPT, + .retval =0xfaceb00c , }, { "PTR_TO_STACK store/load - bad alignment on off",
@@ -1841,6 +1850,7 @@ static struct bpf_test tests[] = { .result = ACCEPT, .result_unpriv = REJECT, .errstr_unpriv = "R0 leaks addr", + .retval = POINTER_VALUE, }, { "unpriv: add const to pointer",
@@ -2014,6 +2024,7 @@ static struct bpf_test tests[] = {BPF_LDX_MEM (BPF_DW ,BPF_REG_1 ,BPF_REG_6 ,0 ),BPF_RAW_INSN (BPF_JMP |BPF_CALL ,0 ,0 ,0 , BPF_FUNC_get_hash_recalc), +BPF_MOV64_IMM (BPF_REG_0 ,0 ), BPF_EXIT_INSN(), }, .result = ACCEPT,
@@ -2778,6 +2789,7 @@ static struct bpf_test tests[] = { }, .result = ACCEPT, .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .retval = 1, }, { "direct packet access: test12 (and, good access)",
@@ -2802,6 +2814,7 @@ static struct bpf_test tests[] = { }, .result = ACCEPT, .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .retval = 1, }, { "direct packet access: test13 (branches, good access)",
@@ -2832,6 +2845,7 @@ static struct bpf_test tests[] = { }, .result = ACCEPT, .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .retval = 1, }, { "direct packet access: test14 (pkt_ptr += 0, CONST_IMM, good access)",
@@ -2855,6 +2869,7 @@ static struct bpf_test tests[] = { }, .result = ACCEPT, .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .retval = 1, }, { "direct packet access: test15 (spill with xadd)",
@@ -3141,6 +3156,7 @@ static struct bpf_test tests[] = { }, .result = ACCEPT, .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .retval = 1, }, { "direct packet access: test28 (marking on <=, bad access)",
@@ -5758,6 +5774,7 @@ static struct bpf_test tests[] = { }, .result = ACCEPT, .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .retval = 0 /* csum_diff of 64-byte packet */, }, { "helper access to variable memory: size = 0 not allowed on NULL (!ARG_PTR_TO_MEM_OR_NULL)",
@@ -6126,6 +6143,7 @@ static struct bpf_test tests[] = { }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .result = ACCEPT, + .retval = 42 /* ultimate return value */, }, { "ld_ind: check calling conv, r1",
@@ -6197,6 +6215,7 @@ static struct bpf_test tests[] = { BPF_EXIT_INSN(), }, .result = ACCEPT, + .retval =1 , }, { "check bpf_perf_event_data->sample_period byte load permitted",
@@ -7184,6 +7203,7 @@ static struct bpf_test tests[] = { }, .fixup_map1 = { 3 }, .result = ACCEPT, + .retval = POINTER_VALUE, .result_unpriv = REJECT, .errstr_unpriv ="R0 leaks addr as return value" },
@@ -7204,6 +7224,7 @@ static struct bpf_test tests[] = { }, .fixup_map1 = { 3 }, .result = ACCEPT, + .retval = POINTER_VALUE, .result_unpriv = REJECT, .errstr_unpriv ="R0 leaks addr as return value" },
@@ -7645,6 +7666,7 @@ static struct bpf_test tests[] = { BPF_EXIT_INSN(), }, .result = ACCEPT, + .retval = TEST_DATA_LEN, .prog_type = BPF_PROG_TYPE_SCHED_CLS, }, {
@@ -8665,6 +8687,7 @@ static struct bpf_test tests[] = { .errstr_unpriv = "function calls to other bpf functions are allowed for root only", .result_unpriv = REJECT, .result = ACCEPT, + .retval = 1, }, { "calls: overlapping caller/callee",
@@ -8860,6 +8883,7 @@ static struct bpf_test tests[] = { }, .prog_type = BPF_PROG_TYPE_SCHED_ACT, .result = ACCEPT, + .retval = TEST_DATA_LEN, }, { "calls: callee using args1",
@@ -8872,6 +8896,7 @@ static struct bpf_test tests[] = { .errstr_unpriv = "allowed for root only", .result_unpriv = REJECT, .result = ACCEPT, + .retval = POINTER_VALUE, }, { "calls: callee using wrong args2",
@@ -8902,6 +8927,7 @@ static struct bpf_test tests[] = { .errstr_unpriv = "allowed for root only", .result_unpriv = REJECT, .result = ACCEPT, + .retval = TEST_DATA_LEN + TEST_DATA_LEN - ETH_HLEN - ETH_HLEN, }, { "calls: callee changing pkt pointers",
@@ -8950,6 +8976,7 @@ static struct bpf_test tests[] = { }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .result = ACCEPT, + .retval = TEST_DATA_LEN + TEST_DATA_LEN, }, { "calls: calls with stack arith",
@@ -8968,6 +8995,7 @@ static struct bpf_test tests[] = { }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .result = ACCEPT, + .retval = 42, }, { "calls: calls with misaligned stack access",
@@ -9001,6 +9029,7 @@ static struct bpf_test tests[] = { }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .result = ACCEPT, + .retval = 43, }, { "calls: calls control flow, jump test 2",
@@ -9493,6 +9522,7 @@ static struct bpf_test tests[] = { }, .prog_type = BPF_PROG_TYPE_XDP, .result = ACCEPT, + .retval = 42, }, { "calls: write into callee stack frame",
@@ -10104,6 +10134,7 @@ static struct bpf_test tests[] = { }, .result = ACCEPT, .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .retval = POINTER_VALUE, }, { "calls: pkt_ptr spill into caller stack 2",
@@ -10169,6 +10200,7 @@ static struct bpf_test tests[] = { }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .result = ACCEPT, + .retval = 1, }, { "calls: pkt_ptr spill into caller stack 4",
@@ -10202,6 +10234,7 @@ static struct bpf_test tests[] = { }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .result = ACCEPT, + .retval = 1, }, { "calls: pkt_ptr spill into caller stack 5",
@@ -10610,10 +10643,12 @@ static void do_test_single(struct bpf_test *test, bool unpriv,int fd_prog, expected_ret, reject_from_alignment;struct bpf_insn *prog = test->insns;int prog_len =probe_filter_length (prog); +char data_in[TEST_DATA_LEN ] = {};int prog_type = test->prog_type;int map_fds[MAX_NR_MAPS ];const char *expected_err; -int i; +uint32_t retval; +int i, err;for (i =0 ; i <MAX_NR_MAPS ; i++) map_fds[i] =-1 ;
@@ -10656,6 +10691,19 @@ static void do_test_single(struct bpf_test *test, bool unpriv, } } +if (fd_prog >=0 ) { + err =bpf_prog_test_run (fd_prog,1 , data_in,sizeof (data_in), +NULL ,NULL , &retval,NULL ); +if (err && errno !=524 /*ENOTSUPP*/ && errno !=EPERM ) { +printf ("Unexpected bpf_prog_test_run error\n" ); + goto fail_log; + } +if (!err && retval != test->retval && + test->retval !=POINTER_VALUE ) { +printf ("FAIL retval %d != %d\n" , retval, test->retval); + goto fail_log; + } + } (*passes)++;printf ("OK%s\n" , reject_from_alignment ?" (NOTE: reject due to unknown alignment)" :"" );
Signature · 1 line
2.9.5