Skip to content

Commit 0238c45

Browse files
anakryikoAlexei Starovoitov
authored andcommitted
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: 2e7ba4f ("libbpf: Recognize __arena global variables.") Signed-off-by: Andrii Nakryiko <[email protected]> Tested-by: Eduard Zingerman <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexei Starovoitov <[email protected]>
1 parent 2e2713a commit 0238c45

File tree

1 file changed

+13
-7
lines changed

1 file changed

+13
-7
lines changed

tools/lib/bpf/libbpf.c

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -735,7 +735,7 @@ struct bpf_object {
735735

736736
struct usdt_manager *usdt_man;
737737

738-
struct bpf_map *arena_map;
738+
int arena_map_idx;
739739
void *arena_data;
740740
size_t arena_data_sz;
741741

@@ -1517,6 +1517,7 @@ static struct bpf_object *bpf_object__new(const char *path,
15171517
obj->efile.obj_buf_sz = obj_buf_sz;
15181518
obj->efile.btf_maps_shndx = -1;
15191519
obj->kconfig_map_idx = -1;
1520+
obj->arena_map_idx = -1;
15201521

15211522
obj->kern_version = get_kernel_version();
15221523
obj->state = OBJ_OPEN;
@@ -2964,7 +2965,7 @@ static int init_arena_map_data(struct bpf_object *obj, struct bpf_map *map,
29642965
const long page_sz = sysconf(_SC_PAGE_SIZE);
29652966
size_t mmap_sz;
29662967

2967-
mmap_sz = bpf_map_mmap_sz(obj->arena_map);
2968+
mmap_sz = bpf_map_mmap_sz(map);
29682969
if (roundup(data_sz, page_sz) > mmap_sz) {
29692970
pr_warn("elf: sec '%s': declared ARENA map size (%zu) is too small to hold global __arena variables of size %zu\n",
29702971
sec_name, mmap_sz, data_sz);
@@ -3038,12 +3039,12 @@ static int bpf_object__init_user_btf_maps(struct bpf_object *obj, bool strict,
30383039
if (map->def.type != BPF_MAP_TYPE_ARENA)
30393040
continue;
30403041

3041-
if (obj->arena_map) {
3042+
if (obj->arena_map_idx >= 0) {
30423043
pr_warn("map '%s': only single ARENA map is supported (map '%s' is also ARENA)\n",
3043-
map->name, obj->arena_map->name);
3044+
map->name, obj->maps[obj->arena_map_idx].name);
30443045
return -EINVAL;
30453046
}
3046-
obj->arena_map = map;
3047+
obj->arena_map_idx = i;
30473048

30483049
if (obj->efile.arena_data) {
30493050
err = init_arena_map_data(obj, map, ARENA_SEC, obj->efile.arena_data_shndx,
@@ -3053,7 +3054,7 @@ static int bpf_object__init_user_btf_maps(struct bpf_object *obj, bool strict,
30533054
return err;
30543055
}
30553056
}
3056-
if (obj->efile.arena_data && !obj->arena_map) {
3057+
if (obj->efile.arena_data && obj->arena_map_idx < 0) {
30573058
pr_warn("elf: sec '%s': to use global __arena variables the ARENA map should be explicitly declared in SEC(\".maps\")\n",
30583059
ARENA_SEC);
30593060
return -ENOENT;
@@ -4583,8 +4584,13 @@ static int bpf_program__record_reloc(struct bpf_program *prog,
45834584
if (shdr_idx == obj->efile.arena_data_shndx) {
45844585
reloc_desc->type = RELO_DATA;
45854586
reloc_desc->insn_idx = insn_idx;
4586-
reloc_desc->map_idx = obj->arena_map - obj->maps;
4587+
reloc_desc->map_idx = obj->arena_map_idx;
45874588
reloc_desc->sym_off = sym->st_value;
4589+
4590+
map = &obj->maps[obj->arena_map_idx];
4591+
pr_debug("prog '%s': found arena map %d (%s, sec %d, off %zu) for insn %u\n",
4592+
prog->name, obj->arena_map_idx, map->name, map->sec_idx,
4593+
map->sec_offset, insn_idx);
45884594
return 0;
45894595
}
45904596

0 commit comments

Comments
 (0)