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>
This commit is contained in:
parent
81777efbf5
commit
56d3e44af8
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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 */
|
||||
|
Loading…
x
Reference in New Issue
Block a user