libbpf: Defer arena map size check to load time

init_arena_map_data() used the build-host page size while it opened an
object. This could reject skeleton generation when the build host and
target use different page sizes.

Validate the size during load, before libbpf calculates the arena data
offset. This uses the running kernel page size and rejects an
undersized map before relocation.

This problem manifested when cross compiling BPF selftests for
arm64 (64K page) on x86 (4K page). In this setup skeleton generation
fails.

Signed-off-by: Mykyta Yatsenko <yatsenko@meta.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com>
Link: https://lore.kernel.org/bpf/20260908-libbpf_arena_thing-v1-1-0092c0e0d91b@meta.com
This commit is contained in:
Mykyta Yatsenko authored and Andrii Nakryiko committed 2026-10-02 05:41:50 -07:00
1 parent b9c8ceca9c
commit 4ea184df98
1 file changed
+13 -18
+13 -18
View File
@@ -3018,20 +3018,8 @@ static int bpf_object__init_user_btf_map(struct bpf_object *obj,
}
static int init_arena_map_data(struct bpf_object *obj, struct bpf_map *map,
const char *sec_name, int sec_idx,
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 (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;
}
obj->arena_data = malloc(data_sz);
if (!obj->arena_data)
return -ENOMEM;
@@ -3107,8 +3095,7 @@ static int bpf_object__init_user_btf_maps(struct bpf_object *obj, bool strict,
obj->arena_map_idx = i;
if (obj->efile.arena_data) {
err = init_arena_map_data(obj, map, ARENA_SEC, obj->efile.arena_data_shndx,
obj->efile.arena_data->d_buf,
err = init_arena_map_data(obj, map, obj->efile.arena_data->d_buf,
obj->efile.arena_data->d_size);
if (err)
return err;
@@ -7489,12 +7476,20 @@ static int bpf_object__relocate(struct bpf_object *obj, const char *targ_btf_pat
bpf_object__sort_relos(obj);
}
/* place globals at the end of the arena (if supported) */
if (obj->arena_map_idx >= 0 && kernel_supports(obj, FEAT_LDIMM64_FULL_RANGE_OFF)) {
if (obj->arena_map_idx >= 0) {
struct bpf_map *arena_map = &obj->maps[obj->arena_map_idx];
size_t data_sz = roundup(obj->arena_data_sz, sysconf(_SC_PAGE_SIZE));
size_t mmap_sz = bpf_map_mmap_sz(arena_map);
obj->arena_data_off = bpf_map_mmap_sz(arena_map) -
roundup(obj->arena_data_sz, sysconf(_SC_PAGE_SIZE));
if (data_sz > mmap_sz) {
pr_warn("map '%s': declared ARENA map size (%zu) is too small to hold global __arena variables of size %zu\n",
arena_map->name, mmap_sz, obj->arena_data_sz);
return -E2BIG;
}
/* 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_sz;
}
/* Before relocating calls pre-process relocations and mark