Skip to content

Commit 44e7324

Browse files
anakryikogregkh
authored andcommitted
libbpf: Fix handling of BPF arena relocations
[ Upstream commit 0238c45 ] 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]> Signed-off-by: Sasha Levin <[email protected]>
1 parent f0de970 commit 44e7324

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
@@ -726,7 +726,7 @@ struct bpf_object {
726726

727727
struct usdt_manager *usdt_man;
728728

729-
struct bpf_map *arena_map;
729+
int arena_map_idx;
730730
void *arena_data;
731731
size_t arena_data_sz;
732732

@@ -1494,6 +1494,7 @@ static struct bpf_object *bpf_object__new(const char *path,
14941494
obj->efile.obj_buf_sz = obj_buf_sz;
14951495
obj->efile.btf_maps_shndx = -1;
14961496
obj->kconfig_map_idx = -1;
1497+
obj->arena_map_idx = -1;
14971498

14981499
obj->kern_version = get_kernel_version();
14991500
obj->loaded = false;
@@ -2935,7 +2936,7 @@ static int init_arena_map_data(struct bpf_object *obj, struct bpf_map *map,
29352936
const long page_sz = sysconf(_SC_PAGE_SIZE);
29362937
size_t mmap_sz;
29372938

2938-
mmap_sz = bpf_map_mmap_sz(obj->arena_map);
2939+
mmap_sz = bpf_map_mmap_sz(map);
29392940
if (roundup(data_sz, page_sz) > mmap_sz) {
29402941
pr_warn("elf: sec '%s': declared ARENA map size (%zu) is too small to hold global __arena variables of size %zu\n",
29412942
sec_name, mmap_sz, data_sz);
@@ -3009,12 +3010,12 @@ static int bpf_object__init_user_btf_maps(struct bpf_object *obj, bool strict,
30093010
if (map->def.type != BPF_MAP_TYPE_ARENA)
30103011
continue;
30113012

3012-
if (obj->arena_map) {
3013+
if (obj->arena_map_idx >= 0) {
30133014
pr_warn("map '%s': only single ARENA map is supported (map '%s' is also ARENA)\n",
3014-
map->name, obj->arena_map->name);
3015+
map->name, obj->maps[obj->arena_map_idx].name);
30153016
return -EINVAL;
30163017
}
3017-
obj->arena_map = map;
3018+
obj->arena_map_idx = i;
30183019

30193020
if (obj->efile.arena_data) {
30203021
err = init_arena_map_data(obj, map, ARENA_SEC, obj->efile.arena_data_shndx,
@@ -3024,7 +3025,7 @@ static int bpf_object__init_user_btf_maps(struct bpf_object *obj, bool strict,
30243025
return err;
30253026
}
30263027
}
3027-
if (obj->efile.arena_data && !obj->arena_map) {
3028+
if (obj->efile.arena_data && obj->arena_map_idx < 0) {
30283029
pr_warn("elf: sec '%s': to use global __arena variables the ARENA map should be explicitly declared in SEC(\".maps\")\n",
30293030
ARENA_SEC);
30303031
return -ENOENT;
@@ -4547,8 +4548,13 @@ static int bpf_program__record_reloc(struct bpf_program *prog,
45474548
if (shdr_idx == obj->efile.arena_data_shndx) {
45484549
reloc_desc->type = RELO_DATA;
45494550
reloc_desc->insn_idx = insn_idx;
4550-
reloc_desc->map_idx = obj->arena_map - obj->maps;
4551+
reloc_desc->map_idx = obj->arena_map_idx;
45514552
reloc_desc->sym_off = sym->st_value;
4553+
4554+
map = &obj->maps[obj->arena_map_idx];
4555+
pr_debug("prog '%s': found arena map %d (%s, sec %d, off %zu) for insn %u\n",
4556+
prog->name, obj->arena_map_idx, map->name, map->sec_idx,
4557+
map->sec_offset, insn_idx);
45524558
return 0;
45534559
}
45544560

0 commit comments

Comments
 (0)