* [PATCH bpf-next 0/2] bpf: Reject out-of-range arena free addresses
@ 2026-07-06 15:52 Nuoqi Gui
2026-07-06 15:52 ` [PATCH bpf-next 1/2] " Nuoqi Gui
2026-07-06 15:52 ` [PATCH bpf-next 2/2] selftests/bpf: Cover " Nuoqi Gui
0 siblings, 2 replies; 5+ messages in thread
From: Nuoqi Gui @ 2026-07-06 15:52 UTC (permalink / raw)
To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Eduard Zingerman, Kumar Kartikeya Dwivedi, Shuah Khan
Cc: Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa,
Emil Tsalapatis, Puranjay Mohan, bpf, linux-kernel,
linux-kselftest, Nuoqi Gui
bpf_arena_free_pages() accepts scalar arena addresses. The free path
masks the low 32 bits, computes the full user address, and clips only
against arena->user_vm_end before inserting the range into the arena
free range tree.
A scalar address below arena->user_vm_start can therefore produce an
out-of-domain page offset. A later allocation can consume that offset
from the free range tree and return an address outside the arena range.
Reject frees whose computed full address is below the arena start before
clipping the end of the range, and add a verifier selftest for the
out-of-range free case.
Signed-off-by: Nuoqi Gui <gnq25@mails.tsinghua.edu.cn>
---
Nuoqi Gui (2):
bpf: Reject out-of-range arena free addresses
selftests/bpf: Cover out-of-range arena free addresses
kernel/bpf/arena.c | 2 ++
tools/testing/selftests/bpf/progs/verifier_arena.c | 26 ++++++++++++++++++++++
2 files changed, 28 insertions(+)
---
base-commit: 87bfe634b1193db90e5170e1ddbad04a63ef4501
change-id: 20260706-f01-31-arena-free-bpf-next-82bbb5be9bd4
Best regards,
--
Nuoqi Gui <gnq25@mails.tsinghua.edu.cn>
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH bpf-next 1/2] bpf: Reject out-of-range arena free addresses
2026-07-06 15:52 [PATCH bpf-next 0/2] bpf: Reject out-of-range arena free addresses Nuoqi Gui
@ 2026-07-06 15:52 ` Nuoqi Gui
2026-07-06 16:09 ` sashiko-bot
2026-07-06 16:57 ` Emil Tsalapatis
2026-07-06 15:52 ` [PATCH bpf-next 2/2] selftests/bpf: Cover " Nuoqi Gui
1 sibling, 2 replies; 5+ messages in thread
From: Nuoqi Gui @ 2026-07-06 15:52 UTC (permalink / raw)
To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Eduard Zingerman, Kumar Kartikeya Dwivedi, Shuah Khan
Cc: Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa,
Emil Tsalapatis, Puranjay Mohan, bpf, linux-kernel,
linux-kselftest, Nuoqi Gui
bpf_arena_free_pages() accepts scalar arena addresses. The free path
masks the low 32 bits, computes the full user address, and clips only
against arena->user_vm_end before inserting the range into the arena
free range tree.
A scalar address below arena->user_vm_start can therefore produce an
out-of-domain page offset. A later allocation can consume that offset
from the free range tree and return an address outside the arena range.
Reject frees whose computed full address is below the arena start before
clipping the end of the range.
Fixes: 317460317a02 ("bpf: Introduce bpf_arena.")
Signed-off-by: Nuoqi Gui <gnq25@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 80b7b8a69446..97a5d8d21295 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 related [flat|nested] 5+ messages in thread
* [PATCH bpf-next 2/2] selftests/bpf: Cover out-of-range arena free addresses
2026-07-06 15:52 [PATCH bpf-next 0/2] bpf: Reject out-of-range arena free addresses Nuoqi Gui
2026-07-06 15:52 ` [PATCH bpf-next 1/2] " Nuoqi Gui
@ 2026-07-06 15:52 ` Nuoqi Gui
1 sibling, 0 replies; 5+ messages in thread
From: Nuoqi Gui @ 2026-07-06 15:52 UTC (permalink / raw)
To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Eduard Zingerman, Kumar Kartikeya Dwivedi, Shuah Khan
Cc: Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa,
Emil Tsalapatis, Puranjay Mohan, bpf, linux-kernel,
linux-kselftest, Nuoqi Gui
Add a verifier selftest that fills a two-page arena, frees the page below
the arena start through a scalar value, and checks that a third allocation
is still unavailable.
Without the arena free range check, the out-of-range free can be inserted
into the free range tree and then allocated again, so the test returns 3.
With the fix, the out-of-range free is ignored and the focused test passes.
Signed-off-by: Nuoqi Gui <gnq25@mails.tsinghua.edu.cn>
---
tools/testing/selftests/bpf/progs/verifier_arena.c | 26 ++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/tools/testing/selftests/bpf/progs/verifier_arena.c b/tools/testing/selftests/bpf/progs/verifier_arena.c
index df0e22d1a29b..b21a8895804f 100644
--- a/tools/testing/selftests/bpf/progs/verifier_arena.c
+++ b/tools/testing/selftests/bpf/progs/verifier_arena.c
@@ -11,6 +11,7 @@
#include <bpf_arena_common.h>
#define private(name) SEC(".bss." #name) __hidden __attribute__((aligned(8)))
+#define ARENA_VM_START_L32 (~0u - __PAGE_SIZE * 2 + 1)
struct {
__uint(type, BPF_MAP_TYPE_ARENA);
@@ -93,6 +94,31 @@ int basic_alloc1(void *ctx)
return 0;
}
+SEC("syscall")
+__success __retval(0)
+int free_pages_out_of_bounds(void *ctx)
+{
+#if defined(__BPF_FEATURE_ADDR_SPACE_CAST)
+ __u64 page1, page2, no_page;
+ __u64 below_start = (__u32)(ARENA_VM_START_L32 - __PAGE_SIZE);
+
+ page1 = (__u64)bpf_arena_alloc_pages(&arena, NULL, 1, NUMA_NO_NODE, 0);
+ if (!page1)
+ return 1;
+ page2 = (__u64)bpf_arena_alloc_pages(&arena, NULL, 1, NUMA_NO_NODE, 0);
+ if (!page2)
+ return 2;
+
+ asm volatile("" : "+r"(below_start));
+ bpf_arena_free_pages(&arena, (void __arena *)below_start, 1);
+
+ no_page = (__u64)bpf_arena_alloc_pages(&arena, NULL, 1, NUMA_NO_NODE, 0);
+ if (no_page)
+ return 3;
+#endif
+ 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 1/2] bpf: Reject out-of-range arena free addresses
2026-07-06 15:52 ` [PATCH bpf-next 1/2] " Nuoqi Gui
@ 2026-07-06 16:09 ` sashiko-bot
2026-07-06 16:57 ` Emil Tsalapatis
1 sibling, 0 replies; 5+ messages in thread
From: sashiko-bot @ 2026-07-06 16:09 UTC (permalink / raw)
To: Nuoqi Gui; +Cc: bpf
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Missing 32-bit boundary check in `arena_map_mmap` allows kernel PTE overwrite and sandbox escape.
--
commit d41218f03bbc51a996de1d468ac821cb61f84615
Author: Nuoqi Gui <gnq25@mails.tsinghua.edu.cn>
bpf: Reject out-of-range arena free addresses
This commit adds a check in arena_free_pages() to reject frees where the
computed full address is below arena->user_vm_start. This prevents
out-of-domain page offsets from being inserted into the free range tree.
> 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;
[Severity: High]
This is a pre-existing issue, but looking at arena_map_mmap(), is it possible
for a user to dynamically choose a VMA that crosses a 32-bit boundary?
kernel/bpf/arena.c:arena_map_mmap() {
[ ... ]
arena->user_vm_start = vma->vm_start;
arena->user_vm_end = vma->vm_end;
[ ... ]
}
If a user maps the arena at an address crossing a 32-bit boundary (e.g.,
0x7FFF_FFFF0000 with a size of 4MB) by not specifying map_extra and using
mmap with MAP_FIXED, does this bypass the boundary check?
If so, could this lead to an overflow in arena_alloc_pages() when calculating
uaddr32?
kernel/bpf/arena.c:arena_alloc_pages() {
[ ... ]
uaddr32 = (u32)(arena->user_vm_start + pgoff * PAGE_SIZE);
while (remaining) {
[ ... ]
ret = apply_to_page_range(&init_mm,
kern_vm_start + uaddr32 + (mapped << PAGE_SHIFT),
this_batch << PAGE_SHIFT, apply_range_set_cb, &data);
[ ... ]
}
When uaddr32 overflows, does the calculation kern_vm_start + uaddr32 exceed
the KERN_VM_SZ bounds? Can this overwrite PTEs of adjacent vmalloc areas?
> uaddr_end = min(arena->user_vm_end, full_uaddr + (page_cnt << PAGE_SHIFT));
> if (full_uaddr >= uaddr_end)
> return;
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260706-f01-31-arena-free-bpf-next-v1-0-3ad6e7384285@mails.tsinghua.edu.cn?part=1
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH bpf-next 1/2] bpf: Reject out-of-range arena free addresses
2026-07-06 15:52 ` [PATCH bpf-next 1/2] " Nuoqi Gui
2026-07-06 16:09 ` sashiko-bot
@ 2026-07-06 16:57 ` Emil Tsalapatis
1 sibling, 0 replies; 5+ messages in thread
From: Emil Tsalapatis @ 2026-07-06 16:57 UTC (permalink / raw)
To: Nuoqi Gui, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Eduard Zingerman, Kumar Kartikeya Dwivedi, Shuah Khan
Cc: Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa,
Emil Tsalapatis, Puranjay Mohan, bpf, linux-kernel,
linux-kselftest
On Mon Jul 6, 2026 at 11:52 AM EDT, Nuoqi Gui wrote:
> bpf_arena_free_pages() accepts scalar arena addresses. The free path
> masks the low 32 bits, computes the full user address, and clips only
> against arena->user_vm_end before inserting the range into the arena
> free range tree.
>
> A scalar address below arena->user_vm_start can therefore produce an
> out-of-domain page offset. A later allocation can consume that offset
> from the free range tree and return an address outside the arena range.
>
> Reject frees whose computed full address is below the arena start before
> clipping the end of the range.
>
> Fixes: 317460317a02 ("bpf: Introduce bpf_arena.")
> Signed-off-by: Nuoqi Gui <gnq25@mails.tsinghua.edu.cn>
This is the exact same patch that Yiyang Chen sent about a week ago.
pw-bot: cr
> ---
> kernel/bpf/arena.c | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/kernel/bpf/arena.c b/kernel/bpf/arena.c
> index 80b7b8a69446..97a5d8d21295 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;
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-07-06 16:57 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-06 15:52 [PATCH bpf-next 0/2] bpf: Reject out-of-range arena free addresses Nuoqi Gui
2026-07-06 15:52 ` [PATCH bpf-next 1/2] " Nuoqi Gui
2026-07-06 16:09 ` sashiko-bot
2026-07-06 16:57 ` Emil Tsalapatis
2026-07-06 15:52 ` [PATCH bpf-next 2/2] selftests/bpf: Cover " Nuoqi Gui
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox