Commit 728ff167910e uses a PROG_TYPE_TRACEPOINT BPF test program to check whether the running kernel supports large LDIMM64 offsets. The feature gate incorrectly assumes that the program will fail at verification time with one of two messages, depending on whether the feature is supported by the running kernel. However, PROG_TYPE_TRACEPOINT programs may fail to load before verification even starts, e.g., if the shell does not have the appropriate capabilities. Use a BPF_PROG_TYPE_SOCKET_FILTER program for the feature gate instead. Also fix two minor issues. First, ensure the log buffer for the test is initialized: Failing program load before verification led to libbpf dumping uninitialized data to stdout. Also, ensure that close() is only called for program_fd in the probe if the program load actually succeeded. The call was currently failing silently with -EBADF most of the time. Reported-by: Alexei Starovoitov Fixes: 728ff167910e ("libbpf: Add gating for arena globals relocation feature") Signed-off-by: Emil Tsalapatis --- tools/lib/bpf/features.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tools/lib/bpf/features.c b/tools/lib/bpf/features.c index b65ab109e3ff..7d24b99a61fa 100644 --- a/tools/lib/bpf/features.c +++ b/tools/lib/bpf/features.c @@ -527,6 +527,12 @@ static int probe_ldimm64_full_range_off(int token_fd) }; int insn_cnt = ARRAY_SIZE(insns); + /* + * Ensure the log is NUL-terminated even if we fail to start + * verification. + */ + log_buf[0] = '\0'; + map_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, "arr", sizeof(int), 1, 1, &map_opts); if (map_fd < 0) { ret = -errno; @@ -536,14 +542,14 @@ static int probe_ldimm64_full_range_off(int token_fd) } insns[0].imm = map_fd; - prog_fd = bpf_prog_load(BPF_PROG_TYPE_TRACEPOINT, "global_reloc", "GPL", insns, insn_cnt, &prog_opts); + prog_fd = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, "global_reloc", "GPL", insns, insn_cnt, &prog_opts); ret = -errno; close(map_fd); - close(prog_fd); if (prog_fd >= 0) { pr_warn("Error in %s(): Program loading unexpectedly succeeded.\n", __func__); + close(prog_fd); return -EINVAL; } -- 2.49.0 Commit 728ff167910e ("libbpf: Add gating for arena globals relocation feature") adds a feature gate check that loads a map and BPF program to test the running kernel supports large direct offsets for LDIMM64 instructions. This check is currently used to calculate arena symbol offsets during bpf_object__collect_relos, itself called by bpf_object_open. However, the program calling bpf_object_open may not have the permissions to load maps and programs. This is the case with the BPF selftests, where bpftool is invoked at compilation time during skeleton generation. This causes errors as the feature gate unexpectedly fails with -EPERM. Avoid this by moving all the use of the FEAT_LDIMM64_FULL_RANGE_OFF feature gate to BPF object preparation time instead. Fixes: 728ff167910e ("libbpf: Add gating for arena globals relocation feature") Signed-off-by: Emil Tsalapatis --- tools/lib/bpf/libbpf.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 93e59ed8d9a1..fa2da486124e 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -3009,12 +3009,6 @@ static int init_arena_map_data(struct bpf_object *obj, struct bpf_map *map, memcpy(obj->arena_data, data, data_sz); obj->arena_data_sz = data_sz; - /* place globals at the end of the arena (if supported) */ - if (kernel_supports(obj, FEAT_LDIMM64_FULL_RANGE_OFF)) - obj->arena_data_off = mmap_sz - data_alloc_sz; - else - obj->arena_data_off = 0; - /* make bpf_map__init_value() work for ARENA maps */ map->mmaped = obj->arena_data; @@ -4672,7 +4666,7 @@ static int bpf_program__record_reloc(struct bpf_program *prog, reloc_desc->type = RELO_DATA; reloc_desc->insn_idx = insn_idx; reloc_desc->map_idx = obj->arena_map_idx; - reloc_desc->sym_off = sym->st_value + obj->arena_data_off; + reloc_desc->sym_off = sym->st_value; map = &obj->maps[obj->arena_map_idx]; pr_debug("prog '%s': found arena map %d (%s, sec %d, off %zu) for insn %u\n", @@ -6386,6 +6380,10 @@ bpf_object__relocate_data(struct bpf_object *obj, struct bpf_program *prog) case RELO_DATA: map = &obj->maps[relo->map_idx]; insn[1].imm = insn[0].imm + relo->sym_off; + + if (relo->map_idx == obj->arena_map_idx) + insn[1].imm += obj->arena_data_off; + if (obj->gen_loader) { insn[0].src_reg = BPF_PSEUDO_MAP_IDX_VALUE; insn[0].imm = relo->map_idx; @@ -7373,6 +7371,7 @@ static int bpf_program_fixup_func_info(struct bpf_object *obj, struct bpf_progra static int bpf_object__relocate(struct bpf_object *obj, const char *targ_btf_path) { + struct bpf_map *arena_map; struct bpf_program *prog; size_t i, j; int err; @@ -7387,6 +7386,19 @@ static int bpf_object__relocate(struct bpf_object *obj, const char *targ_btf_pat bpf_object__sort_relos(obj); } + if (obj->arena_map_idx >= 0) { + arena_map = &obj->maps[obj->arena_map_idx]; + + /* + * Only relocate the globals to the end of the arena + * if the kernel supports it. The field is 0 by default. + */ + if (kernel_supports(obj, FEAT_LDIMM64_FULL_RANGE_OFF)) { + obj->arena_data_off = bpf_map_mmap_sz(arena_map) - + roundup(obj->arena_data_sz, sysconf(_SC_PAGE_SIZE)); + } + } + /* Before relocating calls pre-process relocations and mark * few ld_imm64 instructions that points to subprogs. * Otherwise bpf_object__reloc_code() later would have to consider -- 2.49.0