Skip to content

Commit 9fc7632

Browse files
etsalKernel Patches Daemon
authored andcommitted
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 <[email protected]> Signed-off-by: Emil Tsalapatis <[email protected]>
1 parent f5dd51a commit 9fc7632

File tree

2 files changed

+22
-7
lines changed

2 files changed

+22
-7
lines changed

tools/lib/bpf/libbpf.c

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -757,6 +757,7 @@ struct bpf_object {
757757
int arena_map_idx;
758758
void *arena_data;
759759
size_t arena_data_sz;
760+
size_t arena_data_off;
760761

761762
void *jumptables_data;
762763
size_t jumptables_data_sz;
@@ -2991,10 +2992,11 @@ static int init_arena_map_data(struct bpf_object *obj, struct bpf_map *map,
29912992
void *data, size_t data_sz)
29922993
{
29932994
const long page_sz = sysconf(_SC_PAGE_SIZE);
2995+
const size_t data_alloc_sz = roundup(data_sz, page_sz);
29942996
size_t mmap_sz;
29952997

29962998
mmap_sz = bpf_map_mmap_sz(map);
2997-
if (roundup(data_sz, page_sz) > mmap_sz) {
2999+
if (data_alloc_sz > mmap_sz) {
29983000
pr_warn("elf: sec '%s': declared ARENA map size (%zu) is too small to hold global __arena variables of size %zu\n",
29993001
sec_name, mmap_sz, data_sz);
30003002
return -E2BIG;
@@ -3006,6 +3008,9 @@ static int init_arena_map_data(struct bpf_object *obj, struct bpf_map *map,
30063008
memcpy(obj->arena_data, data, data_sz);
30073009
obj->arena_data_sz = data_sz;
30083010

3011+
/* place globals at the end of the arena */
3012+
obj->arena_data_off = mmap_sz - data_alloc_sz;
3013+
30093014
/* make bpf_map__init_value() work for ARENA maps */
30103015
map->mmaped = obj->arena_data;
30113016

@@ -4663,7 +4668,7 @@ static int bpf_program__record_reloc(struct bpf_program *prog,
46634668
reloc_desc->type = RELO_DATA;
46644669
reloc_desc->insn_idx = insn_idx;
46654670
reloc_desc->map_idx = obj->arena_map_idx;
4666-
reloc_desc->sym_off = sym->st_value;
4671+
reloc_desc->sym_off = sym->st_value + obj->arena_data_off;
46674672

46684673
map = &obj->maps[obj->arena_map_idx];
46694674
pr_debug("prog '%s': found arena map %d (%s, sec %d, off %zu) for insn %u\n",
@@ -5624,7 +5629,8 @@ bpf_object__create_maps(struct bpf_object *obj)
56245629
return err;
56255630
}
56265631
if (obj->arena_data) {
5627-
memcpy(map->mmaped, obj->arena_data, obj->arena_data_sz);
5632+
memcpy(map->mmaped + obj->arena_data_off, obj->arena_data,
5633+
obj->arena_data_sz);
56285634
zfree(&obj->arena_data);
56295635
}
56305636
}
@@ -14429,7 +14435,10 @@ int bpf_object__load_skeleton(struct bpf_object_skeleton *s)
1442914435
if (!map_skel->mmaped)
1443014436
continue;
1443114437

14432-
*map_skel->mmaped = map->mmaped;
14438+
if (map->def.type == BPF_MAP_TYPE_ARENA)
14439+
*map_skel->mmaped = map->mmaped + map->obj->arena_data_off;
14440+
else
14441+
*map_skel->mmaped = map->mmaped;
1443314442
}
1443414443

1443514444
return 0;

tools/testing/selftests/bpf/progs/verifier_arena_large.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,22 @@ int big_alloc1(void *ctx)
3131
if (!page1)
3232
return 1;
3333

34-
/* Account for global arena data. */
35-
if ((u64)page1 != base + PAGE_SIZE)
34+
if ((u64)page1 != base)
3635
return 15;
3736

3837
*page1 = 1;
39-
page2 = bpf_arena_alloc_pages(&arena, (void __arena *)(ARENA_SIZE - PAGE_SIZE),
38+
page2 = bpf_arena_alloc_pages(&arena, (void __arena *)(ARENA_SIZE - 2 * PAGE_SIZE),
4039
1, NUMA_NO_NODE, 0);
4140
if (!page2)
4241
return 2;
4342
*page2 = 2;
43+
44+
/* Test for the guard region at the end of the arena. */
45+
no_page = bpf_arena_alloc_pages(&arena, (void __arena *)ARENA_SIZE - PAGE_SIZE,
46+
1, NUMA_NO_NODE, 0);
47+
if (no_page)
48+
return 16;
49+
4450
no_page = bpf_arena_alloc_pages(&arena, (void __arena *)ARENA_SIZE,
4551
1, NUMA_NO_NODE, 0);
4652
if (no_page)

0 commit comments

Comments
 (0)