* [PATCH bpf-next 0/2] bpf: Reject arena frees below the arena base @ 2026-06-30 10:12 Yiyang Chen 2026-06-30 10:12 ` [PATCH bpf-next 1/2] " Yiyang Chen 2026-06-30 10:12 ` [PATCH bpf-next 2/2] selftests/bpf: Cover scalar arena frees below the base Yiyang Chen 0 siblings, 2 replies; 5+ messages in thread From: Yiyang Chen @ 2026-06-30 10:12 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() 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. Patch 1 rejects frees whose reconstructed full user address is below user_vm_start. Patch 2 adds verifier_arena coverage for the scalar-below-base case. Yiyang Chen (2): bpf: Reject arena frees below the arena base selftests/bpf: Cover scalar arena frees below the base kernel/bpf/arena.c | 2 + .../selftests/bpf/progs/verifier_arena.c | 41 ++++++++++++++++--- 2 files changed, 38 insertions(+), 5 deletions(-) base-commit: 7feeed42d8b97d0db0eab2c1c30aa86f110fe49c -- 2.34.1 ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH bpf-next 1/2] bpf: Reject arena frees below the arena base 2026-06-30 10:12 [PATCH bpf-next 0/2] bpf: Reject arena frees below the arena base Yiyang Chen @ 2026-06-30 10:12 ` Yiyang Chen 2026-07-01 21:12 ` Emil Tsalapatis 2026-06-30 10:12 ` [PATCH bpf-next 2/2] selftests/bpf: Cover scalar arena frees below the base Yiyang Chen 1 sibling, 1 reply; 5+ messages in thread From: Yiyang Chen @ 2026-06-30 10:12 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.") 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 49a8f7b1beef5..e28e83bed8c51 100644 --- a/kernel/bpf/arena.c +++ b/kernel/bpf/arena.c @@ -693,6 +693,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 related [flat|nested] 5+ messages in thread
* Re: [PATCH bpf-next 1/2] bpf: Reject arena frees below the arena base 2026-06-30 10:12 ` [PATCH bpf-next 1/2] " Yiyang Chen @ 2026-07-01 21:12 ` Emil Tsalapatis 0 siblings, 0 replies; 5+ messages in thread From: Emil Tsalapatis @ 2026-07-01 21:12 UTC (permalink / raw) To: Yiyang Chen, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi Cc: Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa, Shuah Khan, Emil Tsalapatis, Puranjay Mohan, bpf, linux-kselftest, linux-kernel On Tue Jun 30, 2026 at 6:12 AM EDT, Yiyang Chen wrote: > 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. > This seems reasonable, my understanding is that this happens because neither arena start nor end actually has to be aligned at a 4GiB boundary, while the underlying kernel mapping does span the full 32 bits. AFAICT this bug returns an address that is not actually mapped into userspace and is inaccessible from it, correct? If the above is correct, feel free to add: Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com> > Reject such frees before computing the clipped range. > > Fixes: 317460317a02a ("bpf: Introduce bpf_arena.") > 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 49a8f7b1beef5..e28e83bed8c51 100644 > --- a/kernel/bpf/arena.c > +++ b/kernel/bpf/arena.c > @@ -693,6 +693,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; ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH bpf-next 2/2] selftests/bpf: Cover scalar arena frees below the base 2026-06-30 10:12 [PATCH bpf-next 0/2] bpf: Reject arena frees below the arena base Yiyang Chen 2026-06-30 10:12 ` [PATCH bpf-next 1/2] " Yiyang Chen @ 2026-06-30 10:12 ` Yiyang Chen 2026-07-01 21:13 ` Emil Tsalapatis 1 sibling, 1 reply; 5+ messages in thread From: Yiyang Chen @ 2026-06-30 10:12 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. Signed-off-by: Yiyang Chen <chenyy23@mails.tsinghua.edu.cn> --- .../selftests/bpf/progs/verifier_arena.c | 41 ++++++++++++++++--- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/bpf/progs/verifier_arena.c b/tools/testing/selftests/bpf/progs/verifier_arena.c index 62e282f4448aa..b4bd134646607 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,35 @@ 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; + + asm volatile("" : "+r"(bad_addr)); + 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 related [flat|nested] 5+ messages in thread
* Re: [PATCH bpf-next 2/2] selftests/bpf: Cover scalar arena frees below the base 2026-06-30 10:12 ` [PATCH bpf-next 2/2] selftests/bpf: Cover scalar arena frees below the base Yiyang Chen @ 2026-07-01 21:13 ` Emil Tsalapatis 0 siblings, 0 replies; 5+ messages in thread From: Emil Tsalapatis @ 2026-07-01 21:13 UTC (permalink / raw) To: Yiyang Chen, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi Cc: Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa, Shuah Khan, Emil Tsalapatis, Puranjay Mohan, bpf, linux-kselftest, linux-kernel On Tue Jun 30, 2026 at 6:12 AM EDT, Yiyang Chen wrote: > 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. > > Signed-off-by: Yiyang Chen <chenyy23@mails.tsinghua.edu.cn> Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com> Nit/question below. > --- > .../selftests/bpf/progs/verifier_arena.c | 41 ++++++++++++++++--- > 1 file changed, 36 insertions(+), 5 deletions(-) > > diff --git a/tools/testing/selftests/bpf/progs/verifier_arena.c b/tools/testing/selftests/bpf/progs/verifier_arena.c > index 62e282f4448aa..b4bd134646607 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,35 @@ 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; > + > + asm volatile("" : "+r"(bad_addr)); Why the asm volatile? We use it right underneath, what does this give us. > + 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) ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-07-01 21:13 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-06-30 10:12 [PATCH bpf-next 0/2] bpf: Reject arena frees below the arena base Yiyang Chen 2026-06-30 10:12 ` [PATCH bpf-next 1/2] " Yiyang Chen 2026-07-01 21:12 ` Emil Tsalapatis 2026-06-30 10:12 ` [PATCH bpf-next 2/2] selftests/bpf: Cover scalar arena frees below the base Yiyang Chen 2026-07-01 21:13 ` Emil Tsalapatis
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.