summaryrefslogtreecommitdiff
path: root/include/linux
diff options
context:
space:
mode:
authorKumar Kartikeya Dwivedi <memxor@gmail.com>2026-10-19 15:21:49 +0200
committerAlexei Starovoitov <ast@kernel.org>2026-10-19 19:45:03 +0000
commit7efe1d4e11395e31c49122f0052b57f0513c7e83 (patch)
tree9362acde7cf09d6c4ec876bf7b7f31bd1f6b2c83 /include/linux
parentbc7c2824682be8dda2e0aa43b08aff822b8fca0d (diff)
bpf: Turn loads of __arena pointer members into arena pointers
A kernel struct shared with BPF programs may want to point at arena memory, e.g. a sched_ext argument struct that the kernel builds in the scheduler's arena and that refers to another arena object. A pointer member reaches the program typed as a kernel pointer, so sched_ext publishes a plain u64 holding a pre-translated arena address that the program casts before use. Translate in the verifier instead. When a load through a kernel struct pointer lands on a member tagged __arena, btf_struct_walk() reports it and the destination register becomes PTR_TO_ARENA. The member holds the kernel address of the arena memory; the fixup pass appends the conversion to the arena pointer form that the struct_ops trampoline applies to __arena arguments, after a plain load or a load-acquire of the member: r1 = *(u64 *)(r2 + off) if r1 == 0 goto +1 // __nullable members and probed loads w1 -= lo32(kern_vm_start) A probed load, through a plain or an untrusted pointer, keeps the NULL test as well: it reads as 0 when it faults, and the subtraction must not turn that into an arena pointer. An acquire load only comes through a pointer that cannot fault. Stores to kernel structs are rejected as before, and with them the atomics that write such a member. A member inside a multi-member union is rejected too: an offset into a union resolves to its first member, so a program reading another member there would receive an arena pointer it did not ask for. Loads through program-allocated objects and program BTF are unaffected, there the tag is what the compiler emits for the arena address space. The rewrite is per insn while verification is per path, so the aux data records what an insn loaded on any path: an insn that loaded an arena pointer member on one path and a different member on another is rejected by the fixup pass, while paths disagreeing only on __nullable keep the NULL test, which a never-NULL member can afford. As for __arena arguments, the program needs an associated arena, which also supplies the base to subtract. Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org> Link: https://patch.msgid.link/20261019132203.3034698-8-memxor@gmail.com
Diffstat (limited to 'include/linux')
-rw-r--r--include/linux/bpf_verifier.h8
1 files changed, 8 insertions, 0 deletions
diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
index 951a90458d18..54481da4ed2d 100644
--- a/include/linux/bpf_verifier.h
+++ b/include/linux/bpf_verifier.h
@@ -793,6 +793,14 @@ struct bpf_insn_aux_data {
*/
u64 fastcall_spills_num:3;
u64 arg_prog:4;
+ /*
+ * What a load found, on any path: an __arena pointer member of a
+ * kernel struct, which arena_member_fixup() rewrites, one that is
+ * __nullable as well, or anything else through any pointer.
+ */
+ u64 arena_member:1;
+ u64 arena_member_nullable:1;
+ u64 non_arena_load:1;
/* below flags are initialized once */
u64 jmp_point:1;