BPF List
 help / color / mirror / Atom feed
From: Kumar Kartikeya Dwivedi <memxor@gmail.com>
To: bpf@vger.kernel.org
Cc: Alexei Starovoitov <ast@kernel.org>,
	Andrii Nakryiko <andrii@kernel.org>,
	Daniel Borkmann <daniel@iogearbox.net>,
	Eduard Zingerman <eddyz87@gmail.com>,
	Emil Tsalapatis <emil@etsalapatis.com>,
	kkd@meta.com, kernel-team@meta.com
Subject: [RFC PATCH bpf-next v1 14/16] selftests/bpf: Test typed arena object access, kptrs and typed pointer fields
Date: Sun, 27 Sep 2026 01:34:52 +0200	[thread overview]
Message-ID: <20260926233503.3114147-15-memxor@gmail.com> (raw)
In-Reply-To: <20260926233503.3114147-1-memxor@gmail.com>

Write and read a scalar field natively on a chunk faulted to scratch, run an
atomic on it, and move the pointer within the object; reject an access
beyond the object, a negative offset and a variable one. Walk a nested
struct and see a pointer to a kernel struct load as a scalar. See helpers
refuse the pointer as memory.

Exchange a kernel kptr into an object and out again, leave a local kptr in a
dummy object for the map to drop, and reject direct loads and stores of a
kptr field, an exchange on a scalar field and one with the wrong type.

Load a typed pointer field and see the pointer stay unsanitized until it is
used as an address: the dereference carries the mask, base load and add in
place, a compare of the value does not, a store of the raw value written by
hand is accepted, a second dereference through the same register does not
sanitize again, and pointer arithmetic sanitizes before it adds. A NULL
dereferences object 0 of the slice, whether held directly or loaded from
the field. The field takes a typed pointer, a loaded pointer or NULL, and
the compiler casts what a program assigns to it, so a scalar and a pointer
to another typed struct are accepted from C and rejected only when stored
by hand; reject a narrow load or store and an atomic. The same member in
raw arena memory is data: a stored pointer loads as a scalar and casts back
to its object where it is used. A struct whose only special field is a
pointer to a typed struct gets a typed arena of its own. One instruction
sanitizes one typed arena: reject it when two paths bring pointers of
different types, or a typed pointer on one path only, and reject the cast
the compiler inserts when one path brings a loaded arena pointer and
another an allocated object.

Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
 .../bpf/progs/verifier_typed_arena.c          | 634 ++++++++++++++++++
 1 file changed, 634 insertions(+)

diff --git a/tools/testing/selftests/bpf/progs/verifier_typed_arena.c b/tools/testing/selftests/bpf/progs/verifier_typed_arena.c
index 22a8c3bfd493..808a65611d4e 100644
--- a/tools/testing/selftests/bpf/progs/verifier_typed_arena.c
+++ b/tools/testing/selftests/bpf/progs/verifier_typed_arena.c
@@ -523,6 +523,640 @@ int narrow_store_is_invalid_spill(void *ctx)
 	return 0;
 }
 
+SEC("syscall")
+__description("a scalar field is written and read natively, on a chunk faulted to scratch")
+__success __retval(7)
+__stderr("ERROR: Typed arena WRITE access to unallocated struct typed_obj at 0x{{[0-9a-f]+}}")
+int access_scalar_field(void *ctx)
+{
+	struct typed_obj *obj;
+
+	arena_bind();
+	obj = ptr;
+	obj->value = 7;
+	return obj->value;
+}
+
+SEC("syscall")
+__description("atomics run natively on a scalar field")
+__success __retval(3)
+int access_atomic(void *ctx)
+{
+	struct typed_obj *obj;
+
+	arena_bind();
+	obj = ptr;
+	obj->value = 1;
+	__sync_fetch_and_add(&obj->value, 2);
+	return obj->value;
+}
+
+SEC("syscall")
+__description("pointer arithmetic stays inside the object")
+__success __retval(9)
+int access_after_arithmetic(void *ctx)
+{
+	struct typed_obj *obj;
+	void *p;
+
+	arena_bind();
+	obj = ptr;
+	p = obj;
+	asm volatile("%[p] += 8" : [p] "+r"(p));
+	*(__u64 *)p = 9;
+	return obj->value;
+}
+
+SEC("syscall")
+__description("an access beyond the object is rejected")
+__failure __msg("access beyond struct typed_obj")
+int access_beyond_object(void *ctx)
+{
+	struct typed_obj *obj;
+
+	arena_bind();
+	obj = ptr;
+	((__u64 *)obj)[2] = 1;
+	return 0;
+}
+
+SEC("syscall")
+__description("a negative offset is rejected")
+__failure __msg("invalid negative access")
+int access_negative_offset(void *ctx)
+{
+	struct typed_obj *obj;
+	void *p;
+
+	arena_bind();
+	obj = ptr;
+	p = (void *)obj - 8;
+	return *(__u64 *)p;
+}
+
+SEC("syscall")
+__description("a variable offset is rejected")
+__failure __msg("{{variable (offset|typed_arena_ptr_ access)}}")
+int access_variable_offset(void *ctx)
+{
+	struct typed_obj *obj;
+	void *p;
+
+	arena_bind();
+	obj = ptr;
+	p = (void *)obj + (bpf_get_prandom_u32() & 8);
+	return *(__u64 *)p;
+}
+
+struct mixed_obj {
+	struct task_struct __kptr *task;
+	struct {
+		__u32 a;
+		__u32 b;
+	} inner;
+	struct task_struct *ptr;
+};
+
+SEC("syscall")
+__description("nested structs are walked and pointers to kernel structs load as scalars")
+__success __retval(3)
+int access_nested_and_kernel_pointer_fields(void *ctx)
+{
+	struct mixed_obj *obj;
+
+	arena_bind();
+	obj = ptr;
+	obj->inner.b = 3;
+	if (obj->ptr)
+		return 1;
+	return obj->inner.b;
+}
+
+SEC("syscall")
+__description("helpers do not take typed arena pointers as memory")
+__failure __msg("R1 type=typed_arena_ptr_ expected=")
+int helper_rejects_typed_pointer(void *ctx)
+{
+	struct typed_obj *obj;
+	__u64 src = 0;
+
+	arena_bind();
+	obj = ptr;
+	bpf_probe_read_kernel(&obj->value, sizeof(obj->value), &src);
+	return 0;
+}
+
+struct arena_node {
+	__u64 v;
+};
+
+struct kptr_obj {
+	struct task_struct __kptr *task;
+	struct arena_node __kptr *node;
+	__u64 value;
+};
+
+SEC("syscall")
+__description("a kernel kptr is exchanged into and out of an object")
+__success __retval(0)
+int kptr_xchg_task(void *ctx)
+{
+	struct task_struct *task, *old;
+	struct kptr_obj *obj;
+
+	arena_bind();
+	obj = ptr;
+	task = bpf_task_acquire(bpf_get_current_task_btf());
+	if (!task)
+		return 2;
+	old = bpf_kptr_xchg(&obj->task, task);
+	if (old)
+		bpf_task_release(old);
+	old = bpf_kptr_xchg(&obj->task, NULL);
+	if (!old)
+		return 3;
+	bpf_task_release(old);
+	return 0;
+}
+
+SEC("syscall")
+__description("a local kptr left in a dummy object is dropped with the map")
+__success __retval(0)
+int kptr_xchg_local(void *ctx)
+{
+	struct arena_node *n, *old;
+	struct kptr_obj *obj;
+
+	arena_bind();
+	obj = ptr;
+	n = bpf_obj_new(struct arena_node);
+	if (!n)
+		return 2;
+	n->v = 42;
+	old = bpf_kptr_xchg(&obj->node, n);
+	if (old)
+		bpf_obj_drop(old);
+	return 0;
+}
+
+SEC("syscall")
+__description("a kptr field is not read directly")
+__failure __msg("direct access to kptr is disallowed")
+int kptr_read_directly(void *ctx)
+{
+	struct kptr_obj *obj;
+
+	arena_bind();
+	obj = ptr;
+	return obj->task != NULL;
+}
+
+SEC("syscall")
+__description("a kptr field is not written directly")
+__failure __msg("direct access to kptr is disallowed")
+int kptr_write_directly(void *ctx)
+{
+	struct kptr_obj *obj;
+
+	arena_bind();
+	obj = ptr;
+	obj->task = NULL;
+	return 0;
+}
+
+SEC("syscall")
+__description("an exchange needs a kptr field")
+__failure __msg("off=16 doesn't point to kptr")
+int kptr_xchg_scalar_field(void *ctx)
+{
+	struct kptr_obj *obj;
+
+	arena_bind();
+	obj = ptr;
+	bpf_kptr_xchg(&obj->value, NULL);
+	return 0;
+}
+
+SEC("syscall")
+__description("an exchange checks the value against the field's type")
+__failure __msg("invalid kptr access, R2 type=ptr_arena_node expected=ptr_task_struct")
+int kptr_xchg_wrong_type(void *ctx)
+{
+	struct kptr_obj *obj;
+	struct arena_node *n;
+
+	arena_bind();
+	obj = ptr;
+	n = bpf_obj_new(struct arena_node);
+	if (!n)
+		return 2;
+	n = bpf_kptr_xchg(&obj->task, n);
+	if (n)
+		bpf_obj_drop(n);
+	return 0;
+}
+
+/* 32-byte slot, linked through a typed pointer field: the sanitize mask is 134217696 */
+struct node_obj {
+	struct task_struct __kptr *task;
+	struct node_obj *next;
+	__u64 value;
+};
+
+/* The same layout as node_obj, a different typed arena */
+struct pair_obj {
+	struct task_struct __kptr *task;
+	struct pair_obj *next;
+	__u64 value;
+};
+
+/* 8-byte slot, typed only by its pointer to a typed struct: the cast mask is 134217720 */
+struct head_obj {
+	struct node_obj *first;
+};
+
+SEC("syscall")
+__description("a typed pointer field loads unsanitized, and a dereference sanitizes it in place")
+__success __retval(0) __log_level(2)
+__msg("R{{[0-9]}}=unsanitized_typed_arena_ptr_node_obj(")
+__xlated("r{{[0-9]}} &= 134217720")
+__xlated("r12 = 0x{{[0-9a-f]+}}")
+__xlated("r{{[0-9]}} += r12")
+__xlated("...")
+__xlated("r{{[0-9]}} = *(u64 *)(r{{[0-9]}} +0)")
+__xlated("r{{[0-9]}} &= 134217696")
+__xlated("r12 = 0x{{[0-9a-f]+}}")
+__xlated("r{{[0-9]}} += r12")
+__xlated("r{{[0-9]}} = *(u64 *)(r{{[0-9]}} +16)")
+int ptr_field_deref_sanitizes(void *ctx)
+{
+	struct head_obj *h;
+	struct node_obj *n;
+
+	arena_bind();
+	h = ptr;
+	n = h->first;
+	return n->value;
+}
+
+SEC("syscall")
+__description("a compare and a store of a loaded typed pointer use the raw value")
+__success __retval(0) __log_level(2)
+__msg("R{{[0-9]}}=unsanitized_typed_arena_ptr_node_obj(")
+__msg("if r{{[0-9]}} == 0x0 goto")
+__msg("R{{[0-9]}}=unsanitized_typed_arena_ptr_node_obj(")
+__msg("*(u64 *)(r1 +8) = r2")
+int ptr_field_compare_and_store_stay_raw(void *ctx)
+{
+	struct node_obj *n, *m;
+
+	arena_bind();
+	n = ptr;
+	m = n->next;
+	/* Opaque to the compiler, so that the compare is emitted. */
+	barrier_var(m);
+	if (!m)
+		return 0;
+	/* The store is written by hand: the compiler would cast the value first. */
+	asm volatile("r1 = %[n];"
+		     "r2 = %[m];"
+		     "*(u64 *)(r1 + 8) = r2;"
+		     :: [n] "r"(n), [m] "r"(m)
+		     : "r1", "r2", "memory");
+	return 0;
+}
+
+SEC("syscall")
+__description("a register sanitized by one dereference is not sanitized again by the next")
+__success __retval(5)
+__xlated("r1 = *(u64 *)(r1 +8)")
+__xlated("r2 = 5")
+__xlated("r1 &= 134217696")
+__xlated("r12 = 0x{{[0-9a-f]+}}")
+__xlated("r1 += r12")
+__xlated("*(u64 *)(r1 +16) = r2")
+__xlated("r0 = *(u64 *)(r1 +16)")
+int ptr_field_second_deref_not_sanitized_again(void *ctx)
+{
+	struct node_obj *n;
+	__u64 ret;
+
+	arena_bind();
+	n = ptr;
+	/* Written by hand: the compiler would cast copies rather than reuse the register. */
+	asm volatile("r1 = %[n];"
+		     "r1 = *(u64 *)(r1 + 8);"
+		     "r2 = 5;"
+		     "*(u64 *)(r1 + 16) = r2;"
+		     "r0 = *(u64 *)(r1 + 16);"
+		     "%[ret] = r0;"
+		     : [ret] "=r"(ret) : [n] "r"(n)
+		     : "r0", "r1", "r2", "memory");
+	return ret;
+}
+
+SEC("syscall")
+__description("pointer arithmetic on a loaded typed pointer sanitizes it first")
+__success __retval(0)
+__xlated("r{{[0-9]}} = *(u64 *)(r{{[0-9]}} +8)")
+__xlated("...")
+__xlated("r1 &= 134217696")
+__xlated("r12 = 0x{{[0-9a-f]+}}")
+__xlated("r1 += r12")
+__xlated("r1 += 16")
+__xlated("*(u64 *)(r1 +0) = r2")
+int ptr_field_arithmetic_sanitizes(void *ctx)
+{
+	struct node_obj *n, *m;
+
+	arena_bind();
+	n = ptr;
+	m = n->next;
+	asm volatile("r1 = %[m];"
+		     "r2 = 0;"
+		     "r1 += 16;"
+		     "*(u64 *)(r1 + 0) = r2;"
+		     :: [m] "r"(m)
+		     : "r1", "r2", "memory");
+	return 0;
+}
+
+SEC("syscall")
+__description("a NULL typed pointer dereferences object 0 of the slice, held directly or loaded from a field")
+__success __retval(42)
+int ptr_field_null_lands_on_object_zero(void *ctx)
+{
+	struct node_obj *zero = NULL, *n, *m;
+
+	arena_bind();
+	/*
+	 * The compiler treats a NULL dereference as undefined and would drop
+	 * the store, fold the stored NULL into the load and the load into
+	 * nothing; the barriers keep each value opaque so that the accesses
+	 * are emitted.
+	 */
+	barrier_var(zero);
+	zero->value = 42;
+	n = ptr;
+	n->next = NULL;
+	barrier_var(n);
+	m = n->next;
+	barrier_var(m);
+	return m->value;
+}
+
+SEC("syscall")
+__description("a typed pointer field takes a typed pointer, a loaded one, or NULL")
+__success __retval(0)
+int ptr_field_store_accepted(void *ctx)
+{
+	struct node_obj *n, *m, *p;
+
+	arena_bind();
+	n = ptr;
+	m = ptr2;
+	n->next = m;
+	p = m->next;
+	n->next = p;
+	n->next = NULL;
+	return 0;
+}
+
+SEC("syscall")
+__description("a typed pointer field does not take a scalar")
+__failure __msg("store into typed pointer field of struct node_obj expects a typed arena pointer to struct node_obj or NULL")
+int ptr_field_store_scalar_rejected(void *ctx)
+{
+	struct node_obj *n;
+
+	arena_bind();
+	n = ptr;
+	/* Written by hand: the compiler would cast the value before the store. */
+	asm volatile("r6 = %[n];"
+		     "call %[bpf_get_prandom_u32];"
+		     "r1 = r6;"
+		     "*(u64 *)(r1 + 8) = r0;"
+		     :: [n] "r"(n), __imm(bpf_get_prandom_u32)
+		     : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "memory");
+	return 0;
+}
+
+SEC("syscall")
+__description("a scalar assigned to a typed pointer field is cast by the compiler first")
+__success __retval(0)
+__xlated("call unknown")
+__xlated("...")
+__xlated("r{{[0-9]}} &= 134217696")
+__xlated("r12 = 0x{{[0-9a-f]+}}")
+__xlated("r{{[0-9]}} += r12")
+__xlated("*(u64 *)(r{{[0-9]}} +8) = r{{[0-9]}}")
+int ptr_field_store_scalar_cast_by_compiler(void *ctx)
+{
+	struct node_obj *n;
+
+	arena_bind();
+	n = ptr;
+	n->next = (void *)(long)bpf_get_prandom_u32();
+	return 0;
+}
+
+SEC("syscall")
+__description("a typed pointer field does not take a pointer to another typed struct")
+__failure __msg("store into typed pointer field of struct node_obj expects a typed arena pointer to struct node_obj or NULL")
+int ptr_field_store_other_type_rejected(void *ctx)
+{
+	struct typed_obj *other;
+	struct node_obj *n;
+
+	arena_bind();
+	n = ptr;
+	other = ptr;
+	/* Written by hand: the compiler would re-cast the value to node_obj first. */
+	asm volatile("r1 = %[n];"
+		     "r2 = %[o];"
+		     "*(u64 *)(r1 + 8) = r2;"
+		     :: [n] "r"(n), [o] "r"(other)
+		     : "r1", "r2", "memory");
+	return 0;
+}
+
+SEC("syscall")
+__description("a pointer to another typed struct assigned to a typed pointer field is re-cast by the compiler")
+__success __retval(0)
+int ptr_field_store_other_type_recast(void *ctx)
+{
+	struct typed_obj *other;
+	struct node_obj *n;
+
+	arena_bind();
+	n = ptr;
+	other = ptr;
+	n->next = (struct node_obj *)other;
+	return n->next == NULL;
+}
+
+SEC("syscall")
+__description("a typed pointer field is loaded whole")
+__failure __msg("typed pointer field of struct node_obj must be accessed with a 64-bit load or store")
+int ptr_field_narrow_load_rejected(void *ctx)
+{
+	struct node_obj *n;
+
+	arena_bind();
+	n = ptr;
+	asm volatile("r1 = %[n];"
+		     "w2 = *(u32 *)(r1 + 8);"
+		     :: [n] "r"(n)
+		     : "r1", "r2");
+	return 0;
+}
+
+SEC("syscall")
+__description("a typed pointer field is stored whole")
+__failure __msg("typed pointer field of struct node_obj must be accessed with a 64-bit load or store")
+int ptr_field_narrow_store_rejected(void *ctx)
+{
+	struct node_obj *n;
+
+	arena_bind();
+	n = ptr;
+	asm volatile("r1 = %[n];"
+		     "w2 = 0;"
+		     "*(u32 *)(r1 + 8) = w2;"
+		     :: [n] "r"(n)
+		     : "r1", "r2", "memory");
+	return 0;
+}
+
+SEC("syscall")
+__description("a typed pointer field takes no atomic operation")
+__failure __msg("typed pointer field of struct node_obj")
+int ptr_field_atomic_rejected(void *ctx)
+{
+	struct node_obj *n, *m;
+
+	arena_bind();
+	n = ptr;
+	m = ptr2;
+	__sync_val_compare_and_swap((__u64 *)&n->next, 0, (__u64)m);
+	return 0;
+}
+
+/* The same member outside a typed object is data */
+struct raw_holder {
+	struct node_obj *n;
+	__u64 v;
+};
+
+SEC("syscall")
+__description("a pointer stored in raw arena memory loads as a scalar and casts back to its object")
+__success __retval(0)
+int ptr_field_in_raw_memory_is_scalar(void *ctx)
+{
+	struct raw_holder __arena *h;
+	struct node_obj *n, *again;
+
+	h = bpf_arena_alloc_pages(&arena, NULL, 1, NUMA_NO_NODE, 0);
+	if (!h)
+		return 1;
+	n = ptr;
+	n->value = 7;
+	h->n = n;
+	again = h->n;
+	return again != n || again->value != 7;
+}
+
+SEC("syscall")
+__description("a struct typed only by a pointer to a typed struct gets a typed arena of its own")
+__success __retval(0) __log_level(2)
+__msg("typed arena for struct head_obj: slot 8 bytes")
+int ptr_field_makes_struct_typed(void *ctx)
+{
+	struct head_obj *h;
+	struct node_obj *n;
+
+	arena_bind();
+	h = ptr;
+	n = ptr2;
+	h->first = n;
+	return h->first != n;
+}
+
+/*
+ * The cast the compiler inserts is one instruction on every path through it:
+ * a loaded typed pointer needs the sanitizing sequence there, an allocated
+ * object needs the identity, and the two cannot share a lowering.
+ */
+SEC("syscall")
+__description("one cast cannot both sanitize an arena pointer and pass an allocated object")
+__failure __msg("casts values that need different treatment on different paths")
+int cast_conflicts_between_arena_and_allocated(void *ctx)
+{
+	struct node_obj *n, *a;
+	struct head_obj *h;
+
+	arena_bind();
+	a = bpf_obj_new(struct node_obj);
+	if (!a)
+		return 1;
+	h = ptr;
+	if (bpf_get_prandom_u32() & 1)
+		n = h->first;
+	else
+		n = a;
+	n->value = 1;
+	bpf_obj_drop(a);
+	return 0;
+}
+
+SEC("syscall")
+__description("one instruction sanitizes one typed arena: two types on two paths are rejected")
+__failure __msg("sanitizes typed arena pointers of different types on different paths")
+int ptr_field_sanitize_two_types_at_one_insn(void *ctx)
+{
+	struct node_obj *n;
+	struct pair_obj *p;
+
+	arena_bind();
+	n = ptr;
+	p = ptr;
+	asm volatile("call %[bpf_get_prandom_u32];"
+		     "if r0 == 0 goto 1f;"
+		     "r1 = %[n];"
+		     "r1 = *(u64 *)(r1 + 8);"
+		     "goto 2f;"
+		     "1: r1 = %[p];"
+		     "r1 = *(u64 *)(r1 + 8);"
+		     "2: r2 = *(u64 *)(r1 + 16);"
+		     :: [n] "r"(n), [p] "r"(p), __imm(bpf_get_prandom_u32)
+		     : "r0", "r1", "r2", "r3", "r4", "r5", "memory");
+	return 0;
+}
+
+SEC("syscall")
+__description("one instruction sanitizes one typed arena: a typed pointer on one path only is rejected")
+__failure __msg("sanitizes a typed arena pointer only on some paths")
+int ptr_field_sanitize_on_one_path(void *ctx)
+{
+	struct node_obj *n;
+
+	arena_bind();
+	n = ptr;
+	asm volatile("r2 = 0;"
+		     "*(u64 *)(r10 - 16) = r2;"
+		     "call %[bpf_get_prandom_u32];"
+		     "if r0 == 0 goto 1f;"
+		     "r1 = %[n];"
+		     "r1 = *(u64 *)(r1 + 8);"
+		     "goto 2f;"
+		     "1: r1 = r10;"
+		     "r1 += -32;"
+		     "2: r2 = *(u64 *)(r1 + 16);"
+		     :: [n] "r"(n), __imm(bpf_get_prandom_u32)
+		     : "r0", "r1", "r2", "r3", "r4", "r5", "memory");
+	return 0;
+}
+
 #endif /* __BPF_FEATURE_TYPED_ARENA_CAST */
 
 char _license[] SEC("license") = "GPL";
-- 
2.53.0


  parent reply	other threads:[~2026-09-26 23:35 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-26 23:34 [RFC PATCH bpf-next v1 00/16] BPF typed arenas Kumar Kartikeya Dwivedi
2026-09-26 23:34 ` [RFC PATCH bpf-next v1 01/16] mm/vmalloc: Add get_vm_area_align() Kumar Kartikeya Dwivedi
2026-09-26 23:42   ` sashiko-bot
2026-09-26 23:34 ` [RFC PATCH bpf-next v1 02/16] bpf: Introduce BPF typed arenas Kumar Kartikeya Dwivedi
2026-09-26 23:34 ` [RFC PATCH bpf-next v1 03/16] bpf: Back typed arena chunks with scratch on demand Kumar Kartikeya Dwivedi
2026-09-26 23:56   ` sashiko-bot
2026-09-26 23:34 ` [RFC PATCH bpf-next v1 04/16] bpf: Add the typed_arena_cast instruction Kumar Kartikeya Dwivedi
2026-09-26 23:55   ` sashiko-bot
2026-09-26 23:34 ` [RFC PATCH bpf-next v1 05/16] bpf: Allow scalar and atomic access to typed arena objects Kumar Kartikeya Dwivedi
2026-09-26 23:34 ` [RFC PATCH bpf-next v1 06/16] bpf: Support special fields in " Kumar Kartikeya Dwivedi
2026-09-26 23:59   ` sashiko-bot
2026-09-26 23:34 ` [RFC PATCH bpf-next v1 07/16] bpf: Trust typed pointer fields of " Kumar Kartikeya Dwivedi
2026-09-27  0:03   ` sashiko-bot
2026-09-26 23:34 ` [RFC PATCH bpf-next v1 08/16] bpf: Canonicalize loaded typed arena pointers where they are used Kumar Kartikeya Dwivedi
2026-09-26 23:34 ` [RFC PATCH bpf-next v1 09/16] bpf: Add typed arena page allocation and release kfuncs Kumar Kartikeya Dwivedi
2026-09-26 23:55   ` sashiko-bot
2026-09-26 23:34 ` [RFC PATCH bpf-next v1 10/16] bpf: Let typed_arena_cast copy pointers the verifier already trusts Kumar Kartikeya Dwivedi
2026-09-26 23:49   ` sashiko-bot
2026-09-26 23:34 ` [RFC PATCH bpf-next v1 11/16] libbpf: Support the typed_arena_cast instruction Kumar Kartikeya Dwivedi
2026-09-26 23:34 ` [RFC PATCH bpf-next v1 12/16] selftests/bpf: Build BPF objects with compiler-inserted typed arena casts Kumar Kartikeya Dwivedi
2026-09-26 23:46   ` sashiko-bot
2026-09-26 23:34 ` [RFC PATCH bpf-next v1 13/16] selftests/bpf: Test typed arena casts and registration Kumar Kartikeya Dwivedi
2026-09-26 23:34 ` Kumar Kartikeya Dwivedi [this message]
2026-09-26 23:34 ` [RFC PATCH bpf-next v1 15/16] selftests/bpf: Test typed arena page allocation and release Kumar Kartikeya Dwivedi
2026-09-26 23:46   ` sashiko-bot
2026-09-26 23:34 ` [RFC PATCH bpf-next v1 16/16] selftests/bpf: Exercise typed arenas at run time Kumar Kartikeya Dwivedi
2026-09-26 23:50   ` 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=20260926233503.3114147-15-memxor@gmail.com \
    --to=memxor@gmail.com \
    --cc=andrii@kernel.org \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=eddyz87@gmail.com \
    --cc=emil@etsalapatis.com \
    --cc=kernel-team@meta.com \
    --cc=kkd@meta.com \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox