* [PATCH bpf-next v2 1/2] bpf: Reject arena frees below the arena base
2026-07-17 12:53 [PATCH bpf-next v2 0/2] bpf: Reject arena frees below the arena base Yiyang Chen
@ 2026-07-17 12:53 ` Yiyang Chen
2026-07-17 12:53 ` [PATCH bpf-next v2 2/2] selftests/bpf: Cover scalar arena frees below the base Yiyang Chen
2026-07-19 16:30 ` [PATCH bpf-next v2 0/2] bpf: Reject arena frees below the arena base patchwork-bot+netdevbpf
2 siblings, 0 replies; 5+ messages in thread
From: Yiyang Chen @ 2026-07-17 12:53 UTC (permalink / raw)
To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Eduard Zingerman, Kumar Kartikeya Dwivedi
Cc: Yiyang Chen, Martin KaFai Lau, Song Liu, Yonghong Song,
Jiri Olsa, Shuah Khan, Emil Tsalapatis, Puranjay Mohan, bpf,
linux-kselftest, linux-kernel
bpf_arena_free_pages() accepts scalar arena addresses. The runtime
masks the address to the low 32 bits and reconstructs a full user
address from the arena base before returning the range to the arena
free tree.
When the scalar value is below the low 32 bits of the arena base,
full_uaddr falls below user_vm_start. The existing upper-end clipping
then turns this into an out-of-range free-tree offset. A later
allocation can reuse that offset and return an address below the arena
mapping.
Reject such frees before computing the clipped range.
Fixes: 317460317a02a ("bpf: Introduce bpf_arena.")
Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com>
Signed-off-by: Yiyang Chen <chenyy23@mails.tsinghua.edu.cn>
---
kernel/bpf/arena.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/kernel/bpf/arena.c b/kernel/bpf/arena.c
index 80b7b8a694464..97a5d8d212955 100644
--- a/kernel/bpf/arena.c
+++ b/kernel/bpf/arena.c
@@ -853,6 +853,8 @@ static void arena_free_pages(struct bpf_arena *arena, long uaddr, long page_cnt,
uaddr &= PAGE_MASK;
kaddr = bpf_arena_get_kern_vm_start(arena) + uaddr;
full_uaddr = clear_lo32(arena->user_vm_start) + uaddr;
+ if (full_uaddr < arena->user_vm_start)
+ return;
uaddr_end = min(arena->user_vm_end, full_uaddr + (page_cnt << PAGE_SHIFT));
if (full_uaddr >= uaddr_end)
return;
--
2.34.1
^ permalink raw reply [flat|nested] 5+ messages in thread* [PATCH bpf-next v2 2/2] selftests/bpf: Cover scalar arena frees below the base
2026-07-17 12:53 [PATCH bpf-next v2 0/2] bpf: Reject arena frees below the arena base Yiyang Chen
2026-07-17 12:53 ` [PATCH bpf-next v2 1/2] " Yiyang Chen
@ 2026-07-17 12:53 ` Yiyang Chen
2026-07-17 13:39 ` bot+bpf-ci
2026-07-19 16:30 ` [PATCH bpf-next v2 0/2] bpf: Reject arena frees below the arena base patchwork-bot+netdevbpf
2 siblings, 1 reply; 5+ messages in thread
From: Yiyang Chen @ 2026-07-17 12:53 UTC (permalink / raw)
To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Eduard Zingerman, Kumar Kartikeya Dwivedi
Cc: Yiyang Chen, Martin KaFai Lau, Song Liu, Yonghong Song,
Jiri Olsa, Shuah Khan, Emil Tsalapatis, Puranjay Mohan, bpf,
linux-kselftest, linux-kernel
Add a verifier_arena case that fills a two-page arena, calls
bpf_arena_free_pages() with a scalar address one page below the arena
base, and then verifies that another allocation is still rejected.
Before the runtime guard, the invalid free can repopulate the free
tree with an out-of-domain offset and the final allocation succeeds.
Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com>
Signed-off-by: Yiyang Chen <chenyy23@mails.tsinghua.edu.cn>
---
tools/testing/selftests/bpf/progs/verifier_arena.c | 40 +++++++++++++++++++---
1 file changed, 35 insertions(+), 5 deletions(-)
diff --git a/tools/testing/selftests/bpf/progs/verifier_arena.c b/tools/testing/selftests/bpf/progs/verifier_arena.c
index df0e22d1a29b1..b241bbcf54a8a 100644
--- a/tools/testing/selftests/bpf/progs/verifier_arena.c
+++ b/tools/testing/selftests/bpf/progs/verifier_arena.c
@@ -12,15 +12,17 @@
#define private(name) SEC(".bss." #name) __hidden __attribute__((aligned(8)))
+#ifdef __TARGET_ARCH_arm64
+#define ARENA_VM_START ((1ull << 32) | (~0u - __PAGE_SIZE * 2 + 1))
+#else
+#define ARENA_VM_START ((1ull << 44) | (~0u - __PAGE_SIZE * 2 + 1))
+#endif
+
struct {
__uint(type, BPF_MAP_TYPE_ARENA);
__uint(map_flags, BPF_F_MMAPABLE);
__uint(max_entries, 2); /* arena of two pages close to 32-bit boundary*/
-#ifdef __TARGET_ARCH_arm64
- __ulong(map_extra, (1ull << 32) | (~0u - __PAGE_SIZE * 2 + 1)); /* start of mmap() region */
-#else
- __ulong(map_extra, (1ull << 44) | (~0u - __PAGE_SIZE * 2 + 1)); /* start of mmap() region */
-#endif
+ __ulong(map_extra, ARENA_VM_START); /* start of mmap() region */
} arena SEC(".maps");
SEC("socket")
@@ -93,6 +95,34 @@ int basic_alloc1(void *ctx)
return 0;
}
+SEC("syscall")
+__success __retval(0)
+int free_scalar_below_arena(void *ctx)
+{
+ void __arena *page1, *page2, *page3;
+ __u64 bad_addr = ARENA_VM_START - __PAGE_SIZE;
+
+ page1 = bpf_arena_alloc_pages(&arena, NULL, 1, NUMA_NO_NODE, 0);
+ if (!page1)
+ return 1;
+
+ page2 = bpf_arena_alloc_pages(&arena, NULL, 1, NUMA_NO_NODE, 0);
+ if (!page2)
+ return 2;
+
+ page3 = bpf_arena_alloc_pages(&arena, NULL, 1, NUMA_NO_NODE, 0);
+ if (page3)
+ return 3;
+
+ bpf_arena_free_pages(&arena, (void __arena *)bad_addr, 1);
+
+ page3 = bpf_arena_alloc_pages(&arena, NULL, 1, NUMA_NO_NODE, 0);
+ if (page3)
+ return 4;
+
+ return 0;
+}
+
SEC("socket")
__success __retval(0)
int basic_alloc2_nosleep(void *ctx)
--
2.34.1
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: [PATCH bpf-next v2 0/2] bpf: Reject arena frees below the arena base
2026-07-17 12:53 [PATCH bpf-next v2 0/2] bpf: Reject arena frees below the arena base Yiyang Chen
2026-07-17 12:53 ` [PATCH bpf-next v2 1/2] " Yiyang Chen
2026-07-17 12:53 ` [PATCH bpf-next v2 2/2] selftests/bpf: Cover scalar arena frees below the base Yiyang Chen
@ 2026-07-19 16:30 ` patchwork-bot+netdevbpf
2 siblings, 0 replies; 5+ messages in thread
From: patchwork-bot+netdevbpf @ 2026-07-19 16:30 UTC (permalink / raw)
To: Yiyang Chen
Cc: ast, daniel, andrii, eddyz87, memxor, martin.lau, song,
yonghong.song, jolsa, shuah, emil, puranjay, bpf,
linux-kselftest, linux-kernel
Hello:
This series was applied to bpf/bpf-next.git (master)
by Kumar Kartikeya Dwivedi <memxor@gmail.com>:
On Fri, 17 Jul 2026 12:53:46 +0000 you wrote:
> bpf_arena_free_pages() can be called with a scalar arena address. The
> runtime reconstructs a full user address from the arena base and the low
> 32 bits before returning the range to the arena free tree. A scalar one
> page below the arena base can otherwise produce an out-of-domain free-tree
> offset and make a later allocation return an address below the arena
> mapping.
>
> [...]
Here is the summary with links:
- [bpf-next,v2,1/2] bpf: Reject arena frees below the arena base
https://git.kernel.org/bpf/bpf-next/c/b5a71cb2db6d
- [bpf-next,v2,2/2] selftests/bpf: Cover scalar arena frees below the base
https://git.kernel.org/bpf/bpf-next/c/770b62a6d389
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply [flat|nested] 5+ messages in thread