Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/bpf: detect testing prog flags support

Various tests specify extra testing prog_flags when loading BPF
programs, like BPF_F_TEST_RND_HI32, and more recently also
BPF_F_TEST_REG_INVARIANTS. While BPF_F_TEST_RND_HI32 is old enough to
not cause much problem on older kernels, BPF_F_TEST_REG_INVARIANTS is
very fresh and unconditionally specifying it causes selftests to fail on
even slightly outdated kernels.

This breaks libbpf CI test against 4.9 and 5.15 kernels, it can break
some local development (done outside of VM), etc.

To prevent this, and guard against similar problems in the future, do
runtime detection of supported "testing flags", and only provide those
that host kernel recognizes.

Acked-by: Song Liu <song@kernel.org>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/r/20240109231738.575844-1-andrii@kernel.org
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Andrii Nakryiko and committed by
Alexei Starovoitov
56d3e44a 81777efb

+37 -7
+1 -1
tools/testing/selftests/bpf/prog_tests/bpf_verif_scale.c
··· 35 35 } 36 36 37 37 bpf_program__set_type(prog, type); 38 - bpf_program__set_flags(prog, BPF_F_TEST_RND_HI32 | BPF_F_TEST_REG_INVARIANTS); 38 + bpf_program__set_flags(prog, testing_prog_flags()); 39 39 bpf_program__set_log_level(prog, 4 | extra_prog_load_log_flags); 40 40 41 41 err = bpf_object__load(obj);
+1 -1
tools/testing/selftests/bpf/prog_tests/reg_bounds.c
··· 840 840 .log_level = 2, 841 841 .log_buf = log_buf, 842 842 .log_size = log_sz, 843 - .prog_flags = BPF_F_TEST_REG_INVARIANTS, 843 + .prog_flags = testing_prog_flags(), 844 844 ); 845 845 846 846 /* ; skip exit block below
+1 -1
tools/testing/selftests/bpf/test_loader.c
··· 181 181 memset(spec, 0, sizeof(*spec)); 182 182 183 183 spec->prog_name = bpf_program__name(prog); 184 - spec->prog_flags = BPF_F_TEST_REG_INVARIANTS; /* by default be strict */ 184 + spec->prog_flags = testing_prog_flags(); 185 185 186 186 btf = bpf_object__btf(obj); 187 187 if (!btf) {
+2 -1
tools/testing/selftests/bpf/test_sock_addr.c
··· 19 19 #include <bpf/libbpf.h> 20 20 21 21 #include "cgroup_helpers.h" 22 + #include "testing_helpers.h" 22 23 #include "bpf_util.h" 23 24 24 25 #ifndef ENOTSUPP ··· 680 679 681 680 bpf_program__set_type(prog, BPF_PROG_TYPE_CGROUP_SOCK_ADDR); 682 681 bpf_program__set_expected_attach_type(prog, test->expected_attach_type); 683 - bpf_program__set_flags(prog, BPF_F_TEST_RND_HI32 | BPF_F_TEST_REG_INVARIANTS); 682 + bpf_program__set_flags(prog, testing_prog_flags()); 684 683 685 684 err = bpf_object__load(obj); 686 685 if (err) {
+1 -1
tools/testing/selftests/bpf/test_verifier.c
··· 1545 1545 if (fixup_skips != skips) 1546 1546 return; 1547 1547 1548 - pflags = BPF_F_TEST_RND_HI32 | BPF_F_TEST_REG_INVARIANTS; 1548 + pflags = testing_prog_flags(); 1549 1549 if (test->flags & F_LOAD_WITH_STRICT_ALIGNMENT) 1550 1550 pflags |= BPF_F_STRICT_ALIGNMENT; 1551 1551 if (test->flags & F_NEEDS_EFFICIENT_UNALIGNED_ACCESS)
+30 -2
tools/testing/selftests/bpf/testing_helpers.c
··· 252 252 253 253 int extra_prog_load_log_flags = 0; 254 254 255 + int testing_prog_flags(void) 256 + { 257 + static int cached_flags = -1; 258 + static int prog_flags[] = { BPF_F_TEST_RND_HI32, BPF_F_TEST_REG_INVARIANTS }; 259 + static struct bpf_insn insns[] = { 260 + BPF_MOV64_IMM(BPF_REG_0, 0), 261 + BPF_EXIT_INSN(), 262 + }; 263 + int insn_cnt = ARRAY_SIZE(insns), i, fd, flags = 0; 264 + LIBBPF_OPTS(bpf_prog_load_opts, opts); 265 + 266 + if (cached_flags >= 0) 267 + return cached_flags; 268 + 269 + for (i = 0; i < ARRAY_SIZE(prog_flags); i++) { 270 + opts.prog_flags = prog_flags[i]; 271 + fd = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, "flag-test", "GPL", 272 + insns, insn_cnt, &opts); 273 + if (fd >= 0) { 274 + flags |= prog_flags[i]; 275 + close(fd); 276 + } 277 + } 278 + 279 + cached_flags = flags; 280 + return cached_flags; 281 + } 282 + 255 283 int bpf_prog_test_load(const char *file, enum bpf_prog_type type, 256 284 struct bpf_object **pobj, int *prog_fd) 257 285 { ··· 304 276 if (type != BPF_PROG_TYPE_UNSPEC && bpf_program__type(prog) != type) 305 277 bpf_program__set_type(prog, type); 306 278 307 - flags = bpf_program__flags(prog) | BPF_F_TEST_RND_HI32 | BPF_F_TEST_REG_INVARIANTS; 279 + flags = bpf_program__flags(prog) | testing_prog_flags(); 308 280 bpf_program__set_flags(prog, flags); 309 281 310 282 err = bpf_object__load(obj); ··· 327 299 { 328 300 LIBBPF_OPTS(bpf_prog_load_opts, opts, 329 301 .kern_version = kern_version, 330 - .prog_flags = BPF_F_TEST_RND_HI32 | BPF_F_TEST_REG_INVARIANTS, 302 + .prog_flags = testing_prog_flags(), 331 303 .log_level = extra_prog_load_log_flags, 332 304 .log_buf = log_buf, 333 305 .log_size = log_buf_sz,
+1
tools/testing/selftests/bpf/testing_helpers.h
··· 51 51 * e.g. verifier.c:convert_ctx_access() is done. 52 52 */ 53 53 int get_xlated_program(int fd_prog, struct bpf_insn **buf, __u32 *cnt); 54 + int testing_prog_flags(void); 54 55 55 56 #endif /* __TESTING_HELPERS_H */