From: Yuan Chen <[email protected]> Feature probes (FEAT_GLOBAL_DATA, FEAT_PROG_NAME, etc.) hardcode SOCKET_FILTER or TRACEPOINT as the program type for their test loads. When a BPF token restricts program types, these loads fail and the features are incorrectly reported as missing.
Fetch the first probeable program type from the token's allowed_progs mask. A new helper, token_probeable_prog_type(), queries the token and returns the first match from an 18-type list of program types known to accept trivial "return 0" programs without specific expected_attach_type. Types requiring expected_attach_type (CGROUP_SOCK, CGROUP_SOCK_ADDR, LWT_*, NETFILTER, etc.) are intentionally excluded. Without a token, defaults to SOCKET_FILTER. When the token has no probeable type (e.g. only STRUCT_OPS), conservatively assume the feature is supported: token creation proves the BPF subsystem works, and real issues will be caught during actual program/map loading. Signed-off-by: Yuan Chen <[email protected]> --- tools/lib/bpf/features.c | 97 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 89 insertions(+), 8 deletions(-) diff --git a/tools/lib/bpf/features.c b/tools/lib/bpf/features.c index b7e388f99d0b..f008ee50e246 100644 --- a/tools/lib/bpf/features.c +++ b/tools/lib/bpf/features.c @@ -19,6 +19,57 @@ int probe_fd(int fd) return fd >= 0; } +/* Fetch the first program type from the token that can be used for + * feature probes. Only a few common types are checked that are known + * to accept a trivial "return 0" program. Returns the type on success, + * -EINVAL if the token has no probeable type. + */ +static int token_probeable_prog_type(int token_fd) +{ + /* Types that accept a simple "return 0" probe program */ + /* Types that accept a trivial "return 0" program without + * specific expected_attach_type. Types requiring expected_attach_type + * (CGROUP_SOCK, CGROUP_SOCK_ADDR, LWT_*, NETFILTER) are excluded. + */ + static const int probeable[] = { + BPF_PROG_TYPE_SOCKET_FILTER, + BPF_PROG_TYPE_KPROBE, + BPF_PROG_TYPE_SCHED_CLS, + BPF_PROG_TYPE_SCHED_ACT, + BPF_PROG_TYPE_TRACEPOINT, + BPF_PROG_TYPE_XDP, + BPF_PROG_TYPE_PERF_EVENT, + BPF_PROG_TYPE_CGROUP_SKB, + BPF_PROG_TYPE_SOCK_OPS, + BPF_PROG_TYPE_SK_SKB, + BPF_PROG_TYPE_CGROUP_DEVICE, + BPF_PROG_TYPE_SK_MSG, + BPF_PROG_TYPE_RAW_TRACEPOINT, + BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE, + BPF_PROG_TYPE_CGROUP_SOCKOPT, + BPF_PROG_TYPE_CGROUP_SYSCTL, + BPF_PROG_TYPE_FLOW_DISSECTOR, + BPF_PROG_TYPE_SK_LOOKUP, + }; + struct bpf_token_info info = {}; + __u32 info_len = sizeof(info); + int i, err; + + if (!token_fd) + return BPF_PROG_TYPE_SOCKET_FILTER; + + err = bpf_obj_get_info_by_fd(token_fd, &info, &info_len); + if (err) + return -errno; + + for (i = 0; i < ARRAY_SIZE(probeable); i++) { + if (info.allowed_progs & (1ULL << probeable[i])) + return probeable[i]; + } + + return -EINVAL; +} + static int probe_kern_prog_name(int token_fd) { const size_t attr_sz = offsetofend(union bpf_attr, prog_token_fd); @@ -27,10 +78,14 @@ static int probe_kern_prog_name(int token_fd) BPF_EXIT_INSN(), }; union bpf_attr attr; - int ret; + int ret, prog_type; + + prog_type = token_probeable_prog_type(token_fd); + if (prog_type < 0) + return 1; memset(&attr, 0, attr_sz); - attr.prog_type = BPF_PROG_TYPE_SOCKET_FILTER; + attr.prog_type = prog_type; attr.license = ptr_to_u64("GPL"); attr.insns = ptr_to_u64(insns); attr.insn_cnt = (__u32)ARRAY_SIZE(insns); @@ -61,6 +116,7 @@ static int probe_kern_global_data(int token_fd) .prog_flags = token_fd ? BPF_F_TOKEN_FD : 0, ); int ret, map, insn_cnt = ARRAY_SIZE(insns); + int prog_type; map = bpf_map_create(BPF_MAP_TYPE_ARRAY, "libbpf_global", sizeof(int), 32, 1, &map_opts); if (map < 0) { @@ -72,7 +128,12 @@ static int probe_kern_global_data(int token_fd) insns[0].imm = map; - ret = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, NULL, "GPL", insns, insn_cnt, &prog_opts); + prog_type = token_probeable_prog_type(token_fd); + if (prog_type < 0) { + close(map); + return 1; + } + ret = bpf_prog_load(prog_type, NULL, "GPL", insns, insn_cnt, &prog_opts); close(map); return probe_fd(ret); } @@ -257,8 +318,13 @@ static int probe_kern_probe_read_kernel(int token_fd) BPF_EXIT_INSN(), }; int fd, insn_cnt = ARRAY_SIZE(insns); + int prog_type; - fd = bpf_prog_load(BPF_PROG_TYPE_TRACEPOINT, NULL, "GPL", insns, insn_cnt, &opts); + prog_type = token_probeable_prog_type(token_fd); + if (prog_type < 0) + return 1; + + fd = bpf_prog_load(prog_type, NULL, "GPL", insns, insn_cnt, &opts); return probe_fd(fd); } @@ -277,6 +343,7 @@ static int probe_prog_bind_map(int token_fd) .prog_flags = token_fd ? BPF_F_TOKEN_FD : 0, ); int ret, map, prog, insn_cnt = ARRAY_SIZE(insns); + int prog_type; map = bpf_map_create(BPF_MAP_TYPE_ARRAY, "libbpf_det_bind", sizeof(int), 32, 1, &map_opts); if (map < 0) { @@ -286,7 +353,12 @@ static int probe_prog_bind_map(int token_fd) return ret; } - prog = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, NULL, "GPL", insns, insn_cnt, &prog_opts); + prog = prog_type = token_probeable_prog_type(token_fd); + if (prog_type < 0) { + close(map); + return 1; + } + prog = bpf_prog_load(prog_type, NULL, "GPL", insns, insn_cnt, &prog_opts); if (prog < 0) { close(map); return 0; @@ -435,8 +507,13 @@ static int probe_kern_bpf_cookie(int token_fd) .prog_flags = token_fd ? BPF_F_TOKEN_FD : 0, ); int ret, insn_cnt = ARRAY_SIZE(insns); + int prog_type; - ret = bpf_prog_load(BPF_PROG_TYPE_TRACEPOINT, NULL, "GPL", insns, insn_cnt, &opts); + prog_type = token_probeable_prog_type(token_fd); + if (prog_type < 0) + return 1; + + ret = bpf_prog_load(prog_type, NULL, "GPL", insns, insn_cnt, &opts); return probe_fd(ret); } @@ -509,7 +586,7 @@ static int probe_kern_arg_ctx_tag(int token_fd) static int probe_ldimm64_full_range_off(int token_fd) { char log_buf[1024]; - int prog_fd, map_fd; + int prog_fd, map_fd, prog_type; int ret; LIBBPF_OPTS(bpf_map_create_opts, map_opts, .token_fd = token_fd, @@ -527,6 +604,10 @@ static int probe_ldimm64_full_range_off(int token_fd) }; int insn_cnt = ARRAY_SIZE(insns); + prog_type = token_probeable_prog_type(token_fd); + if (prog_type < 0) + return 1; + map_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, "arr", sizeof(int), 1, 1, &map_opts); if (map_fd < 0) { ret = -errno; @@ -537,7 +618,7 @@ static int probe_ldimm64_full_range_off(int token_fd) insns[0].imm = map_fd; log_buf[0] = '\0'; - prog_fd = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, "global_reloc", "GPL", insns, insn_cnt, &prog_opts); + prog_fd = bpf_prog_load(prog_type, "global_reloc", "GPL", insns, insn_cnt, &prog_opts); ret = -errno; close(map_fd); -- 2.54.0
