All of lore.kernel.org
 help / color / mirror / Atom feed
From: Emil Tsalapatis <emil@etsalapatis.com>
To: bpf@vger.kernel.org
Cc: ast@kernel.org, andrii@kernel.org, eddyz87@gmail.com,
	memxor@gmail.com, daniel@iogearbox.net,
	Emil Tsalapatis <emil@etsalapatis.com>, Tejun Heo <tj@kernel.org>
Subject: [PATCH bpf 1/2] bpf: recover page faults across all arenas
Date: Wed, 28 Oct 2026 01:51:40 +0000	[thread overview]
Message-ID: <20261028015141.10710-2-emil@etsalapatis.com> (raw)
In-Reply-To: <20261028015141.10710-1-emil@etsalapatis.com>

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


  reply	other threads:[~2026-10-28  1:51 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 [this message]
2026-10-28  2:36   ` [PATCH bpf 1/2] bpf: recover page faults across all arenas 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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261028015141.10710-2-emil@etsalapatis.com \
    --to=emil@etsalapatis.com \
    --cc=andrii@kernel.org \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=eddyz87@gmail.com \
    --cc=memxor@gmail.com \
    --cc=tj@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.