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

libbpf: Fix handling of BPF arena relocations

Initial __arena global variable support implementation in libbpf
contains a bug: it remembers struct bpf_map pointer for arena, which is
used later on to process relocations. Recording this pointer is
problematic because map pointers are not stable during ELF relocation
collection phase, as an array of struct bpf_map's can be reallocated,
invalidating all the pointers. Libbpf is dealing with similar issues by
using a stable internal map index, though for BPF arena map specifically
this approach wasn't used due to an oversight.

The resulting behavior is non-deterministic issue which depends on exact
layout of ELF object file, number of actual maps, etc. We didn't hit
this until very recently, when this bug started triggering crash in BPF
CI when validating one of sched-ext BPF programs.

The fix is rather straightforward: we just follow an established pattern
of remembering map index (just like obj->kconfig_map_idx, for example)
instead of `struct bpf_map *`, and resolving index to a pointer at the
point where map information is necessary.

While at it also add debug-level message for arena-related relocation
resolution information, which we already have for all other kinds of
maps.

Fixes: 2e7ba4f8fd1f ("libbpf: Recognize __arena global variables.")
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Tested-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/r/20250718001009.610955-1-andrii@kernel.org
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Andrii Nakryiko and committed by
Alexei Starovoitov
0238c45f 2e2713ae

+13 -7
+13 -7
tools/lib/bpf/libbpf.c
··· 735 735 736 736 struct usdt_manager *usdt_man; 737 737 738 - struct bpf_map *arena_map; 738 + int arena_map_idx; 739 739 void *arena_data; 740 740 size_t arena_data_sz; 741 741 ··· 1517 1517 obj->efile.obj_buf_sz = obj_buf_sz; 1518 1518 obj->efile.btf_maps_shndx = -1; 1519 1519 obj->kconfig_map_idx = -1; 1520 + obj->arena_map_idx = -1; 1520 1521 1521 1522 obj->kern_version = get_kernel_version(); 1522 1523 obj->state = OBJ_OPEN; ··· 2965 2964 const long page_sz = sysconf(_SC_PAGE_SIZE); 2966 2965 size_t mmap_sz; 2967 2966 2968 - mmap_sz = bpf_map_mmap_sz(obj->arena_map); 2967 + mmap_sz = bpf_map_mmap_sz(map); 2969 2968 if (roundup(data_sz, page_sz) > mmap_sz) { 2970 2969 pr_warn("elf: sec '%s': declared ARENA map size (%zu) is too small to hold global __arena variables of size %zu\n", 2971 2970 sec_name, mmap_sz, data_sz); ··· 3039 3038 if (map->def.type != BPF_MAP_TYPE_ARENA) 3040 3039 continue; 3041 3040 3042 - if (obj->arena_map) { 3041 + if (obj->arena_map_idx >= 0) { 3043 3042 pr_warn("map '%s': only single ARENA map is supported (map '%s' is also ARENA)\n", 3044 - map->name, obj->arena_map->name); 3043 + map->name, obj->maps[obj->arena_map_idx].name); 3045 3044 return -EINVAL; 3046 3045 } 3047 - obj->arena_map = map; 3046 + obj->arena_map_idx = i; 3048 3047 3049 3048 if (obj->efile.arena_data) { 3050 3049 err = init_arena_map_data(obj, map, ARENA_SEC, obj->efile.arena_data_shndx, ··· 3054 3053 return err; 3055 3054 } 3056 3055 } 3057 - if (obj->efile.arena_data && !obj->arena_map) { 3056 + if (obj->efile.arena_data && obj->arena_map_idx < 0) { 3058 3057 pr_warn("elf: sec '%s': to use global __arena variables the ARENA map should be explicitly declared in SEC(\".maps\")\n", 3059 3058 ARENA_SEC); 3060 3059 return -ENOENT; ··· 4584 4583 if (shdr_idx == obj->efile.arena_data_shndx) { 4585 4584 reloc_desc->type = RELO_DATA; 4586 4585 reloc_desc->insn_idx = insn_idx; 4587 - reloc_desc->map_idx = obj->arena_map - obj->maps; 4586 + reloc_desc->map_idx = obj->arena_map_idx; 4588 4587 reloc_desc->sym_off = sym->st_value; 4588 + 4589 + map = &obj->maps[obj->arena_map_idx]; 4590 + pr_debug("prog '%s': found arena map %d (%s, sec %d, off %zu) for insn %u\n", 4591 + prog->name, obj->arena_map_idx, map->name, map->sec_idx, 4592 + map->sec_offset, insn_idx); 4589 4593 return 0; 4590 4594 } 4591 4595