Skip to content

Commit e993607

Browse files
author
Alexei Starovoitov
committed
Merge branch 'First set of verifier/*.c migrated to inline assembly'
Eduard Zingerman says: ==================== This is a follow up for RFC [1]. It migrates a first batch of 38 verifier/*.c tests to inline assembly and use of ./test_progs for actual execution. The migration is done by a python script (see [2]). Each migrated verifier/xxx.c file is mapped to progs/verifier_xxx.c plus an entry in the prog_tests/verifier.c. One patch per each file. A few patches at the beginning of the patch-set extend test_loader with necessary functionality, mainly: - support for tests execution in unprivileged mode; - support for test runs for test programs. Migrated tests could be selected for execution using the following filter: ./test_progs -a verifier_* An example of the migrated test: SEC("xdp") __description("XDP pkt read, pkt_data' > pkt_end, corner case, good access") __success __retval(0) __flag(BPF_F_ANY_ALIGNMENT) __naked void end_corner_case_good_access_1(void) { asm volatile (" \ r2 = *(u32*)(r1 + %[xdp_md_data]); \ r3 = *(u32*)(r1 + %[xdp_md_data_end]); \ r1 = r2; \ r1 += 8; \ if r1 > r3 goto l0_%=; \ r0 = *(u64*)(r1 - 8); \ l0_%=: r0 = 0; \ exit; \ " : : __imm_const(xdp_md_data, offsetof(struct xdp_md, data)), __imm_const(xdp_md_data_end, offsetof(struct xdp_md, data_end)) : __clobber_all); } Changes compared to RFC: - test_loader.c is extended to support test program runs; - capabilities handling now matches behavior of test_verifier; - BPF_ST_MEM instructions are automatically replaced by BPF_STX_MEM instructions to overcome current clang limitations; - tests styling updates according to RFC feedback; - 38 migrated files are included instead of 1. I used the following means for testing: - migration tool itself has a set of self-tests; - migrated tests are passing; - manually compared each old/new file side-by-side. While doing side-by-side comparison I've noted a few defects in the original tests: - and.c: - One of the jump targets is off by one; - BPF_ST_MEM wrong OFF/IMM ordering; - array_access.c: - BPF_ST_MEM wrong OFF/IMM ordering; - value_or_null.c: - BPF_ST_MEM wrong OFF/IMM ordering. These defects would be addressed separately. [1] RFC https://lore.kernel.org/bpf/[email protected]/ [2] Migration tool https://github.com/eddyz87/verifier-tests-migrator ==================== Signed-off-by: Alexei Starovoitov <[email protected]>
2 parents 496f4f1 + ffb515c commit e993607

File tree

82 files changed

+10270
-7532
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

82 files changed

+10270
-7532
lines changed

tools/testing/selftests/bpf/Makefile

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -231,8 +231,9 @@ TEST_GEN_PROGS_EXTENDED += $(TRUNNER_BPFTOOL)
231231

232232
$(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED): $(BPFOBJ)
233233

234-
CGROUP_HELPERS := $(OUTPUT)/cgroup_helpers.o
235234
TESTING_HELPERS := $(OUTPUT)/testing_helpers.o
235+
CGROUP_HELPERS := $(OUTPUT)/cgroup_helpers.o
236+
UNPRIV_HELPERS := $(OUTPUT)/unpriv_helpers.o
236237
TRACE_HELPERS := $(OUTPUT)/trace_helpers.o
237238
JSON_WRITER := $(OUTPUT)/json_writer.o
238239
CAP_HELPERS := $(OUTPUT)/cap_helpers.o
@@ -252,7 +253,7 @@ $(OUTPUT)/test_lirc_mode2_user: $(TESTING_HELPERS)
252253
$(OUTPUT)/xdping: $(TESTING_HELPERS)
253254
$(OUTPUT)/flow_dissector_load: $(TESTING_HELPERS)
254255
$(OUTPUT)/test_maps: $(TESTING_HELPERS)
255-
$(OUTPUT)/test_verifier: $(TESTING_HELPERS) $(CAP_HELPERS)
256+
$(OUTPUT)/test_verifier: $(TESTING_HELPERS) $(CAP_HELPERS) $(UNPRIV_HELPERS)
256257
$(OUTPUT)/xsk.o: $(BPFOBJ)
257258

258259
BPFTOOL ?= $(DEFAULT_BPFTOOL)
@@ -560,8 +561,9 @@ TRUNNER_BPF_PROGS_DIR := progs
560561
TRUNNER_EXTRA_SOURCES := test_progs.c cgroup_helpers.c trace_helpers.c \
561562
network_helpers.c testing_helpers.c \
562563
btf_helpers.c flow_dissector_load.h \
563-
cap_helpers.c test_loader.c xsk.c disasm.c \
564-
json_writer.c
564+
cap_helpers.c test_loader.c xsk.c disasm.c \
565+
json_writer.c unpriv_helpers.c
566+
565567
TRUNNER_EXTRA_FILES := $(OUTPUT)/urandom_read $(OUTPUT)/bpf_testmod.ko \
566568
$(OUTPUT)/liburandom_read.so \
567569
$(OUTPUT)/xdp_synproxy \
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
3+
#ifdef HAVE_GENHDR
4+
# include "autoconf.h"
5+
#else
6+
# if defined(__i386) || defined(__x86_64) || defined(__s390x__) || defined(__aarch64__)
7+
# define CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 1
8+
# endif
9+
#endif
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
3+
#include <test_progs.h>
4+
5+
#include "cap_helpers.h"
6+
#include "verifier_and.skel.h"
7+
#include "verifier_array_access.skel.h"
8+
#include "verifier_basic_stack.skel.h"
9+
#include "verifier_bounds_deduction.skel.h"
10+
#include "verifier_bounds_mix_sign_unsign.skel.h"
11+
#include "verifier_cfg.skel.h"
12+
#include "verifier_cgroup_inv_retcode.skel.h"
13+
#include "verifier_cgroup_skb.skel.h"
14+
#include "verifier_cgroup_storage.skel.h"
15+
#include "verifier_const_or.skel.h"
16+
#include "verifier_ctx_sk_msg.skel.h"
17+
#include "verifier_direct_stack_access_wraparound.skel.h"
18+
#include "verifier_div0.skel.h"
19+
#include "verifier_div_overflow.skel.h"
20+
#include "verifier_helper_access_var_len.skel.h"
21+
#include "verifier_helper_packet_access.skel.h"
22+
#include "verifier_helper_restricted.skel.h"
23+
#include "verifier_helper_value_access.skel.h"
24+
#include "verifier_int_ptr.skel.h"
25+
#include "verifier_ld_ind.skel.h"
26+
#include "verifier_leak_ptr.skel.h"
27+
#include "verifier_map_ptr.skel.h"
28+
#include "verifier_map_ret_val.skel.h"
29+
#include "verifier_masking.skel.h"
30+
#include "verifier_meta_access.skel.h"
31+
#include "verifier_raw_stack.skel.h"
32+
#include "verifier_raw_tp_writable.skel.h"
33+
#include "verifier_ringbuf.skel.h"
34+
#include "verifier_spill_fill.skel.h"
35+
#include "verifier_stack_ptr.skel.h"
36+
#include "verifier_uninit.skel.h"
37+
#include "verifier_value_adj_spill.skel.h"
38+
#include "verifier_value.skel.h"
39+
#include "verifier_value_or_null.skel.h"
40+
#include "verifier_var_off.skel.h"
41+
#include "verifier_xadd.skel.h"
42+
#include "verifier_xdp.skel.h"
43+
44+
__maybe_unused
45+
static void run_tests_aux(const char *skel_name, skel_elf_bytes_fn elf_bytes_factory)
46+
{
47+
struct test_loader tester = {};
48+
__u64 old_caps;
49+
int err;
50+
51+
/* test_verifier tests are executed w/o CAP_SYS_ADMIN, do the same here */
52+
err = cap_disable_effective(1ULL << CAP_SYS_ADMIN, &old_caps);
53+
if (err) {
54+
PRINT_FAIL("failed to drop CAP_SYS_ADMIN: %i, %s\n", err, strerror(err));
55+
return;
56+
}
57+
58+
test_loader__run_subtests(&tester, skel_name, elf_bytes_factory);
59+
test_loader_fini(&tester);
60+
61+
err = cap_enable_effective(old_caps, NULL);
62+
if (err)
63+
PRINT_FAIL("failed to restore CAP_SYS_ADMIN: %i, %s\n", err, strerror(err));
64+
}
65+
66+
#define RUN(skel) run_tests_aux(#skel, skel##__elf_bytes)
67+
68+
void test_verifier_and(void) { RUN(verifier_and); }
69+
void test_verifier_array_access(void) { RUN(verifier_array_access); }
70+
void test_verifier_basic_stack(void) { RUN(verifier_basic_stack); }
71+
void test_verifier_bounds_deduction(void) { RUN(verifier_bounds_deduction); }
72+
void test_verifier_bounds_mix_sign_unsign(void) { RUN(verifier_bounds_mix_sign_unsign); }
73+
void test_verifier_cfg(void) { RUN(verifier_cfg); }
74+
void test_verifier_cgroup_inv_retcode(void) { RUN(verifier_cgroup_inv_retcode); }
75+
void test_verifier_cgroup_skb(void) { RUN(verifier_cgroup_skb); }
76+
void test_verifier_cgroup_storage(void) { RUN(verifier_cgroup_storage); }
77+
void test_verifier_const_or(void) { RUN(verifier_const_or); }
78+
void test_verifier_ctx_sk_msg(void) { RUN(verifier_ctx_sk_msg); }
79+
void test_verifier_direct_stack_access_wraparound(void) { RUN(verifier_direct_stack_access_wraparound); }
80+
void test_verifier_div0(void) { RUN(verifier_div0); }
81+
void test_verifier_div_overflow(void) { RUN(verifier_div_overflow); }
82+
void test_verifier_helper_access_var_len(void) { RUN(verifier_helper_access_var_len); }
83+
void test_verifier_helper_packet_access(void) { RUN(verifier_helper_packet_access); }
84+
void test_verifier_helper_restricted(void) { RUN(verifier_helper_restricted); }
85+
void test_verifier_helper_value_access(void) { RUN(verifier_helper_value_access); }
86+
void test_verifier_int_ptr(void) { RUN(verifier_int_ptr); }
87+
void test_verifier_ld_ind(void) { RUN(verifier_ld_ind); }
88+
void test_verifier_leak_ptr(void) { RUN(verifier_leak_ptr); }
89+
void test_verifier_map_ptr(void) { RUN(verifier_map_ptr); }
90+
void test_verifier_map_ret_val(void) { RUN(verifier_map_ret_val); }
91+
void test_verifier_masking(void) { RUN(verifier_masking); }
92+
void test_verifier_meta_access(void) { RUN(verifier_meta_access); }
93+
void test_verifier_raw_stack(void) { RUN(verifier_raw_stack); }
94+
void test_verifier_raw_tp_writable(void) { RUN(verifier_raw_tp_writable); }
95+
void test_verifier_ringbuf(void) { RUN(verifier_ringbuf); }
96+
void test_verifier_spill_fill(void) { RUN(verifier_spill_fill); }
97+
void test_verifier_stack_ptr(void) { RUN(verifier_stack_ptr); }
98+
void test_verifier_uninit(void) { RUN(verifier_uninit); }
99+
void test_verifier_value_adj_spill(void) { RUN(verifier_value_adj_spill); }
100+
void test_verifier_value(void) { RUN(verifier_value); }
101+
void test_verifier_value_or_null(void) { RUN(verifier_value_or_null); }
102+
void test_verifier_var_off(void) { RUN(verifier_var_off); }
103+
void test_verifier_xadd(void) { RUN(verifier_xadd); }
104+
void test_verifier_xdp(void) { RUN(verifier_xdp); }

tools/testing/selftests/bpf/progs/bpf_misc.h

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,42 @@
55
/* This set of attributes controls behavior of the
66
* test_loader.c:test_loader__run_subtests().
77
*
8+
* The test_loader sequentially loads each program in a skeleton.
9+
* Programs could be loaded in privileged and unprivileged modes.
10+
* - __success, __failure, __msg imply privileged mode;
11+
* - __success_unpriv, __failure_unpriv, __msg_unpriv imply
12+
* unprivileged mode.
13+
* If combination of privileged and unprivileged attributes is present
14+
* both modes are used. If none are present privileged mode is implied.
15+
*
16+
* See test_loader.c:drop_capabilities() for exact set of capabilities
17+
* that differ between privileged and unprivileged modes.
18+
*
19+
* For test filtering purposes the name of the program loaded in
20+
* unprivileged mode is derived from the usual program name by adding
21+
* `@unpriv' suffix.
22+
*
823
* __msg Message expected to be found in the verifier log.
924
* Multiple __msg attributes could be specified.
25+
* __msg_unpriv Same as __msg but for unprivileged mode.
1026
*
1127
* __success Expect program load success in privileged mode.
28+
* __success_unpriv Expect program load success in unprivileged mode.
1229
*
1330
* __failure Expect program load failure in privileged mode.
31+
* __failure_unpriv Expect program load failure in unprivileged mode.
32+
*
33+
* __retval Execute the program using BPF_PROG_TEST_RUN command,
34+
* expect return value to match passed parameter:
35+
* - a decimal number
36+
* - a hexadecimal number, when starts from 0x
37+
* - literal INT_MIN
38+
* - literal POINTER_VALUE (see definition below)
39+
* - literal TEST_DATA_LEN (see definition below)
40+
* __retval_unpriv Same, but load program in unprivileged mode.
41+
*
42+
* __description Text to be used instead of a program name for display
43+
* and filtering purposes.
1444
*
1545
* __log_level Log level to use for the program, numeric value expected.
1646
*
@@ -27,16 +57,28 @@
2757
#define __msg(msg) __attribute__((btf_decl_tag("comment:test_expect_msg=" msg)))
2858
#define __failure __attribute__((btf_decl_tag("comment:test_expect_failure")))
2959
#define __success __attribute__((btf_decl_tag("comment:test_expect_success")))
60+
#define __description(desc) __attribute__((btf_decl_tag("comment:test_description=" desc)))
61+
#define __msg_unpriv(msg) __attribute__((btf_decl_tag("comment:test_expect_msg_unpriv=" msg)))
62+
#define __failure_unpriv __attribute__((btf_decl_tag("comment:test_expect_failure_unpriv")))
63+
#define __success_unpriv __attribute__((btf_decl_tag("comment:test_expect_success_unpriv")))
3064
#define __log_level(lvl) __attribute__((btf_decl_tag("comment:test_log_level="#lvl)))
3165
#define __flag(flag) __attribute__((btf_decl_tag("comment:test_prog_flags="#flag)))
66+
#define __retval(val) __attribute__((btf_decl_tag("comment:test_retval="#val)))
67+
#define __retval_unpriv(val) __attribute__((btf_decl_tag("comment:test_retval_unpriv="#val)))
3268

3369
/* Convenience macro for use with 'asm volatile' blocks */
3470
#define __naked __attribute__((naked))
3571
#define __clobber_all "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "memory"
3672
#define __clobber_common "r0", "r1", "r2", "r3", "r4", "r5", "memory"
3773
#define __imm(name) [name]"i"(name)
74+
#define __imm_const(name, expr) [name]"i"(expr)
3875
#define __imm_addr(name) [name]"i"(&name)
3976
#define __imm_ptr(name) [name]"p"(&name)
77+
#define __imm_insn(name, expr) [name]"i"(*(long *)&(expr))
78+
79+
/* Magic constants used with __retval() */
80+
#define POINTER_VALUE 0xcafe4all
81+
#define TEST_DATA_LEN 64
4082

4183
#if defined(__TARGET_ARCH_x86)
4284
#define SYSCALL_WRAPPER 1
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/* Converted from tools/testing/selftests/bpf/verifier/and.c */
3+
4+
#include <linux/bpf.h>
5+
#include <bpf/bpf_helpers.h>
6+
#include "bpf_misc.h"
7+
8+
#define MAX_ENTRIES 11
9+
10+
struct test_val {
11+
unsigned int index;
12+
int foo[MAX_ENTRIES];
13+
};
14+
15+
struct {
16+
__uint(type, BPF_MAP_TYPE_HASH);
17+
__uint(max_entries, 1);
18+
__type(key, long long);
19+
__type(value, struct test_val);
20+
} map_hash_48b SEC(".maps");
21+
22+
SEC("socket")
23+
__description("invalid and of negative number")
24+
__failure __msg("R0 max value is outside of the allowed memory range")
25+
__failure_unpriv
26+
__flag(BPF_F_ANY_ALIGNMENT)
27+
__naked void invalid_and_of_negative_number(void)
28+
{
29+
asm volatile (" \
30+
r1 = 0; \
31+
*(u64*)(r10 - 8) = r1; \
32+
r2 = r10; \
33+
r2 += -8; \
34+
r1 = %[map_hash_48b] ll; \
35+
call %[bpf_map_lookup_elem]; \
36+
if r0 == 0 goto l0_%=; \
37+
r1 = *(u8*)(r0 + 0); \
38+
r1 &= -4; \
39+
r1 <<= 2; \
40+
r0 += r1; \
41+
l0_%=: r1 = %[test_val_foo]; \
42+
*(u64*)(r0 + 0) = r1; \
43+
exit; \
44+
" :
45+
: __imm(bpf_map_lookup_elem),
46+
__imm_addr(map_hash_48b),
47+
__imm_const(test_val_foo, offsetof(struct test_val, foo))
48+
: __clobber_all);
49+
}
50+
51+
SEC("socket")
52+
__description("invalid range check")
53+
__failure __msg("R0 max value is outside of the allowed memory range")
54+
__failure_unpriv
55+
__flag(BPF_F_ANY_ALIGNMENT)
56+
__naked void invalid_range_check(void)
57+
{
58+
asm volatile (" \
59+
r1 = 0; \
60+
*(u64*)(r10 - 8) = r1; \
61+
r2 = r10; \
62+
r2 += -8; \
63+
r1 = %[map_hash_48b] ll; \
64+
call %[bpf_map_lookup_elem]; \
65+
if r0 == 0 goto l0_%=; \
66+
r1 = *(u32*)(r0 + 0); \
67+
r9 = 1; \
68+
w1 %%= 2; \
69+
w1 += 1; \
70+
w9 &= w1; \
71+
w9 += 1; \
72+
w9 >>= 1; \
73+
w3 = 1; \
74+
w3 -= w9; \
75+
w3 *= 0x10000000; \
76+
r0 += r3; \
77+
*(u32*)(r0 + 0) = r3; \
78+
l0_%=: r0 = r0; \
79+
exit; \
80+
" :
81+
: __imm(bpf_map_lookup_elem),
82+
__imm_addr(map_hash_48b)
83+
: __clobber_all);
84+
}
85+
86+
SEC("socket")
87+
__description("check known subreg with unknown reg")
88+
__success __failure_unpriv __msg_unpriv("R1 !read_ok")
89+
__retval(0)
90+
__naked void known_subreg_with_unknown_reg(void)
91+
{
92+
asm volatile (" \
93+
call %[bpf_get_prandom_u32]; \
94+
r0 <<= 32; \
95+
r0 += 1; \
96+
r0 &= 0xFFFF1234; \
97+
/* Upper bits are unknown but AND above masks out 1 zero'ing lower bits */\
98+
if w0 < 1 goto l0_%=; \
99+
r1 = *(u32*)(r1 + 512); \
100+
l0_%=: r0 = 0; \
101+
exit; \
102+
" :
103+
: __imm(bpf_get_prandom_u32)
104+
: __clobber_all);
105+
}
106+
107+
char _license[] SEC("license") = "GPL";

0 commit comments

Comments
 (0)