Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions kernel/bpf/verifier.c
Original file line number Diff line number Diff line change
Expand Up @@ -21132,11 +21132,6 @@ static int resolve_pseudo_ldimm64(struct bpf_verifier_env *env)
} else {
u32 off = insn[1].imm;

if (off >= BPF_MAX_VAR_OFF) {
verbose(env, "direct value offset of %u is not allowed\n", off);
return -EINVAL;
}

if (!map->ops->map_direct_value_addr) {
verbose(env, "no direct value access support for this map type\n");
return -EINVAL;
Expand Down
21 changes: 15 additions & 6 deletions tools/lib/bpf/libbpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ struct reloc_desc {
const struct bpf_core_relo *core_relo; /* used when type == RELO_CORE */
struct {
int map_idx;
int sym_off;
unsigned int sym_off;
/*
* The following two fields can be unionized, as the
* ext_idx field is used for extern symbols, and the
Expand Down Expand Up @@ -757,13 +757,14 @@ 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;

struct {
struct bpf_program *prog;
int sym_off;
unsigned int sym_off;
int fd;
} *jumptable_maps;
size_t jumptable_map_cnt;
Expand Down Expand Up @@ -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;
Expand All @@ -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;

Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -5624,7 +5629,8 @@ bpf_object__create_maps(struct bpf_object *obj)
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);
}
}
Expand Down Expand Up @@ -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;
Expand Down
4 changes: 4 additions & 0 deletions tools/testing/selftests/bpf/prog_tests/verifier.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#include "verifier_and.skel.h"
#include "verifier_arena.skel.h"
#include "verifier_arena_large.skel.h"
#include "verifier_arena_globals1.skel.h"
#include "verifier_arena_globals2.skel.h"
#include "verifier_array_access.skel.h"
#include "verifier_async_cb_context.skel.h"
#include "verifier_basic_stack.skel.h"
Expand Down Expand Up @@ -147,6 +149,8 @@ static void run_tests_aux(const char *skel_name,
void test_verifier_and(void) { RUN(verifier_and); }
void test_verifier_arena(void) { RUN(verifier_arena); }
void test_verifier_arena_large(void) { RUN(verifier_arena_large); }
void test_verifier_arena_globals1(void) { RUN(verifier_arena_globals1); }
void test_verifier_arena_globals2(void) { RUN(verifier_arena_globals2); }
void test_verifier_basic_stack(void) { RUN(verifier_basic_stack); }
void test_verifier_bitfield_write(void) { RUN(verifier_bitfield_write); }
void test_verifier_bounds(void) { RUN(verifier_bounds); }
Expand Down
75 changes: 75 additions & 0 deletions tools/testing/selftests/bpf/progs/verifier_arena_globals1.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2025 Meta Platforms, Inc. and affiliates. */

#define BPF_NO_KFUNC_PROTOTYPES
#include <vmlinux.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include "bpf_experimental.h"
#include "bpf_arena_common.h"
#include "bpf_misc.h"

#define ARENA_PAGES (1UL<< (32 - 12))
#define GLOBAL_PAGES (16)

struct {
__uint(type, BPF_MAP_TYPE_ARENA);
__uint(map_flags, BPF_F_MMAPABLE);
__uint(max_entries, ARENA_PAGES);
#ifdef __TARGET_ARCH_arm64
__ulong(map_extra, (1ull << 32) | (~0u - __PAGE_SIZE * ARENA_PAGES + 1));
#else
__ulong(map_extra, (1ull << 44) | (~0u - __PAGE_SIZE * ARENA_PAGES + 1));
#endif
} arena SEC(".maps");

/*
* Global data, to be placed at the end of the arena.
*/
char __arena global_data[GLOBAL_PAGES][PAGE_SIZE];

SEC("syscall")
__success __retval(0)
int check_reserve1(void *ctx)
{
#if defined(__BPF_FEATURE_ADDR_SPACE_CAST)
__u8 __arena *guard, *globals;
int ret;

guard = (void __arena *)arena_base(&arena);
globals = (void __arena *)(arena_base(&arena) + (ARENA_PAGES - GLOBAL_PAGES) * PAGE_SIZE);

/* Reserve the region we've offset the globals by. */
ret = bpf_arena_reserve_pages(&arena, guard, ARENA_PAGES - GLOBAL_PAGES);
if (ret)
return 1;

/* Make sure the globals are in the expected offset. */
ret = bpf_arena_reserve_pages(&arena, globals, 1);
if (!ret)
return 2;
#endif
return 0;
}

/*
* Relocation check by reading directly into the global data w/o using symbols.
*/
SEC("syscall")
__success __retval(0)
int check_relocation(void *ctx)
{
#if defined(__BPF_FEATURE_ADDR_SPACE_CAST)
const u8 magic = 0xfa;
u8 __arena *ptr;

global_data[GLOBAL_PAGES - 1][PAGE_SIZE / 2] = magic;
ptr = (u8 __arena *)((u64)(ARENA_PAGES * PAGE_SIZE - PAGE_SIZE / 2));
if (*ptr != magic)
return 1;

#endif
return 0;
}

char _license[] SEC("license") = "GPL";
49 changes: 49 additions & 0 deletions tools/testing/selftests/bpf/progs/verifier_arena_globals2.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2025 Meta Platforms, Inc. and affiliates. */

#define BPF_NO_KFUNC_PROTOTYPES
#include <vmlinux.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include "bpf_misc.h"
#include "bpf_experimental.h"
#include "bpf_arena_common.h"

#define ARENA_PAGES (32)

struct {
__uint(type, BPF_MAP_TYPE_ARENA);
__uint(map_flags, BPF_F_MMAPABLE);
__uint(max_entries, ARENA_PAGES);
#ifdef __TARGET_ARCH_arm64
__ulong(map_extra, (1ull << 32) | (~0u - __PAGE_SIZE * ARENA_PAGES + 1));
#else
__ulong(map_extra, (1ull << 44) | (~0u - __PAGE_SIZE * ARENA_PAGES + 1));
#endif
} arena SEC(".maps");

/*
* Fill the entire arena with global data.
* The offset into the arena should be 0.
*/
char __arena global_data[PAGE_SIZE][ARENA_PAGES];

SEC("syscall")
__success __retval(0)
int check_reserve2(void *ctx)
{
#if defined(__BPF_FEATURE_ADDR_SPACE_CAST)
void __arena *guard;
int ret;

guard = (void __arena *)arena_base(&arena);

/* Make sure the data at offset 0 case is properly handled. */
ret = bpf_arena_reserve_pages(&arena, guard, 1);
if (!ret)
return 1;
#endif
return 0;
}

char _license[] SEC("license") = "GPL";
21 changes: 17 additions & 4 deletions tools/testing/selftests/bpf/progs/verifier_arena_large.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,31 @@ int big_alloc1(void *ctx)
{
#if defined(__BPF_FEATURE_ADDR_SPACE_CAST)
volatile char __arena *page1, *page2, *no_page, *page3;
void __arena *base;
u64 base;

page1 = base = bpf_arena_alloc_pages(&arena, NULL, 1, NUMA_NO_NODE, 0);
base = (u64)arena_base(&arena);

page1 = bpf_arena_alloc_pages(&arena, NULL, 1, NUMA_NO_NODE, 0);
if (!page1)
return 1;

if ((u64)page1 != base)
return 15;

*page1 = 1;
page2 = bpf_arena_alloc_pages(&arena, base + ARENA_SIZE - PAGE_SIZE * 2,
page2 = bpf_arena_alloc_pages(&arena, (void __arena *)(ARENA_SIZE - 2 * PAGE_SIZE),
1, NUMA_NO_NODE, 0);
if (!page2)
return 2;
*page2 = 2;
no_page = bpf_arena_alloc_pages(&arena, base + ARENA_SIZE - PAGE_SIZE,

/* Test for the guard region at the end of the arena. */
no_page = bpf_arena_alloc_pages(&arena, (void __arena *)ARENA_SIZE - PAGE_SIZE,
1, NUMA_NO_NODE, 0);
if (no_page)
return 16;

no_page = bpf_arena_alloc_pages(&arena, (void __arena *)ARENA_SIZE,
1, NUMA_NO_NODE, 0);
if (no_page)
return 3;
Expand Down
Loading