From: "Alexei Starovoitov" <alexei.starovoitov@gmail.com>
To: "Kumar Kartikeya Dwivedi" <memxor@gmail.com>
Cc: <bpf@vger.kernel.org>, <daniel@iogearbox.net>,
<andrii@kernel.org>, <eddyz87@gmail.com>
Subject: Re: [PATCH bpf 26/81] bpf: Support BPF_REG_ARENA_SP in the verifier
Date: Tue, 27 Oct 2026 18:45:44 +0000 [thread overview]
Message-ID: <DMFUDQAC6N4S.1CNBGYKG58DMR@gmail.com> (raw)
In-Reply-To: <CAP01T75HAHkP4bzdGzeazN4n_FNd5w1Pckd3GBN68V0n1PNe_w@mail.gmail.com>
On Mon, Oct 26, 2026 at 5:18 PM Kumar Kartikeya Dwivedi <memxor@gmail.com> wrote:
> Overall, I think it is less clear to me (or anyone looking at patches)
> as to why you did things this way.
point taken.
I was wrong in my previous email. An iterator over kernel objects
stays in the r10 stack, and it works today.
> Are there real patterns that existing stack tracking simply cannot
> salvage?
Yes.
Pattern 1: one insn, two kinds of memory
sum(&local_array) r1 = fp-64 --+
+--> r2 = *(u64 *)(r1 + 0)
sum(&vec) r1 = arena --+
one insn, one JIT form
We discussed an idea to let llvm clone such function.
I tried it, and it didn't work.
Short summary:
case why a copy does not help
--------------------------------- ------------------------------------
the pointer comes from memory no kind for the compiler, a scalar
for the verifier
an indirect call: &dyn Trait, fmt one function for the two kinds
if c { &local } else { &*boxed } one pointer, two kinds, one function
n pointer arguments up to 2^n copies
and real case in <&PanicInfo as Display>::fmt().
Pattern 2: the address of a local goes to memory, a load gives a scalar
That's typical rust heap.
Pattern 3: LLVM removes a bounds check, here in core::fmt::num
loop { remain /= 10000; offset -= 4; buf[offset] = ...; }
and 'buf' is on stack.
run-time clamp won't help, since real tracked spill/fills are in r10.
Pattern 4: fp in an argument
...
So an address-taken local must be where the heap is... in arena.
experiments for arena-stack
where the local is what breaks it
-------------------------------------- ---------------------------------
- structs by value, more inlining an optimization. Pattern 2 stays
- a second vm area or arena, a map value a different base: pattern 1
- arena, a fixed frame for each function recursion, a second run on the
and cpu, as in the private stack same cpu
- arena stack, sp in a per-cpu cell preemption, see below
- arena stack, sp in bpf_run_ctx load, add, store in each function
- arena stack, sp in a hidden argument an argument and a callee saved
register. BTF does not match
- arena stack, sp in a reserved r9 a verifier change too, and one
register less for the prog
- arena stack, sp in r12, the kernel the series. It costs verifier
supplies the stack code and a register in each JIT
The choices made for this arena-stack design:
in the series what was rejected and why
------------------------------- ----------------------------------------
- one 'r12 += N', the first insn 'r12 -= rX': the depth has no bound
of a function several 'r12 += imm': verifier state
- the verifier tracks nothing tracked slots: a store through a scalar
invalidates them
- 'rX = r12' gives a scalar PTR_TO_ARENA: after a load from memory
it is a scalar. Two types at one insn
- the cast of a kernel pointer is an error: two progs cannot share
a move (patch 18) fill(&mut Event), ring buffer and Box
- the kernel supplies the stacks, compiler, libbpf: the entry code is in
one set for each arena each object file
- contiguous, 32 Kbyte at most, fixed, 4 per cpu: 512 Mbyte of addresses
pages at the first use segments: each function can fail
pages on a fault: can fail in mid-run
- regular arena pages hidden from user space: no gain. It can
corrupt all other data of the prog
- a run takes the per-cpu stack: preemption off: no sleepable progs
a counter, local xadd. If it is two calls, get and put: 4 nsec
taken: one of 16 more stacks, split, sleepable or not: two mechanisms
then new pages skip the second run: not for a scheduler
- grows up: r12 - off, like r10 down, r12 + off: harder to read
- x86-64: R9. Arg 6 of a BPF call reject 6 arguments: Rust has them
is on the stack r12 in a frame slot: a load per access
- a callback takes its own stack reject r12 there: scx_central needs it
- bpf_throw() keeps the stack: a slot in the frame of main: an irq
the kernel frees the arena as overwrites it after rsp = rbp
a whole, and Rust unwinds give back first: no record of new pages
> It might require teaching the compiler not to move certain types on
> the stack to r12 relative accesses, but it just feels ugly.
it might feel fragile, but it worked for huge corpus of rust crates:
https://github.com/llvm/llvm-project/pull/235577
Your dsq iterator exapmle is 'alloca [48 x i8]' in the IR, so it works
(I replied too soon yesteday).
llvm selects the stack by use:
rule 1 r10 The function that owns the local passes its address to
a helper or a kfunc: iterator, irq flag, dynptr, map key.
rule 2 r10 The prog stores a kernel pointer in it and loads it again.
Also a local that holds the address of such a local.
else r12
> For certain things, like open coded iterators on kernel collections,
> there is no other choice.
Of the 16 rust sched that I hacked 4 walk dsq and 13 call
bpf_local_irq_save(). In testing they loaded and *run*.
But I agree that passing them around is fragile.
The hope is for typed arena to save the day.
Then rule 2 will go away.
> unsure how various assumptions around address contiguity get affected
> when stack reuse occurs [...]
A local never changes its stack, and it is contiguous. The compiler selects
the stack after all IR optimizations, for the full alloca and
its full life. r12 locals have a stack id of their own, and stack coloring merges
only objects with the same id. An iterator in one scope and a buffer in the
next are two allocas, one in each stack.
next prev parent reply other threads:[~2026-10-27 18:45 UTC|newest]
Thread overview: 144+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-26 2:58 [PATCH bpf 00/81] bpf: Stack in arena and a verifier that joins states Alexei Starovoitov
2026-10-26 2:58 ` [PATCH bpf 01/81] selftests/bpf: Remove tests for global data in arena Alexei Starovoitov
2026-10-26 2:58 ` [PATCH bpf 02/81] libbpf: Remove .arena.data Alexei Starovoitov
2026-10-26 2:58 ` [PATCH bpf 03/81] libbpf: Keep format strings of bpf_printk() in .rodata Alexei Starovoitov
2026-10-26 2:58 ` [PATCH bpf 04/81] selftests/bpf: Remove tests for arena access through numbers Alexei Starovoitov
2026-10-26 2:58 ` [PATCH bpf 05/81] bpf: Remove BPF_F_ARENA_SCALAR Alexei Starovoitov
2026-10-26 2:58 ` [PATCH bpf 06/81] bpf, x86: Remove r0_on_stack from fetching atomics in arena Alexei Starovoitov
2026-10-26 2:58 ` [PATCH bpf 07/81] bpf: One time slice of may_goto for a run of a prog Alexei Starovoitov
2026-10-26 12:50 ` kernel test robot
2026-10-26 14:43 ` kernel test robot
2026-10-26 17:35 ` Kumar Kartikeya Dwivedi
2026-10-27 16:39 ` Alexei Starovoitov
2026-10-26 2:58 ` [PATCH bpf 08/81] selftests/bpf: Test may_goto in a loop that calls a subprog that spins Alexei Starovoitov
2026-10-26 2:58 ` [PATCH bpf 09/81] bpf: Clear delta of a register that scalar evolution widens Alexei Starovoitov
2026-10-26 20:09 ` Daniel Borkmann
2026-10-27 21:23 ` Alexei Starovoitov
2026-10-26 2:58 ` [PATCH bpf 10/81] selftests/bpf: Test that a widened register is not linked Alexei Starovoitov
2026-10-26 2:58 ` [PATCH bpf 11/81] selftests/bpf: Wait for the last maps of map_kptr to be freed Alexei Starovoitov
2026-10-26 2:58 ` [PATCH bpf 12/81] bpf: Don't widen a pointer to a buffer in scalar evolution Alexei Starovoitov
2026-10-26 2:58 ` [PATCH bpf 13/81] selftests/bpf: Test a loop that moves a pointer to a buffer Alexei Starovoitov
2026-10-26 2:58 ` [PATCH bpf 14/81] bpf: Fix a false verifier bug in the clamp of scalar evolution Alexei Starovoitov
2026-10-26 23:45 ` Eduard Zingerman
2026-10-27 16:32 ` Alexei Starovoitov
2026-10-26 2:58 ` [PATCH bpf 15/81] selftests/bpf: Test induction variables that come back out of range Alexei Starovoitov
2026-10-26 2:58 ` [PATCH bpf 16/81] libbpf: Make arena 1 Gbyte when max_entries is not set Alexei Starovoitov
2026-10-26 16:54 ` Andrii Nakryiko
2026-10-26 16:59 ` Kumar Kartikeya Dwivedi
2026-10-27 0:13 ` Alexei Starovoitov
2026-10-27 21:11 ` Kumar Kartikeya Dwivedi
2026-10-27 21:22 ` Alexei Starovoitov
2026-10-27 21:28 ` Andrii Nakryiko
2026-10-27 21:29 ` Kumar Kartikeya Dwivedi
2026-10-26 2:58 ` [PATCH bpf 17/81] selftests/bpf: Test the default size of arena Alexei Starovoitov
2026-10-26 2:58 ` [PATCH bpf 18/81] bpf: Treat addr_space_cast of a pointer that is not in arena as a move Alexei Starovoitov
2026-10-26 2:58 ` [PATCH bpf 19/81] selftests/bpf: Test addr_space_cast of pointers that are not in arena Alexei Starovoitov
2026-10-26 2:58 ` [PATCH bpf 20/81] libbpf: Support .bss.addr_space.1 section Alexei Starovoitov
2026-10-26 2:58 ` [PATCH bpf 21/81] libbpf: Relocate pointers that are stored in arena Alexei Starovoitov
2026-10-26 2:58 ` [PATCH bpf 22/81] selftests/bpf: Test pointers in arena and .bss.addr_space.1 Alexei Starovoitov
2026-10-26 2:58 ` [PATCH bpf 23/81] bpf: Introduce bpf register BPF_REG_ARENA_SP Alexei Starovoitov
2026-10-26 2:58 ` [PATCH bpf 24/81] bpf: Add stacks for programs to arena Alexei Starovoitov
2026-10-26 2:58 ` [PATCH bpf 25/81] bpf, x86: Add BPF_ATOMIC_LOCAL Alexei Starovoitov
2026-10-26 2:58 ` [PATCH bpf 26/81] bpf: Support BPF_REG_ARENA_SP in the verifier Alexei Starovoitov
2026-10-26 17:47 ` Kumar Kartikeya Dwivedi
2026-10-26 23:51 ` Alexei Starovoitov
2026-10-27 0:18 ` Kumar Kartikeya Dwivedi
2026-10-27 18:45 ` Alexei Starovoitov [this message]
2026-10-27 20:23 ` Kumar Kartikeya Dwivedi
2026-10-28 4:47 ` Alexei Starovoitov
2026-10-28 11:00 ` Kumar Kartikeya Dwivedi
2026-10-26 2:58 ` [PATCH bpf 27/81] bpf, x86: Support BPF_REG_ARENA_SP Alexei Starovoitov
2026-10-26 2:58 ` [PATCH bpf 28/81] bpf, arm64: " Alexei Starovoitov
2026-10-26 2:58 ` [PATCH bpf 29/81] selftests/bpf: Add tests for BPF_REG_ARENA_SP Alexei Starovoitov
2026-10-26 2:58 ` [PATCH bpf 30/81] bpf: Add bpf_arena_memcmp() and bpf_arena_memcpy() kfuncs Alexei Starovoitov
2026-10-26 2:58 ` [PATCH bpf 31/81] bpf: Add bpf_alloc() and bpf_free() kfuncs Alexei Starovoitov
2026-10-26 2:58 ` [PATCH bpf 32/81] bpf: Count stack arguments of a static subprog from its code Alexei Starovoitov
2026-10-26 3:53 ` bot+bpf-ci
2026-10-26 2:58 ` [PATCH bpf 33/81] selftests/bpf: Test static subprogs that don't take what BTF says Alexei Starovoitov
2026-10-26 2:58 ` [PATCH bpf 34/81] bpf: Let scalar evolution see loads from read-only maps Alexei Starovoitov
2026-10-26 2:58 ` [PATCH bpf 35/81] selftests/bpf: Test scalar evolution with a loop bound in .rodata Alexei Starovoitov
2026-10-26 2:58 ` [PATCH bpf 36/81] bpf: Helpers don't write through ARG_ANYTHING Alexei Starovoitov
2026-10-26 2:58 ` [PATCH bpf 37/81] selftests/bpf: Test scalar evolution with stack address as ARG_ANYTHING Alexei Starovoitov
2026-10-26 2:58 ` [PATCH bpf 38/81] bpf: Simplify (zext32 (zext32 x)) in scalar evolution Alexei Starovoitov
2026-10-26 2:59 ` [PATCH bpf 39/81] selftests/bpf: Test scalar evolution with a latch on a 32-bit copy Alexei Starovoitov
2026-10-26 2:59 ` [PATCH bpf 40/81] bpf: Keep the range of a packet pointer when a number >= 0 is added Alexei Starovoitov
2026-10-26 2:59 ` [PATCH bpf 41/81] selftests/bpf: Test range of a packet pointer after a number " Alexei Starovoitov
2026-10-26 3:53 ` bot+bpf-ci
2026-10-26 2:59 ` [PATCH bpf 42/81] bpf: Allow BPF_MAX_SUBPROGS targets of a read from a table of functions Alexei Starovoitov
2026-10-26 3:53 ` bot+bpf-ci
2026-10-26 2:59 ` [PATCH bpf 43/81] bpf: Tell user space that a run of a prog was cut short Alexei Starovoitov
2026-10-26 3:53 ` bot+bpf-ci
2026-10-26 2:59 ` [PATCH bpf 44/81] bpf: Mask the count of a 32-bit shift in scalar evolution Alexei Starovoitov
2026-10-26 3:52 ` bot+bpf-ci
2026-10-26 2:59 ` [PATCH bpf 45/81] selftests/bpf: Expect the masked count of 32-bit shifts Alexei Starovoitov
2026-10-26 2:59 ` [PATCH bpf 46/81] bpf: Finish the insn in the state that maybe_fork_scalars() splits off Alexei Starovoitov
2026-10-26 3:53 ` bot+bpf-ci
2026-10-26 2:59 ` [PATCH bpf 47/81] bpf: Add join of verifier states Alexei Starovoitov
2026-10-26 3:53 ` bot+bpf-ci
2026-10-26 2:59 ` [PATCH bpf 48/81] bpf: Describe loops that scalar evolution cannot count exactly Alexei Starovoitov
2026-10-26 3:53 ` bot+bpf-ci
2026-10-26 2:59 ` [PATCH bpf 49/81] selftests/bpf: Adjust tests to loops that are counted now Alexei Starovoitov
2026-10-26 2:59 ` [PATCH bpf 50/81] bpf: Add may_goto to the loops that the verifier marks Alexei Starovoitov
2026-10-26 3:53 ` bot+bpf-ci
2026-10-26 2:59 ` [PATCH bpf 51/81] bpf: Check stack and count calls of recursive subprogs at run time Alexei Starovoitov
2026-10-26 4:09 ` bot+bpf-ci
2026-10-26 12:51 ` kernel test robot
2026-10-26 2:59 ` [PATCH bpf 52/81] bpf: Add the main pass as a fixpoint over the control flow graph Alexei Starovoitov
2026-10-26 3:53 ` bot+bpf-ci
2026-10-26 2:59 ` [PATCH bpf 53/81] bpf: Verify programs " Alexei Starovoitov
2026-10-26 4:25 ` bot+bpf-ci
2026-10-26 2:59 ` [PATCH bpf 54/81] bpf: Allow 24 arguments of static subprogs Alexei Starovoitov
2026-10-26 3:53 ` bot+bpf-ci
2026-10-26 2:59 ` [PATCH bpf 55/81] selftests/bpf: Test a static subprog with 24 arguments Alexei Starovoitov
2026-10-26 2:59 ` [PATCH bpf 56/81] bpf: Bump MAX_CALL_FRAMES to 32 Alexei Starovoitov
2026-10-26 3:53 ` bot+bpf-ci
2026-10-26 2:59 ` [PATCH bpf 57/81] selftests/bpf: Test 32 and 33 call frames Alexei Starovoitov
2026-10-26 3:53 ` bot+bpf-ci
2026-10-26 2:59 ` [PATCH bpf 58/81] bpf: Bump BPF_MAX_SUBPROGS to 1024 Alexei Starovoitov
2026-10-26 2:59 ` [PATCH bpf 59/81] selftests/bpf: Make room in veristat for the stats of 1024 subprogs Alexei Starovoitov
2026-10-26 2:59 ` [PATCH bpf 60/81] bpf: Remove is_state_visited() Alexei Starovoitov
2026-10-26 2:59 ` [PATCH bpf 61/81] bpf: Remove precision tracking Alexei Starovoitov
2026-10-26 3:53 ` bot+bpf-ci
2026-10-26 2:59 ` [PATCH bpf 62/81] bpf: Remove prune points, levels of state comparison and pop_stack() Alexei Starovoitov
2026-10-26 3:53 ` bot+bpf-ci
2026-10-26 2:59 ` [PATCH bpf 63/81] bpf: Print 0 as the limit in the statistics line Alexei Starovoitov
2026-10-26 3:52 ` bot+bpf-ci
2026-10-26 2:59 ` [PATCH bpf 64/81] bpf: Remove bpf_compute_scc() Alexei Starovoitov
2026-10-26 3:53 ` bot+bpf-ci
2026-10-26 2:59 ` [PATCH bpf 65/81] bpf: Update comments about paths, pruning and explored states Alexei Starovoitov
2026-10-26 3:53 ` bot+bpf-ci
2026-10-26 2:59 ` [PATCH bpf 66/81] bpf: Remove iter.depth Alexei Starovoitov
2026-10-26 2:59 ` [PATCH bpf 67/81] bpf: Remove leftovers of precision tracking and read marks Alexei Starovoitov
2026-10-26 2:59 ` [PATCH bpf 68/81] bpf: Track a pointer to one of a set of functions Alexei Starovoitov
2026-10-26 3:53 ` bot+bpf-ci
2026-10-26 2:59 ` [PATCH bpf 69/81] bpf, docs: Rewrite verifier.rst Alexei Starovoitov
2026-10-26 3:53 ` bot+bpf-ci
2026-10-26 2:59 ` [PATCH bpf 70/81] selftests/bpf: Adjust tests of precision tracking Alexei Starovoitov
2026-10-26 3:53 ` bot+bpf-ci
2026-10-26 2:59 ` [PATCH bpf 71/81] selftests/bpf: Adjust tests of linked registers and spills Alexei Starovoitov
2026-10-26 3:53 ` bot+bpf-ci
2026-10-26 2:59 ` [PATCH bpf 72/81] selftests/bpf: Adjust tests of pruning Alexei Starovoitov
2026-10-26 3:53 ` bot+bpf-ci
2026-10-26 2:59 ` [PATCH bpf 73/81] selftests/bpf: Adjust tests of loops Alexei Starovoitov
2026-10-26 3:53 ` bot+bpf-ci
2026-10-26 2:59 ` [PATCH bpf 74/81] selftests/bpf: Adjust tests of recursion Alexei Starovoitov
2026-10-26 2:59 ` [PATCH bpf 75/81] selftests/bpf: Adjust tests to the order of verification and to the log Alexei Starovoitov
2026-10-26 2:59 ` [PATCH bpf 76/81] selftests/bpf: Adjust tests of unprivileged progs Alexei Starovoitov
2026-10-26 2:59 ` [PATCH bpf 77/81] selftests/bpf: Test states that are not joined Alexei Starovoitov
2026-10-26 3:53 ` bot+bpf-ci
2026-10-26 2:59 ` [PATCH bpf 78/81] selftests/bpf: Test progs that run out of budget Alexei Starovoitov
2026-10-26 3:53 ` bot+bpf-ci
2026-10-26 2:59 ` [PATCH bpf 79/81] selftests/bpf: Test 'unwound' in bpf_prog_info Alexei Starovoitov
2026-10-26 2:59 ` [PATCH bpf 80/81] selftests/bpf: Test the stack in arena after recursion ran out of budget Alexei Starovoitov
2026-10-26 2:59 ` [PATCH bpf 81/81] selftests/bpf: Test callx of one of a set of functions Alexei Starovoitov
2026-10-26 3:53 ` bot+bpf-ci
2026-10-26 16:57 ` [PATCH bpf 00/81] bpf: Stack in arena and a verifier that joins states Ihor Solodrai
2026-10-26 23:53 ` Alexei Starovoitov
2026-10-27 0:04 ` Ihor Solodrai
2026-10-27 0:14 ` Alexei Starovoitov
2026-10-27 5:08 ` Ihor Solodrai
2026-10-26 22:28 ` Ihor Solodrai
2026-10-26 23:45 ` Alexei Starovoitov
2026-10-27 0:01 ` Ihor Solodrai
2026-10-27 0:13 ` Ihor Solodrai
2026-10-27 0:16 ` Alexei Starovoitov
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=DMFUDQAC6N4S.1CNBGYKG58DMR@gmail.com \
--to=alexei.starovoitov@gmail.com \
--cc=andrii@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=eddyz87@gmail.com \
--cc=memxor@gmail.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