Skip to content

Commit f405718

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 6032de3 commit f405718

File tree

2 files changed

+24
-7
lines changed

2 files changed

+24
-7
lines changed

tools/lib/bpf/libbpf.c

Lines changed: 15 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+
__u32 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
}
@@ -14383,6 +14389,7 @@ void bpf_object__destroy_subskeleton(struct bpf_object_subskeleton *s)
1438314389

1438414390
int bpf_object__load_skeleton(struct bpf_object_skeleton *s)
1438514391
{
14392+
void *mmaped;
1438614393
int i, err;
1438714394

1438814395
err = bpf_object__load(*s->obj);
@@ -14398,7 +14405,11 @@ int bpf_object__load_skeleton(struct bpf_object_skeleton *s)
1439814405
if (!map_skel->mmaped)
1439914406
continue;
1440014407

14401-
*map_skel->mmaped = map->mmaped;
14408+
mmaped = map->mmaped;
14409+
if (map->def.type == BPF_MAP_TYPE_ARENA)
14410+
mmaped += map->obj->arena_data_off;
14411+
14412+
*map_skel->mmaped = mmaped;
1440214413
}
1440314414

1440414415
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)