* [PATCH bpf-next 0/2] bpf: expand BPF arena kernel fault handling
@ 2026-10-28 1:51 Emil Tsalapatis
2026-10-28 1:51 ` [PATCH bpf 1/2] bpf: recover page faults across all arenas Emil Tsalapatis
2026-10-28 1:51 ` [PATCH bpf 2/2] selftests/bpf: add arena fault recovery tests Emil Tsalapatis
0 siblings, 2 replies; 5+ messages in thread
From: Emil Tsalapatis @ 2026-10-28 1:51 UTC (permalink / raw)
To: bpf; +Cc: ast, andrii, eddyz87, memxor, daniel, Emil Tsalapatis, Tejun Heo
Currently, the BPF arena fault handler protects against
a misbehaving BPF program passing an arena pointer to a
kfunc then unmapping the backing pages, causing a kernel
fault. However, it does not handle errors where the now
unmapped arena address is instead accessed by a non-BPF
path, or by a BPF program that has a different arena.
The former case is already possible in sched-ext if a
BPF program removes from the arena pages allocated
from the genpool allocator.
Keep a list of all arenas in the system and attempt to match
the kernel fault to all of them. If the fault does fall in
an arena, handle it with the already established scratch
page technique and retry the access.
Cc: Tejun Heo <tj@kernel.org>
Signed-off-by: Emil Tsalapatis <emil@etsalapatis.com>
Emil Tsalapatis (2):
bpf: recover page faults across all arenas
selftests/bpf: add arena fault recovery tests
kernel/bpf/arena.c | 54 +++++++----
tools/testing/selftests/bpf/Makefile | 2 +-
.../selftests/bpf/prog_tests/arena_fault.c | 91 +++++++++++++++++++
.../testing/selftests/bpf/progs/arena_fault.c | 55 +++++++++++
.../selftests/bpf/progs/arena_fault_noarena.c | 17 ++++
.../testing/selftests/bpf/test_kmods/Makefile | 2 +-
.../bpf/test_kmods/bpf_test_arena_fault.c | 55 +++++++++++
.../bpf/test_kmods/bpf_test_arena_fault.h | 10 ++
8 files changed, 265 insertions(+), 21 deletions(-)
create mode 100644 tools/testing/selftests/bpf/prog_tests/arena_fault.c
create mode 100644 tools/testing/selftests/bpf/progs/arena_fault.c
create mode 100644 tools/testing/selftests/bpf/progs/arena_fault_noarena.c
create mode 100644 tools/testing/selftests/bpf/test_kmods/bpf_test_arena_fault.c
create mode 100644 tools/testing/selftests/bpf/test_kmods/bpf_test_arena_fault.h
--
2.54.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH bpf 1/2] bpf: recover page faults across all arenas
2026-10-28 1:51 [PATCH bpf-next 0/2] bpf: expand BPF arena kernel fault handling Emil Tsalapatis
@ 2026-10-28 1:51 ` Emil Tsalapatis
2026-10-28 2:36 ` bot+bpf-ci
2026-10-28 1:51 ` [PATCH bpf 2/2] selftests/bpf: add arena fault recovery tests Emil Tsalapatis
1 sibling, 1 reply; 5+ messages in thread
From: Emil Tsalapatis @ 2026-10-28 1:51 UTC (permalink / raw)
To: bpf; +Cc: ast, andrii, eddyz87, memxor, daniel, Emil Tsalapatis, Tejun Heo
The current arena fault handling code accounts for
misbehaving BPF programs that free arena memory
while it is being accessed by a kfunc as part of
another BPF program's execution. This scenario
triggers a kernel page fault that is intercepted
by BPF arena-specific code. The code confirms
that the fault is within the BPF program's arena,
installs a scratch page, and marks the fault as
handled. This is necessary to prevent BPF programs
from being able to trigger an oops.
However, the protection against misbehaving BPF programs
is currently incomplete: Arena memory is accessed by
kernel code not just as part of a kfunc, but also from
non-BPF paths. This is the case with sched-ext that
includes non-BPF code paths that access arena pointers.
These paths do not have an arena associated with them,
and a fault there causes an oops. Such a fault can be
triggered by a misbehaving BPF program by unmapping the
pages nominally owned by the genpool allocator used for
cid management.
Extend the kernel arena fault handling to consider all
arenas in the system. The handler now scans a global
arena list till it finds an arena that includes the address,
and fixes up the address. Retain the stream-based reporting
code for when the faulting call stack includes the BPF
program that owns the arena.
Fixes: 9eca087deb0b ("sched_ext: Sub-allocator over kernel-claimed BPF arena pages")
Cc: Tejun Heo <tj@kernel.org>
Signed-off-by: Emil Tsalapatis <emil@etsalapatis.com>
---
kernel/bpf/arena.c | 54 ++++++++++++++++++++++++++++++----------------
1 file changed, 35 insertions(+), 19 deletions(-)
diff --git a/kernel/bpf/arena.c b/kernel/bpf/arena.c
index 868589f07330..992a0b123449 100644
--- a/kernel/bpf/arena.c
+++ b/kernel/bpf/arena.c
@@ -10,6 +10,7 @@
#include <linux/btf_ids.h>
#include <linux/vmalloc.h>
#include <linux/pagemap.h>
+#include <linux/rculist.h>
#include <asm/tlbflush.h>
#include "range_tree.h"
@@ -46,10 +47,14 @@
#define GUARD_SZ round_up(1ull << sizeof_field(struct bpf_insn, off) * 8, PAGE_SIZE << 1)
#define KERN_VM_SZ (SZ_4G + GUARD_SZ)
+static LIST_HEAD(arena_list);
+static DEFINE_SPINLOCK(arena_list_lock);
+
static void arena_free_pages(struct bpf_arena *arena, long uaddr, long page_cnt, bool sleepable);
struct bpf_arena {
struct bpf_map map;
+ struct list_head list;
u64 user_vm_start;
u64 user_vm_end;
struct vm_struct *kern_vm;
@@ -332,6 +337,10 @@ static struct bpf_map *arena_map_alloc(union bpf_attr *attr)
if (err)
goto err_destroy_rt;
+ spin_lock(&arena_list_lock);
+ list_add_tail_rcu(&arena->list, &arena_list);
+ spin_unlock(&arena_list_lock);
+
return &arena->map;
err_destroy_rt:
@@ -385,6 +394,12 @@ static void arena_map_free(struct bpf_map *map)
if (WARN_ON_ONCE(!list_empty(&arena->vma_list)))
return;
+ spin_lock(&arena_list_lock);
+ list_del_rcu(&arena->list);
+ spin_unlock(&arena_list_lock);
+
+ synchronize_rcu();
+
/* Ensure no pending deferred frees */
irq_work_sync(&arena->free_irq);
flush_work(&arena->free_work);
@@ -1207,31 +1222,32 @@ bool bpf_arena_handle_page_fault(unsigned long addr, bool is_write, unsigned lon
struct bpf_prog *prog;
unsigned long kbase;
unsigned long page_addr = addr & PAGE_MASK;
-
- prog = bpf_prog_find_from_stack();
- if (!prog)
- return false;
-
- arena = prog->aux->arena;
- /* a prog not using arena may be on stack, so arena can be NULL */
- if (!arena)
- return false;
-
- kbase = bpf_arena_get_kern_vm_start(arena);
+ bool handled = false;
/*
* Recovery covers the 4 GiB mappable band plus the upper half-guard.
* Lower guard is unreachable from kfuncs; an address there indicates
* a different bug class - leave it to the regular kernel oops path.
*/
- if (page_addr < kbase || page_addr >= kbase + SZ_4G + GUARD_SZ / 2)
- return false;
-
- apply_to_page_range(&init_mm, page_addr, PAGE_SIZE,
- apply_range_set_scratch_cb, arena->scratch_page);
- flush_vmap_cache(page_addr, PAGE_SIZE);
- __bpf_prog_report_arena_violation(prog, is_write, page_addr - kbase, fault_ip);
- return true;
+ rcu_read_lock();
+ list_for_each_entry_rcu(arena, &arena_list, list) {
+ kbase = bpf_arena_get_kern_vm_start(arena);
+ if (page_addr < kbase || page_addr >= kbase + SZ_4G + GUARD_SZ / 2)
+ continue;
+
+ apply_to_page_range(&init_mm, page_addr, PAGE_SIZE,
+ apply_range_set_scratch_cb, arena->scratch_page);
+ flush_vmap_cache(page_addr, PAGE_SIZE);
+
+ prog = bpf_prog_find_from_stack();
+ if (prog && prog->aux->arena == arena)
+ __bpf_prog_report_arena_violation(prog, is_write,
+ page_addr - kbase, fault_ip);
+ handled = true;
+ break;
+ }
+ rcu_read_unlock();
+ return handled;
}
void bpf_prog_report_arena_violation(bool write, unsigned long addr, unsigned long fault_ip)
--
2.54.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH bpf 2/2] selftests/bpf: add arena fault recovery tests
2026-10-28 1:51 [PATCH bpf-next 0/2] bpf: expand BPF arena kernel fault handling Emil Tsalapatis
2026-10-28 1:51 ` [PATCH bpf 1/2] bpf: recover page faults across all arenas Emil Tsalapatis
@ 2026-10-28 1:51 ` Emil Tsalapatis
2026-10-28 2:13 ` sashiko-bot
1 sibling, 1 reply; 5+ messages in thread
From: Emil Tsalapatis @ 2026-10-28 1:51 UTC (permalink / raw)
To: bpf; +Cc: ast, andrii, eddyz87, memxor, daniel, Emil Tsalapatis
Test the arena fault handling code with two new selftests.
The first one confirms that a program without an arena (and
by extension a code path that doesn't involve BPF at all)
properly recovers after accessing an unbacked arena page.
The second test deploys the same configuration for a program
that has its own arena map.
Signed-off-by: Emil Tsalapatis <emil@etsalapatis.com>
---
tools/testing/selftests/bpf/Makefile | 2 +-
.../selftests/bpf/prog_tests/arena_fault.c | 91 +++++++++++++++++++
.../testing/selftests/bpf/progs/arena_fault.c | 55 +++++++++++
.../selftests/bpf/progs/arena_fault_noarena.c | 17 ++++
.../testing/selftests/bpf/test_kmods/Makefile | 2 +-
.../bpf/test_kmods/bpf_test_arena_fault.c | 55 +++++++++++
.../bpf/test_kmods/bpf_test_arena_fault.h | 10 ++
7 files changed, 230 insertions(+), 2 deletions(-)
create mode 100644 tools/testing/selftests/bpf/prog_tests/arena_fault.c
create mode 100644 tools/testing/selftests/bpf/progs/arena_fault.c
create mode 100644 tools/testing/selftests/bpf/progs/arena_fault_noarena.c
create mode 100644 tools/testing/selftests/bpf/test_kmods/bpf_test_arena_fault.c
create mode 100644 tools/testing/selftests/bpf/test_kmods/bpf_test_arena_fault.h
diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index 1e4af62e8312..97d4a266abed 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -47,7 +47,7 @@ TEST_PROGS_EXTENDED := \
ima_setup.sh verify_sig_setup.sh
TEST_KMODS := bpf_testmod.ko bpf_test_no_cfi.ko bpf_test_modorder_x.ko \
- bpf_test_modorder_y.ko bpf_test_rqspinlock.ko
+ bpf_test_modorder_y.ko bpf_test_rqspinlock.ko bpf_test_arena_fault.ko
TEST_KMOD_TARGETS = $(addprefix $(OUTPUT)/,$(TEST_KMODS))
# Compile but not part of 'make run_tests'
diff --git a/tools/testing/selftests/bpf/prog_tests/arena_fault.c b/tools/testing/selftests/bpf/prog_tests/arena_fault.c
new file mode 100644
index 000000000000..7134ece16a31
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/arena_fault.c
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <test_progs.h>
+#include <testing_helpers.h>
+#include "arena_fault.skel.h"
+#include "arena_fault_noarena.skel.h"
+
+#define ARENA_FAULT_MOD "bpf_test_arena_fault"
+
+static int run_syscall_prog(struct bpf_program *prog, const char *name)
+{
+ LIBBPF_OPTS(bpf_test_run_opts, opts);
+ int err;
+
+ err = bpf_prog_test_run_opts(bpf_program__fd(prog), &opts);
+ if (!ASSERT_OK(err, name))
+ return -1;
+ if (!ASSERT_OK(opts.retval, name))
+ return -1;
+ return 0;
+}
+
+static void test_wrong_arena(void)
+{
+ struct arena_fault *fault_skel = NULL;
+ struct arena_fault *stash_skel = NULL;
+
+ stash_skel = arena_fault__open_and_load();
+ if (!ASSERT_OK_PTR(stash_skel, "open_load_stash"))
+ return;
+
+ fault_skel = arena_fault__open_and_load();
+ if (!ASSERT_OK_PTR(fault_skel, "open_load_fault"))
+ goto out;
+
+ if (run_syscall_prog(stash_skel->progs.stash_and_free, "stash_and_free"))
+ goto out;
+ run_syscall_prog(fault_skel->progs.fault_stashed_wrong_arena,
+ "fault_stashed_wrong_arena");
+
+out:
+ if (stash_skel)
+ run_syscall_prog(stash_skel->progs.clear_stashed, "clear_stashed");
+ arena_fault__destroy(fault_skel);
+ arena_fault__destroy(stash_skel);
+}
+
+static void test_no_arena(void)
+{
+ struct arena_fault_noarena *fault_skel = NULL;
+ struct arena_fault *stash_skel = NULL;
+
+ stash_skel = arena_fault__open_and_load();
+ if (!ASSERT_OK_PTR(stash_skel, "open_load_stash"))
+ return;
+
+ fault_skel = arena_fault_noarena__open_and_load();
+ if (!ASSERT_OK_PTR(fault_skel, "open_load_noarena"))
+ goto out;
+
+ if (run_syscall_prog(stash_skel->progs.stash_and_free, "stash_and_free"))
+ goto out;
+ run_syscall_prog(fault_skel->progs.fault_stashed_noarena,
+ "fault_stashed_noarena");
+
+out:
+ if (stash_skel)
+ run_syscall_prog(stash_skel->progs.clear_stashed, "clear_stashed");
+ arena_fault_noarena__destroy(fault_skel);
+ arena_fault__destroy(stash_skel);
+}
+
+void serial_test_arena_fault(void)
+{
+#if !defined(__x86_64__) && !defined(__aarch64__)
+ test__skip();
+ return;
+#endif
+
+ if (!ASSERT_OK(load_module(ARENA_FAULT_MOD ".ko",
+ env_verbosity > VERBOSE_NONE),
+ "load " ARENA_FAULT_MOD ".ko"))
+ return;
+
+ if (test__start_subtest("wrong_arena"))
+ test_wrong_arena();
+ if (test__start_subtest("no_arena"))
+ test_no_arena();
+
+ unload_module(ARENA_FAULT_MOD, env_verbosity > VERBOSE_NONE);
+}
diff --git a/tools/testing/selftests/bpf/progs/arena_fault.c b/tools/testing/selftests/bpf/progs/arena_fault.c
new file mode 100644
index 000000000000..1967b128fdf6
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/arena_fault.c
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#define BPF_NO_KFUNC_PROTOTYPES
+#include <vmlinux.h>
+#include <bpf/bpf_helpers.h>
+#include "bpf_arena_common.h"
+#include "../test_kmods/bpf_test_arena_fault.h"
+
+struct {
+ __uint(type, BPF_MAP_TYPE_ARENA);
+ __uint(map_flags, BPF_F_MMAPABLE);
+ __uint(max_entries, 2);
+} arena SEC(".maps");
+
+u64 __arena arena_pad;
+volatile u64 observed;
+
+SEC("syscall")
+int stash_and_free(void *ctx)
+{
+ u64 __arena *val;
+
+ val = bpf_arena_alloc_pages(&arena, NULL, 1, NUMA_NO_NODE, 0);
+ if (!val)
+ return 1;
+
+ *val = 42;
+ bpf_test_arena_fault_stash((u64 *)val);
+ bpf_arena_free_pages(&arena, val, 1);
+ return 0;
+}
+
+SEC("syscall")
+int fault_stashed_wrong_arena(void *ctx)
+{
+ u64 __arena *val;
+
+ val = bpf_arena_alloc_pages(&arena, NULL, 1, NUMA_NO_NODE, 0);
+ if (!val)
+ return 1;
+
+ *val = 1;
+ observed = bpf_test_arena_fault_load_stashed();
+ bpf_arena_free_pages(&arena, val, 1);
+ return observed != 0;
+}
+
+SEC("syscall")
+int clear_stashed(void *ctx)
+{
+ bpf_test_arena_fault_clear_stashed();
+ return 0;
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/progs/arena_fault_noarena.c b/tools/testing/selftests/bpf/progs/arena_fault_noarena.c
new file mode 100644
index 000000000000..7fa8814808b5
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/arena_fault_noarena.c
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#define BPF_NO_KFUNC_PROTOTYPES
+#include <vmlinux.h>
+#include <bpf/bpf_helpers.h>
+#include "../test_kmods/bpf_test_arena_fault.h"
+
+volatile u64 observed;
+
+SEC("syscall")
+int fault_stashed_noarena(void *ctx)
+{
+ observed = bpf_test_arena_fault_load_stashed();
+ return observed != 0;
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/test_kmods/Makefile b/tools/testing/selftests/bpf/test_kmods/Makefile
index 031c7454ce65..e611e71fcef1 100644
--- a/tools/testing/selftests/bpf/test_kmods/Makefile
+++ b/tools/testing/selftests/bpf/test_kmods/Makefile
@@ -19,7 +19,7 @@ Q = @
endif
MODULES = bpf_testmod.ko bpf_test_no_cfi.ko bpf_test_modorder_x.ko \
- bpf_test_modorder_y.ko bpf_test_rqspinlock.ko
+ bpf_test_modorder_y.ko bpf_test_rqspinlock.ko bpf_test_arena_fault.ko
$(foreach m,$(MODULES),$(eval obj-m += $(m:.ko=.o)))
diff --git a/tools/testing/selftests/bpf/test_kmods/bpf_test_arena_fault.c b/tools/testing/selftests/bpf/test_kmods/bpf_test_arena_fault.c
new file mode 100644
index 000000000000..0b3dbf80344d
--- /dev/null
+++ b/tools/testing/selftests/bpf/test_kmods/bpf_test_arena_fault.c
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/bpf.h>
+#include <linux/btf.h>
+#include <linux/module.h>
+
+static u64 *stashed_ptr;
+
+__bpf_kfunc_start_defs();
+
+__bpf_kfunc void bpf_test_arena_fault_stash(u64 *ptr__arena)
+{
+ WRITE_ONCE(stashed_ptr, ptr__arena);
+}
+
+__bpf_kfunc u64 bpf_test_arena_fault_load_stashed(void)
+{
+ u64 *ptr = READ_ONCE(stashed_ptr);
+
+ return ptr ? READ_ONCE(*ptr) : U64_MAX;
+}
+
+__bpf_kfunc void bpf_test_arena_fault_clear_stashed(void)
+{
+ WRITE_ONCE(stashed_ptr, NULL);
+}
+
+__bpf_kfunc_end_defs();
+
+BTF_KFUNCS_START(bpf_test_arena_fault_kfunc_ids)
+BTF_ID_FLAGS(func, bpf_test_arena_fault_stash)
+BTF_ID_FLAGS(func, bpf_test_arena_fault_load_stashed)
+BTF_ID_FLAGS(func, bpf_test_arena_fault_clear_stashed)
+BTF_KFUNCS_END(bpf_test_arena_fault_kfunc_ids)
+
+static const struct btf_kfunc_id_set bpf_test_arena_fault_kfunc_set = {
+ .owner = THIS_MODULE,
+ .set = &bpf_test_arena_fault_kfunc_ids,
+};
+
+static int __init bpf_test_arena_fault_init(void)
+{
+ return register_btf_kfunc_id_set(BPF_PROG_TYPE_UNSPEC,
+ &bpf_test_arena_fault_kfunc_set);
+}
+
+static void __exit bpf_test_arena_fault_exit(void)
+{
+}
+
+module_init(bpf_test_arena_fault_init);
+module_exit(bpf_test_arena_fault_exit);
+
+MODULE_DESCRIPTION("BPF arena fault selftest module");
+MODULE_LICENSE("GPL");
diff --git a/tools/testing/selftests/bpf/test_kmods/bpf_test_arena_fault.h b/tools/testing/selftests/bpf/test_kmods/bpf_test_arena_fault.h
new file mode 100644
index 000000000000..1657c445a0fa
--- /dev/null
+++ b/tools/testing/selftests/bpf/test_kmods/bpf_test_arena_fault.h
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#ifndef __BPF_TEST_ARENA_FAULT_H
+#define __BPF_TEST_ARENA_FAULT_H
+
+void bpf_test_arena_fault_stash(__u64 *ptr__arena) __ksym;
+__u64 bpf_test_arena_fault_load_stashed(void) __ksym;
+void bpf_test_arena_fault_clear_stashed(void) __ksym;
+
+#endif /* __BPF_TEST_ARENA_FAULT_H */
--
2.54.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH bpf 2/2] selftests/bpf: add arena fault recovery tests
2026-10-28 1:51 ` [PATCH bpf 2/2] selftests/bpf: add arena fault recovery tests Emil Tsalapatis
@ 2026-10-28 2:13 ` sashiko-bot
0 siblings, 0 replies; 5+ messages in thread
From: sashiko-bot @ 2026-10-28 2:13 UTC (permalink / raw)
To: Emil Tsalapatis, bpf
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] selftests/bpf: unguarded arena dereference in arena_fault breaks no_alu32/bpf_gcc
--
commit 35e23b7a99b662f29a7ebcdbbc98176bb46d1150
Author: Emil Tsalapatis <emil@etsalapatis.com>
selftests/bpf: add arena fault recovery tests
This commit adds two BPF selftests and a supporting test kernel module to
verify arena page fault recovery when accessing an unbacked arena page from
a program with no arena or a program with a different arena map.
> diff --git a/tools/testing/selftests/bpf/progs/arena_fault.c b/tools/testing/selftests/bpf/progs/arena_fault.c
> new file mode 100644
> index 0000000000000..1967b128fdf69
> --- /dev/null
> +++ b/tools/testing/selftests/bpf/progs/arena_fault.c
> @@ -0,0 +1,55 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#define BPF_NO_KFUNC_PROTOTYPES
> +#include <vmlinux.h>
> +#include <bpf/bpf_helpers.h>
> +#include "bpf_arena_common.h"
> +#include "../test_kmods/bpf_test_arena_fault.h"
> +
> +struct {
> + __uint(type, BPF_MAP_TYPE_ARENA);
> + __uint(map_flags, BPF_F_MMAPABLE);
> + __uint(max_entries, 2);
> +} arena SEC(".maps");
> +
> +u64 __arena arena_pad;
> +volatile u64 observed;
> +
> +SEC("syscall")
> +int stash_and_free(void *ctx)
> +{
> + u64 __arena *val;
> +
> + val = bpf_arena_alloc_pages(&arena, NULL, 1, NUMA_NO_NODE, 0);
> + if (!val)
> + return 1;
> +
> + *val = 42;
> + bpf_test_arena_fault_stash((u64 *)val);
> + bpf_arena_free_pages(&arena, val, 1);
> + return 0;
> +}
> +
> +SEC("syscall")
> +int fault_stashed_wrong_arena(void *ctx)
> +{
> + u64 __arena *val;
> +
> + val = bpf_arena_alloc_pages(&arena, NULL, 1, NUMA_NO_NODE, 0);
> + if (!val)
> + return 1;
> +
> + *val = 1;
[Severity: Medium]
Will stash_and_free() and fault_stashed_wrong_arena() fail BPF verification
under test_progs-no_alu32 and test_progs-bpf_gcc when __BPF_FEATURE_ADDR_SPACE_CAST
is not defined?
In tools/testing/selftests/bpf/libarena/include/bpf_arena_common.h, __arena
only includes __attribute__((address_space(1))) when
__BPF_FEATURE_ADDR_SPACE_CAST is defined:
#if defined(__BPF_FEATURE_ADDR_SPACE_CAST) && !defined(BPF_ARENA_FORCE_ASM)
#define __arena __attribute__((address_space(1))) __attribute__((btf_type_tag("arena")))
...
#else
#define __arena __attribute__((btf_type_tag("arena")))
When tools/testing/selftests/bpf/Makefile builds test_progs-no_alu32 (with
-mcpu=v2) or test_progs-bpf_gcc, __BPF_FEATURE_ADDR_SPACE_CAST is not
defined. Without __attribute__((address_space(1))), the compiler does not
emit a BPF_ADDR_SPACE_CAST instruction before dereferencing val in
*val = 42 and *val = 1.
Because bpf_arena_alloc_pages() returns void * in kernel BTF,
check_kfunc_call() in kernel/bpf/verifier.c leaves R0 typed as SCALAR_VALUE
until BPF_ADDR_SPACE_CAST converts it to PTR_TO_ARENA in check_alu_op().
Without that cast, check_mem_access() rejects the stores to *val as invalid
scalar memory accesses, causing arena_fault__open_and_load() in
test_wrong_arena() and test_no_arena() in
tools/testing/selftests/bpf/prog_tests/arena_fault.c to fail instead of
skipping.
Should the arena pointer dereferences in progs/arena_fault.c be guarded by
#if defined(__BPF_FEATURE_ADDR_SPACE_CAST) (with the runner skipping when
unsupported), similar to other arena selftests?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261028015141.10710-1-emil@etsalapatis.com?part=2
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH bpf 1/2] bpf: recover page faults across all arenas
2026-10-28 1:51 ` [PATCH bpf 1/2] bpf: recover page faults across all arenas Emil Tsalapatis
@ 2026-10-28 2:36 ` bot+bpf-ci
0 siblings, 0 replies; 5+ messages in thread
From: bot+bpf-ci @ 2026-10-28 2:36 UTC (permalink / raw)
To: emil, bpf
Cc: ast, andrii, eddyz87, memxor, daniel, emil, tj, ast, andrii,
daniel, martin.lau, eddyz87, yonghong.song, mason, ihor.solodrai
[-- Attachment #1: Type: text/plain, Size: 3027 bytes --]
> bpf: recover page faults across all arenas
TL;DR: Commit message only: the Fixes: tag may point at the wrong commit; the
arena-fault oops looks like it first became reachable in abdc2516f100, not
9eca087deb0b.
> bpf: recover page faults across all arenas
>
> The current arena fault handling code accounts for
> misbehaving BPF programs that free arena memory
> while it is being accessed by a kfunc as part of
> another BPF program's execution. This scenario
> triggers a kernel page fault that is intercepted
> by BPF arena-specific code. The code confirms
> that the fault is within the BPF program's arena,
> installs a scratch page, and marks the fault as
> handled. This is necessary to prevent BPF programs
> from being able to trigger an oops.
>
> However, the protection against misbehaving BPF programs
> is currently incomplete: Arena memory is accessed by
> kernel code not just as part of a kfunc, but also from
> non-BPF paths. This is the case with sched-ext that
> includes non-BPF code paths that access arena pointers.
> These paths do not have an arena associated with them,
> and a fault there causes an oops. Such a fault can be
> triggered by a misbehaving BPF program by unmapping the
> pages nominally owned by the genpool allocator used for
> cid management.
>
> Extend the kernel arena fault handling to consider all
> arenas in the system. The handler now scans a global
> arena list till it finds an arena that includes the address,
> and fixes up the address. Retain the stream-based reporting
> code for when the faulting call stack includes the BPF
> program that owns the arena.
>
> Fixes: 9eca087deb0b ("sched_ext: Sub-allocator over kernel-claimed BPF arena pages")
> Cc: Tejun Heo <tj@kernel.org>
> Signed-off-by: Emil Tsalapatis <emil@etsalapatis.com>
Is the Fixes: tag pointing at the right commit?
9eca087deb0b only adds a gen_pool whose bookkeeping bitmap lives in ordinary
kernel memory (chunk->bits), and at that commit scx_arena_alloc() has no
callers. Nothing there dereferences arena memory from a non-BPF path.
The oops described above looks like it first became reachable in
abdc2516f100, where scx_call_op_set_cpumask() calls scx_cpumask_to_cmask()
to write into the per-CPU arena cmask through the kern_va mapping. That
happens with only the rq lock held and no BPF program on the stack, so
bpf_arena_handle_page_fault() returns false because
bpf_prog_find_from_stack() finds no program. The pool is first used via
scx_set_cmask_scratch_alloc().
The fault handler itself came from dc11a4dba246 ("bpf: Recover arena kernel
faults with scratch page"), but its limitation only matters once a non-BPF
path touches arena memory.
Should this be:
Fixes: abdc2516f100 ("sched_ext: Convert ops.set_cmask() to arena-resident cmask")
---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/40619190018
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-10-28 2:36 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-28 1:51 [PATCH bpf-next 0/2] bpf: expand BPF arena kernel fault handling Emil Tsalapatis
2026-10-28 1:51 ` [PATCH bpf 1/2] bpf: recover page faults across all arenas Emil Tsalapatis
2026-10-28 2:36 ` bot+bpf-ci
2026-10-28 1:51 ` [PATCH bpf 2/2] selftests/bpf: add arena fault recovery tests Emil Tsalapatis
2026-10-28 2:13 ` sashiko-bot
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.