selftests/bpf: detect testing prog flags support
authorAndrii Nakryiko <andrii@kernel.org>
Tue, 9 Jan 2024 23:17:38 +0000 (15:17 -0800)
committerAlexei Starovoitov <ast@kernel.org>
Tue, 23 Jan 2024 22:40:22 +0000 (14:40 -0800)
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>
tools/testing/selftests/bpf/prog_tests/bpf_verif_scale.c
tools/testing/selftests/bpf/prog_tests/reg_bounds.c
tools/testing/selftests/bpf/test_loader.c
tools/testing/selftests/bpf/test_sock_addr.c
tools/testing/selftests/bpf/test_verifier.c
tools/testing/selftests/bpf/testing_helpers.c
tools/testing/selftests/bpf/testing_helpers.h

index e770912fc1d24472984ca84aad452d76cfcbf981..4c6ada5b270b240b6038c6d2ded0d7e3190105e3 100644 (file)
@@ -35,7 +35,7 @@ static int check_load(const char *file, enum bpf_prog_type type)
        }
 
        bpf_program__set_type(prog, type);
-       bpf_program__set_flags(prog, BPF_F_TEST_RND_HI32 | BPF_F_TEST_REG_INVARIANTS);
+       bpf_program__set_flags(prog, testing_prog_flags());
        bpf_program__set_log_level(prog, 4 | extra_prog_load_log_flags);
 
        err = bpf_object__load(obj);
index 820d0bcfc474d9b399ab6d1371e999fc70a5a8de..eb74363f9f701edbf318e86035fde77e799a1f7a 100644 (file)
@@ -840,7 +840,7 @@ static int load_range_cmp_prog(struct range x, struct range y, enum op op,
                .log_level = 2,
                .log_buf = log_buf,
                .log_size = log_sz,
-               .prog_flags = BPF_F_TEST_REG_INVARIANTS,
+               .prog_flags = testing_prog_flags(),
        );
 
        /* ; skip exit block below
index 72906d27babff2ba9b0e676b302f94aeaa66c36f..ba57601c2a4d5b98fdf5513812efab6f40c389c5 100644 (file)
@@ -181,7 +181,7 @@ static int parse_test_spec(struct test_loader *tester,
        memset(spec, 0, sizeof(*spec));
 
        spec->prog_name = bpf_program__name(prog);
-       spec->prog_flags = BPF_F_TEST_REG_INVARIANTS; /* by default be strict */
+       spec->prog_flags = testing_prog_flags();
 
        btf = bpf_object__btf(obj);
        if (!btf) {
index b0068a9d2cfe9ece70ac434daa3e25cafa32beed..80c42583f5977e49a8ebe0145ef84347e7fe909f 100644 (file)
@@ -19,6 +19,7 @@
 #include <bpf/libbpf.h>
 
 #include "cgroup_helpers.h"
+#include "testing_helpers.h"
 #include "bpf_util.h"
 
 #ifndef ENOTSUPP
@@ -679,7 +680,7 @@ static int load_path(const struct sock_addr_test *test, const char *path)
 
        bpf_program__set_type(prog, BPF_PROG_TYPE_CGROUP_SOCK_ADDR);
        bpf_program__set_expected_attach_type(prog, test->expected_attach_type);
-       bpf_program__set_flags(prog, BPF_F_TEST_RND_HI32 | BPF_F_TEST_REG_INVARIANTS);
+       bpf_program__set_flags(prog, testing_prog_flags());
 
        err = bpf_object__load(obj);
        if (err) {
index 87519d7fe4c62a3b1cfc881e4d7e3d3a410bef08..1a09fc34d093a639844e16a098ac0e1f23703bd5 100644 (file)
@@ -1545,7 +1545,7 @@ static void do_test_single(struct bpf_test *test, bool unpriv,
        if (fixup_skips != skips)
                return;
 
-       pflags = BPF_F_TEST_RND_HI32 | BPF_F_TEST_REG_INVARIANTS;
+       pflags = testing_prog_flags();
        if (test->flags & F_LOAD_WITH_STRICT_ALIGNMENT)
                pflags |= BPF_F_STRICT_ALIGNMENT;
        if (test->flags & F_NEEDS_EFFICIENT_UNALIGNED_ACCESS)
index 53c40f62fdcb8ecaa4234a8c6eca4cfd965610c4..106ef05586b8fe80e6c6cac2e3bbb46b921c010d 100644 (file)
@@ -252,6 +252,34 @@ __u32 link_info_prog_id(const struct bpf_link *link, struct bpf_link_info *info)
 
 int extra_prog_load_log_flags = 0;
 
+int testing_prog_flags(void)
+{
+       static int cached_flags = -1;
+       static int prog_flags[] = { BPF_F_TEST_RND_HI32, BPF_F_TEST_REG_INVARIANTS };
+       static struct bpf_insn insns[] = {
+               BPF_MOV64_IMM(BPF_REG_0, 0),
+               BPF_EXIT_INSN(),
+       };
+       int insn_cnt = ARRAY_SIZE(insns), i, fd, flags = 0;
+       LIBBPF_OPTS(bpf_prog_load_opts, opts);
+
+       if (cached_flags >= 0)
+               return cached_flags;
+
+       for (i = 0; i < ARRAY_SIZE(prog_flags); i++) {
+               opts.prog_flags = prog_flags[i];
+               fd = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, "flag-test", "GPL",
+                                  insns, insn_cnt, &opts);
+               if (fd >= 0) {
+                       flags |= prog_flags[i];
+                       close(fd);
+               }
+       }
+
+       cached_flags = flags;
+       return cached_flags;
+}
+
 int bpf_prog_test_load(const char *file, enum bpf_prog_type type,
                       struct bpf_object **pobj, int *prog_fd)
 {
@@ -276,7 +304,7 @@ int bpf_prog_test_load(const char *file, enum bpf_prog_type type,
        if (type != BPF_PROG_TYPE_UNSPEC && bpf_program__type(prog) != type)
                bpf_program__set_type(prog, type);
 
-       flags = bpf_program__flags(prog) | BPF_F_TEST_RND_HI32 | BPF_F_TEST_REG_INVARIANTS;
+       flags = bpf_program__flags(prog) | testing_prog_flags();
        bpf_program__set_flags(prog, flags);
 
        err = bpf_object__load(obj);
@@ -299,7 +327,7 @@ int bpf_test_load_program(enum bpf_prog_type type, const struct bpf_insn *insns,
 {
        LIBBPF_OPTS(bpf_prog_load_opts, opts,
                .kern_version = kern_version,
-               .prog_flags = BPF_F_TEST_RND_HI32 | BPF_F_TEST_REG_INVARIANTS,
+               .prog_flags = testing_prog_flags(),
                .log_level = extra_prog_load_log_flags,
                .log_buf = log_buf,
                .log_size = log_buf_sz,
index 1ed5b9200d661da78940293978518f9159226a5b..e099aa4da611edb1edfb18ed946aed05c84236a3 100644 (file)
@@ -51,5 +51,6 @@ struct bpf_insn;
  * e.g. verifier.c:convert_ctx_access() is done.
  */
 int get_xlated_program(int fd_prog, struct bpf_insn **buf, __u32 *cnt);
+int testing_prog_flags(void);
 
 #endif /* __TESTING_HELPERS_H */