summaryrefslogtreecommitdiff
path: root/tools/lib
diff options
context:
space:
mode:
authorEmil Tsalapatis <emil@etsalapatis.com>2025-12-16 12:33:24 -0500
committerAndrii Nakryiko <andrii@kernel.org>2025-12-16 10:42:55 -0800
commitc1f61171d44b19834cf24def2cf832f2688e83df (patch)
tree18cf11094d501d14cc102959130bc61b5fe29b9e /tools/lib
parent0aa721437e4b74d737f58582f1bbf2eea3e038c7 (diff)
libbpf: Move arena globals to the end of the arena
Arena globals are currently placed at the beginning of the arena by libbpf. This is convenient, but prevents users from reserving guard pages in the beginning of the arena to identify NULL pointer dereferences. Adjust the load logic to place the globals at the end of the arena instead. Also modify bpftool to set the arena pointer in the program's BPF skeleton to point to the globals. Users now call bpf_map__initial_value() to find the beginning of the arena mapping and use the arena pointer in the skeleton to determine which part of the mapping holds the arena globals and which part is free. Suggested-by: Andrii Nakryiko <andrii@kernel.org> Signed-off-by: Emil Tsalapatis <emil@etsalapatis.com> Signed-off-by: Andrii Nakryiko <andrii@kernel.org> Acked-by: Eduard Zingerman <eddyz87@gmail.com> Link: https://lore.kernel.org/bpf/20251216173325.98465-5-emil@etsalapatis.com
Diffstat (limited to 'tools/lib')
-rw-r--r--tools/lib/bpf/libbpf.c17
1 files changed, 13 insertions, 4 deletions
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 4d4badb64824..6fba879492a8 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -757,6 +757,7 @@ struct bpf_object {
int arena_map_idx;
void *arena_data;
size_t arena_data_sz;
+ size_t arena_data_off;
void *jumptables_data;
size_t jumptables_data_sz;
@@ -2991,10 +2992,11 @@ static int init_arena_map_data(struct bpf_object *obj, struct bpf_map *map,
void *data, size_t data_sz)
{
const long page_sz = sysconf(_SC_PAGE_SIZE);
+ const size_t data_alloc_sz = roundup(data_sz, page_sz);
size_t mmap_sz;
mmap_sz = bpf_map_mmap_sz(map);
- if (roundup(data_sz, page_sz) > mmap_sz) {
+ if (data_alloc_sz > mmap_sz) {
pr_warn("elf: sec '%s': declared ARENA map size (%zu) is too small to hold global __arena variables of size %zu\n",
sec_name, mmap_sz, data_sz);
return -E2BIG;
@@ -3006,6 +3008,9 @@ 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 */
+ obj->arena_data_off = mmap_sz - data_alloc_sz;
+
/* make bpf_map__init_value() work for ARENA maps */
map->mmaped = obj->arena_data;
@@ -4663,7 +4668,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;
+ reloc_desc->sym_off = sym->st_value + obj->arena_data_off;
map = &obj->maps[obj->arena_map_idx];
pr_debug("prog '%s': found arena map %d (%s, sec %d, off %zu) for insn %u\n",
@@ -5624,7 +5629,8 @@ retry:
return err;
}
if (obj->arena_data) {
- memcpy(map->mmaped, obj->arena_data, obj->arena_data_sz);
+ memcpy(map->mmaped + obj->arena_data_off, obj->arena_data,
+ obj->arena_data_sz);
zfree(&obj->arena_data);
}
}
@@ -14429,7 +14435,10 @@ int bpf_object__load_skeleton(struct bpf_object_skeleton *s)
if (!map_skel->mmaped)
continue;
- *map_skel->mmaped = map->mmaped;
+ if (map->def.type == BPF_MAP_TYPE_ARENA)
+ *map_skel->mmaped = map->mmaped + map->obj->arena_data_off;
+ else
+ *map_skel->mmaped = map->mmaped;
}
return 0;