diff options
| author | Alexei Starovoitov <ast@kernel.org> | 2025-07-11 10:43:55 -0700 |
|---|---|---|
| committer | Alexei Starovoitov <ast@kernel.org> | 2025-07-11 10:44:02 -0700 |
| commit | 2b1fd82cbaffef05a35bd04ba2d62d96f4d8a622 (patch) | |
| tree | 59c4eced0bd264cfc52170af88cb1bbeb68d7e3c /kernel/bpf | |
| parent | selftests/bpf: Remove enum64 case from __arg_untrusted test suite (diff) | |
| parent | selftests/bpf: add selftests for bpf_arena_reserve_pages (diff) | |
| download | linux-2b1fd82cbaffef05a35bd04ba2d62d96f4d8a622.tar.gz linux-2b1fd82cbaffef05a35bd04ba2d62d96f4d8a622.zip | |
Merge branch 'bpf-arena-add-kfunc-for-reserving-arena-memory'
Emil Tsalapatis says:
====================
bpf/arena: Add kfunc for reserving arena memory
Add a new kfunc for BPF arenas that reserves a region of the mapping
to prevent it from being mapped. These regions serve as guards against
out-of-bounds accesses and are useful for debugging arena-related code.
>From v3 (20250709015712.97099-1-emil@etsalapatis.com)
------------------------------------------------------
- Added Acked-by tags by Yonghong.
- Replace hardcoded error numbers in selftests (Yonghong).
- Fixed selftest for partially freeing a reserved region (Yonghong).
>From v2 (20250702003351.197234-1-emil@etsalapatis.com)
------------------------------------------------------
- Removed -EALREADY and replaced with -EINVAL to bring error handling in
line with the rest of the BPF code (Alexei).
>From v1 (20250620031118.245601-1-emil@etsalapatis.com)
------------------------------------------------------
- Removed the additional guard range tree. Adjusted tests accordingly.
Reserved regions now behave like allocated regions, and can be
unreserved using bpf_arena_free_pages(). They can also be allocated
from userspace through minor faults. It is up to the user to prevent
erroneous frees and/or use the BPF_F_SEGV_ON_FAULT flag to catch
stray userspace accesses (Alexei).
- Changed terminology from guard pages to reserved pages (Alexei,
Kartikeya).
Signed-off-by: Emil Tsalapatis <emil@etsalapatis.com>
====================
Link: https://patch.msgid.link/20250709191312.29840-1-emil@etsalapatis.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Diffstat (limited to 'kernel/bpf')
| -rw-r--r-- | kernel/bpf/arena.c | 43 |
1 files changed, 43 insertions, 0 deletions
diff --git a/kernel/bpf/arena.c b/kernel/bpf/arena.c index 0d56cea71602..5b37753799d2 100644 --- a/kernel/bpf/arena.c +++ b/kernel/bpf/arena.c @@ -550,6 +550,34 @@ static void arena_free_pages(struct bpf_arena *arena, long uaddr, long page_cnt) } } +/* + * Reserve an arena virtual address range without populating it. This call stops + * bpf_arena_alloc_pages from adding pages to this range. + */ +static int arena_reserve_pages(struct bpf_arena *arena, long uaddr, u32 page_cnt) +{ + long page_cnt_max = (arena->user_vm_end - arena->user_vm_start) >> PAGE_SHIFT; + long pgoff; + int ret; + + if (uaddr & ~PAGE_MASK) + return 0; + + pgoff = compute_pgoff(arena, uaddr); + if (pgoff + page_cnt > page_cnt_max) + return -EINVAL; + + guard(mutex)(&arena->lock); + + /* Cannot guard already allocated pages. */ + ret = is_range_tree_set(&arena->rt, pgoff, page_cnt); + if (ret) + return -EBUSY; + + /* "Allocate" the region to prevent it from being allocated. */ + return range_tree_clear(&arena->rt, pgoff, page_cnt); +} + __bpf_kfunc_start_defs(); __bpf_kfunc void *bpf_arena_alloc_pages(void *p__map, void *addr__ign, u32 page_cnt, @@ -573,11 +601,26 @@ __bpf_kfunc void bpf_arena_free_pages(void *p__map, void *ptr__ign, u32 page_cnt return; arena_free_pages(arena, (long)ptr__ign, page_cnt); } + +__bpf_kfunc int bpf_arena_reserve_pages(void *p__map, void *ptr__ign, u32 page_cnt) +{ + struct bpf_map *map = p__map; + struct bpf_arena *arena = container_of(map, struct bpf_arena, map); + + if (map->map_type != BPF_MAP_TYPE_ARENA) + return -EINVAL; + + if (!page_cnt) + return 0; + + return arena_reserve_pages(arena, (long)ptr__ign, page_cnt); +} __bpf_kfunc_end_defs(); BTF_KFUNCS_START(arena_kfuncs) BTF_ID_FLAGS(func, bpf_arena_alloc_pages, KF_TRUSTED_ARGS | KF_SLEEPABLE | KF_ARENA_RET | KF_ARENA_ARG2) BTF_ID_FLAGS(func, bpf_arena_free_pages, KF_TRUSTED_ARGS | KF_SLEEPABLE | KF_ARENA_ARG2) +BTF_ID_FLAGS(func, bpf_arena_reserve_pages, KF_TRUSTED_ARGS | KF_SLEEPABLE | KF_ARENA_ARG2) BTF_KFUNCS_END(arena_kfuncs) static const struct btf_kfunc_id_set common_kfunc_set = { |
