BPF List
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Alexei Starovoitov" <alexei.starovoitov@gmail.com>, bpf@vger.kernel.org
Subject: Re: [PATCH bpf-next v4 18/46] bpf: Tell the passes over the graph where an added may_goto goes
Date: Sat, 07 Nov 2026 04:10:45 +0000	[thread overview]
Message-ID: <sashiko-outbox-202556@kernel.org> (raw)
In-Reply-To: <20261107033758.1547725-19-alexei.starovoitov@gmail.com>

Thank you for your contribution! Sashiko AI review found 2 potential
issues to consider:
- [High] bpf: missing head guard target edge in update_insn() stack
  liveness
- [High] bpf: bpf_prune_dead_branches() folds jumps before head guards
  are placed
--

commit b45291925cc857048f8bb1e4b926985f761611df
Author: Alexei Starovoitov <ast@kernel.org>

bpf: Tell the passes over the graph where an added may_goto goes

This commit runs bpf_flow_place_guards() right after loop detection so
constant folding, subprog argument tracking, and register liveness
account for synthetic may_goto edges from loop headers, and adds
backward condition tracking in bpf_compute_leave_conds() to identify
loop exits controlled by flags.

> diff --git a/kernel/bpf/liveness.c b/kernel/bpf/liveness.c
> index 525c0faff1a66..6a2ee407412b8 100644
> --- a/kernel/bpf/liveness.c
> +++ b/kernel/bpf/liveness.c
[ ... ]
> @@ -2780,6 +2796,7 @@ int bpf_compute_live_registers(struct bpf_verifier_env *env)
>  			u32 new_out = 0;
>  			u32 new_in = 0;
>  			u32 use;
> +			int t;
>  
>  			succ = bpf_insn_successors(env, insn_idx);
>  			for (int s = 0; s < succ->cnt; ++s)
> @@ -2794,6 +2811,10 @@ int bpf_compute_live_registers(struct bpf_verifier_env *env)
>  				use |= state[insn_idx + insns[insn_idx].imm + 1].in &
>  				       mask_widen(GENMASK(BPF_REG_5, BPF_REG_1));
>  			new_in = (new_out & ~live->def) | use;
> +			/* may_goto that is added at the head of a loop goes there */
> +			t = bpf_head_guard_target(env, insn_idx);
> +			if (t >= 0)
> +				new_in |= state[t].in;
>  			if (new_out != live->out || new_in != live->in) {
>  				live->in = new_in;
>  				live->out = new_out;

[Severity: High]
Does update_insn() need the same bpf_head_guard_target() edge for
backward stack-slot liveness (FM_LIVE_BEFORE)?

compute_subprog_args() now propagates stack pointers and spills across
bpf_head_guard_target(), and bpf_compute_live_registers() unions
state[t].in into new_in at the loop header, but update_insn() still
computes FM_LIVE_BEFORE only from normal CFG successors minus
must_write:

kernel/bpf/liveness.c:update_insn() {
	...
	for (s = 0; s < succ->cnt; ++s) {
		unsigned long *succ_live;

		succ_live = rel_mask(fm, relative_idx(instance, succ->items[s]), FM_LIVE_BEFORE);
		for (w = 0; w < fm->words; w++)
			new_after[w] |= succ_live[w];
	}
	...
	for (w = 0; w < fm->words; w++) {
		unsigned long new_before = (new_after[w] & ~must_write[w]) | may_read[w];
}

If a stack slot is initialized before the loop header, overwritten on
every normal path through the loop to the exit target t, and read at or
after t, FM_LIVE_BEFORE is cleared at the loop header.  When a state
arrives at the header in flow_arrive(), __clean_func_state() sees
bpf_stack_slot_alive() == false, clears spilled_ptr to NOT_INIT, and
marks the slot STACK_POISON before check_loop_guard() delivers the state
along the head-guard edge to t.  Reads of that slot after t then fail
verification as reading a poisoned slot, or if the slot held a spilled
pointer before the header and a scalar on normal loop exits, join_slot()
at t can merge the poisoned slot with the scalar into STACK_INVALID when
allow_uninit_stack is set, allowing the spilled pointer bytes on the
may_goto path to be read as a scalar.

> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index 5faea922699af..62a58f38f4e22 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -25268,6 +25268,21 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr,
>  	if (ret < 0)
>  		goto skip_full_check;
>  
> +	/*
> +	 * It took the constants to remove dead branches and find the loops. Now it's known
> +	 * which edges the verifier may add, see bpf_head_guard_target(). What follows
> +	 * believes the constants.
> +	 */
> +	ret = bpf_flow_place_guards(env);
> +	if (ret > 0)
> +		ret = bpf_compute_const_regs(env);
> +	if (ret < 0)
> +		goto skip_full_check;
> +
> +	ret = bpf_find_latches(env, true);
> +	if (ret < 0)
> +		goto skip_full_check;
> +
>  	ret = bpf_compute_live_registers(env);
>  	if (ret < 0)
>  		goto skip_full_check;

[Severity: High]
Can re-running bpf_compute_const_regs() after bpf_flow_place_guards()
leave behind conditional jumps that bpf_prune_dead_branches() already
rewrote into unconditional jumps using constants that only hold on
normal loop exits?

Before bpf_compute_loops() and bpf_flow_place_guards() run, the first
bpf_compute_const_regs() pass has no head-guard edges, so a register (or
a read-only map load through it, as in the r7 == &ro vs &rw case from
the commit message) that is constant on all normal exits to t is marked
constant at and after t.  bpf_prune_dead_branches() then permanently
overwrites conditional jumps testing that register at or after t in
env->prog->insnsi with BPF_JMP_A and recomputes postorder.  Re-running
bpf_compute_const_regs() after bpf_flow_place_guards() clears
const_reg_mask at t, but the in-place BPF_JMP_A rewrites remain in the
program, so a state taking the header may_goto to t will unconditionally
follow the branch decided for normal exits.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261107033758.1547725-1-alexei.starovoitov@gmail.com?part=18

  reply	other threads:[~2026-11-07  4:10 UTC|newest]

Thread overview: 72+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-07  3:37 [PATCH bpf-next v4 00/46] bpf: A verifier that joins states Alexei Starovoitov
2026-11-07  3:37 ` [PATCH bpf-next v4 01/46] bpf: Add may_goto to the loops that the verifier marks Alexei Starovoitov
2026-11-07  4:12   ` sashiko-bot
2026-11-07  3:37 ` [PATCH bpf-next v4 02/46] bpf: Limit depth and time of recursive subprogs at run time Alexei Starovoitov
2026-11-07  3:37 ` [PATCH bpf-next v4 03/46] bpf: Add union and widening of the range of a register Alexei Starovoitov
2026-11-07  4:19   ` bot+bpf-ci
2026-11-07  3:37 ` [PATCH bpf-next v4 04/46] bpf: Add join of registers and stack slots Alexei Starovoitov
2026-11-07  4:18   ` sashiko-bot
2026-11-07  3:37 ` [PATCH bpf-next v4 05/46] bpf: Add join of verifier states Alexei Starovoitov
2026-11-07  4:18   ` sashiko-bot
2026-11-07  3:37 ` [PATCH bpf-next v4 06/46] bpf: Tell which arguments of a call a join must leave alone Alexei Starovoitov
2026-11-07  4:19   ` bot+bpf-ci
2026-11-07  3:37 ` [PATCH bpf-next v4 07/46] bpf: Add the data structures of the main pass over the control flow graph Alexei Starovoitov
2026-11-07  3:37 ` [PATCH bpf-next v4 08/46] bpf: Order the insns, find what stops a loop and where may_goto can go Alexei Starovoitov
2026-11-07  3:37 ` [PATCH bpf-next v4 09/46] bpf: Find the registers that hold a number or a pointer to arena Alexei Starovoitov
2026-11-07  4:11   ` sashiko-bot
2026-11-07  3:37 ` [PATCH bpf-next v4 10/46] bpf: Find the registers and stack slots that later checks depend on Alexei Starovoitov
2026-11-07  3:37 ` [PATCH bpf-next v4 11/46] bpf: Add the sets of states at an insn and the entries of functions Alexei Starovoitov
2026-11-07  3:37 ` [PATCH bpf-next v4 12/46] bpf: Compare states of different iterations of a loop Alexei Starovoitov
2026-11-07  3:37 ` [PATCH bpf-next v4 13/46] bpf: Decide which states are not joined Alexei Starovoitov
2026-11-07  3:37 ` [PATCH bpf-next v4 14/46] bpf: Merge the state that arrives into the set at an insn Alexei Starovoitov
2026-11-07  3:37 ` [PATCH bpf-next v4 15/46] bpf: Move states along edges, into loops and subprogs and out of them Alexei Starovoitov
2026-11-07  4:19   ` bot+bpf-ci
2026-11-07  3:37 ` [PATCH bpf-next v4 16/46] bpf: Make the state after a call from the caller's state and an exit state Alexei Starovoitov
2026-11-07  4:12   ` sashiko-bot
2026-11-07  3:37 ` [PATCH bpf-next v4 17/46] bpf: Enter and leave loops in the main pass, build flow.c Alexei Starovoitov
2026-11-07  3:37 ` [PATCH bpf-next v4 18/46] bpf: Tell the passes over the graph where an added may_goto goes Alexei Starovoitov
2026-11-07  4:10   ` sashiko-bot [this message]
2026-11-07  3:37 ` [PATCH bpf-next v4 19/46] bpf: Verify programs as a fixpoint over the control flow graph Alexei Starovoitov
2026-11-07  4:33   ` bot+bpf-ci
2026-11-07  4:40   ` sashiko-bot
2026-11-07  3:37 ` [PATCH bpf-next v4 20/46] bpf: Keep the count of a loop when a register has no closed form Alexei Starovoitov
2026-11-07  3:37 ` [PATCH bpf-next v4 21/46] bpf: Verify static subprogs on their own Alexei Starovoitov
2026-11-07  4:53   ` sashiko-bot
2026-11-07  3:37 ` [PATCH bpf-next v4 22/46] bpf: Allow recursive subprogs Alexei Starovoitov
2026-11-07  4:33   ` bot+bpf-ci
2026-11-07  4:48   ` sashiko-bot
2026-11-07  3:37 ` [PATCH bpf-next v4 23/46] bpf: Remove is_state_visited(), bpf_compute_scc() and iter.depth Alexei Starovoitov
2026-11-07  3:37 ` [PATCH bpf-next v4 24/46] bpf: Remove precision tracking Alexei Starovoitov
2026-11-07  3:37 ` [PATCH bpf-next v4 25/46] bpf: Remove prune points, levels of state comparison and pop_stack() Alexei Starovoitov
2026-11-07  3:37 ` [PATCH bpf-next v4 26/46] bpf: Update comments about paths, pruning and explored states Alexei Starovoitov
2026-11-07  4:03   ` sashiko-bot
2026-11-07  3:37 ` [PATCH bpf-next v4 27/46] bpf: Track a pointer to one of a set of functions Alexei Starovoitov
2026-11-07  4:31   ` sashiko-bot
2026-11-07  3:37 ` [PATCH bpf-next v4 28/46] bpf: callx reads what the subprogs whose address is taken read Alexei Starovoitov
2026-11-07  3:37 ` [PATCH bpf-next v4 29/46] bpf: Keep the first iteration of a counted loop apart Alexei Starovoitov
2026-11-07  4:34   ` sashiko-bot
2026-11-07  3:37 ` [PATCH bpf-next v4 30/46] bpf: What a call returns in each iteration is like what the loop loads Alexei Starovoitov
2026-11-07  4:26   ` sashiko-bot
2026-11-07  3:37 ` [PATCH bpf-next v4 31/46] bpf: Find where the jumps of a loop stop a number Alexei Starovoitov
2026-11-07  3:37 ` [PATCH bpf-next v4 32/46] bpf: A loop is one iteration shorter behind the jump that counts it Alexei Starovoitov
2026-11-07  4:19   ` bot+bpf-ci
2026-11-07  4:28   ` sashiko-bot
2026-11-07  3:37 ` [PATCH bpf-next v4 33/46] bpf: Give the places of a back edge to the jumps that count Alexei Starovoitov
2026-11-07  3:37 ` [PATCH bpf-next v4 34/46] bpf: Count a loop whose exit tests a copy of the counter Alexei Starovoitov
2026-11-07  3:37 ` [PATCH bpf-next v4 35/46] bpf: Allow tail calls and LD_ABS in subprogs that return void Alexei Starovoitov
2026-11-07  3:37 ` [PATCH bpf-next v4 36/46] bpf: A part of a pointer that is spilled is a number Alexei Starovoitov
2026-11-07  3:37 ` [PATCH bpf-next v4 37/46] bpf: 32-bit add to a pointer and pointer op pointer make " Alexei Starovoitov
2026-11-07  3:37 ` [PATCH bpf-next v4 38/46] selftests/bpf: Adjust tests to log lines that are gone Alexei Starovoitov
2026-11-07  4:19   ` bot+bpf-ci
2026-11-07  3:37 ` [PATCH bpf-next v4 39/46] selftests/bpf: Adjust tests to new verdicts, messages and order Alexei Starovoitov
2026-11-07  4:24   ` sashiko-bot
2026-11-07  3:37 ` [PATCH bpf-next v4 40/46] selftests/bpf: Test states that are not joined Alexei Starovoitov
2026-11-07  3:37 ` [PATCH bpf-next v4 41/46] selftests/bpf: Test static subprogs that are verified on their own Alexei Starovoitov
2026-11-07  3:37 ` [PATCH bpf-next v4 42/46] selftests/bpf: Test loops that are counted, walked or widened Alexei Starovoitov
2026-11-07  3:37 ` [PATCH bpf-next v4 43/46] selftests/bpf: Test progs that run out of budget Alexei Starovoitov
2026-11-07  3:37 ` [PATCH bpf-next v4 44/46] selftests/bpf: Test callx of one of a set of functions Alexei Starovoitov
2026-11-07  3:37 ` [PATCH bpf-next v4 45/46] selftests/bpf: Test pointers that become numbers and subprogs that return void Alexei Starovoitov
2026-11-07  3:37 ` [PATCH bpf-next v4 46/46] selftests/bpf: Test progs without bpf_for(), zero, can_loop and such Alexei Starovoitov
2026-11-07  4:19   ` bot+bpf-ci
2026-11-07  4:37   ` sashiko-bot
2026-11-07  5:00 ` [PATCH bpf-next v4 00/46] bpf: A verifier that joins states patchwork-bot+netdevbpf

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=sashiko-outbox-202556@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=alexei.starovoitov@gmail.com \
    --cc=bpf@vger.kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    /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