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 v2 19/35] bpf: Verify programs as a fixpoint over the control flow graph
Date: Thu, 05 Nov 2026 22:45:50 +0000	[thread overview]
Message-ID: <sashiko-outbox-200329@kernel.org> (raw)
In-Reply-To: <20261105204513.2230344-20-alexei.starovoitov@gmail.com>

Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:
- [High] bpf: missing bpf_head_guard_target() edge in update_insn() and need_const
- [High] bpf: missing loop_stack refs update in release_reference_state()
- [Medium] bpf: unreset loop_guard flag and ignored fatal errors in do_check_all()
- [Medium] bpf: join_func() rejects joins when fa->out_stack_arg_cnt < fb
- [Medium] bpf: unreachable bail_insn in check_unwind_insns() breaks budget exit
- [Medium] bpf: check_loop_guard() rejects offloaded progs during patience walk
- [Medium] bpf: do_check_block() drains queued states after speculative nospec abort
--

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

bpf: Verify programs as a fixpoint over the control flow graph

This commit switches the BPF verifier from path-by-path exploration to a
fixpoint iteration over the control flow graph, joining states at basic
block boundaries and inserting runtime loop guards for loops without
known bounds.

> diff --git a/kernel/bpf/states.c b/kernel/bpf/states.c
> index 9d3a86b5820e9..4b2506f3e3e27 100644
> --- a/kernel/bpf/states.c
> +++ b/kernel/bpf/states.c
[ ... ]
> @@ -872,16 +873,19 @@ static bool stack_arg_safe(struct bpf_verifier_env *env, struct bpf_func_state *
>  			   struct bpf_func_state *cur, struct bpf_idmap *idmap,
>  			   enum exact_level exact)
>  {
> -	int i, nslots, cur_cnt = cur->out_stack_arg_cnt;
> +	int i, nslots, cur_cnt = cur->out_stack_arg_cnt;
>  
> -	nslots = max(old->out_stack_arg_cnt, cur->out_stack_arg_cnt);
> +	/* incoming arguments are not compared with outgoing ones, the other way is ruled out */
> +	if (bpf_stack_args_are_incoming(cur) && !bpf_stack_args_are_incoming(old))
> +		cur_cnt = 0;
> +	nslots = max(old->out_stack_arg_cnt, cur_cnt);
>  	for (i = 0; i < nslots; i++) {
>  		struct bpf_reg_state *old_arg, *cur_arg;
>  		struct bpf_reg_state not_init = { .type = NOT_INIT };
>  
>  		old_arg = i < old->out_stack_arg_cnt ?
>  			  &old->stack_arg_regs[i] : &not_init;
> -		cur_arg = i < cur->out_stack_arg_cnt ?
> +		cur_arg = i < cur_cnt ?
>  			  &cur->stack_arg_regs[i] : &not_init;
>  		if (!regsafe(env, old_arg, cur_arg, idmap, exact))
>  			return false;

[Severity: Medium]
Here in stack_arg_safe(), slots beyond old->out_stack_arg_cnt are treated
as NOT_INIT and therefore subsume any slot in cur, even when
old->out_stack_arg_cnt < cur->out_stack_arg_cnt.

However, when joining or widening states in kernel/bpf/join.c:join_func():

    if (fa->out_stack_arg_cnt < fb->out_stack_arg_cnt)
        return false;

When a function writes outgoing stack arguments for a call inside a loop
body or branch, check_stack_arg_write() grows state->out_stack_arg_cnt, and
invalidate_outgoing_stack_args() after the call resets stack_arg_regs[i]
to NOT_INIT while keeping state->out_stack_arg_cnt > 0.

When that post-call state (fb, with out_stack_arg_cnt > 0) is later joined
or widened into an earlier state at a loop header or merge point (fa, with
out_stack_arg_cnt == 0), won't join_func() unconditionally reject the join?

> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index 8b26bf625e5f5..227bb613176ad 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
[ ... ]
> @@ -1605,9 +1617,14 @@ static int acquire_irq_state(struct bpf_verifier_env *env, int insn_idx)
>  
>  static void release_reference_state(struct bpf_verifier_state *state, int idx)
>  {
> -	int last_idx;
> +	int last_idx, fr;
>  	size_t rem;
>  
> +	/* the frames that were entered with it don't hold it ever since */
> +	for (fr = 0; fr <= state->curframe; fr++)
> +		if (idx < state->frame[fr]->entry_refs)
> +			state->frame[fr]->entry_refs--;
> +
>  	/* IRQ state requires the relative ordering of elements remaining the
>  	 * same, since it relies on the refs array to behave as a stack, so that
>  	 * it can detect out-of-order IRQ restore. Hence use memmove to shift

[Severity: High]
When release_reference_state() releases a reference at idx and shifts
state->refs[] down via memmove(), it decrements state->frame[fr]->entry_refs
if idx < entry_refs, but should it also decrement
state->frame[fr]->loop_stack[i].refs when idx < loop_stack[i].refs (and
should loop_stack_safe() in kernel/bpf/states.c also check
old_stack[i].refs == cur_stack[i].refs)?

In loop_stack_push(), loop_stack[cnt].refs is set to
env->cur_state->acquired_refs upon entering a loop. On a backedge,
bpf_flow_loop_enter()->check_refs_taken_in_loop() checks for leaked
references acquired in the loop by scanning from entry->refs:

    for (i = entry->refs; i < st->acquired_refs; i++) {
        if (st->refs[i].type != REF_TYPE_PTR)
            continue;
        ...
    }

If a reference acquired before the loop (idx < entry->refs) is released
inside the loop and a new reference is acquired inside the loop without
being released, memmove() shifts the new in-loop reference to index
entry->refs - 1 while entry->refs stays unchanged, causing
check_refs_taken_in_loop() to skip it on the backedge.

[ ... ]
> @@ -3459,7 +3482,17 @@ static int check_unwind_insns(struct bpf_verifier_env *env)
>  	bool seen = false;
>  	int i;
>  
> +	for (i = 0; i < env->subprog_cnt; i++)
> +		env->subprog_info[i].bail_insn = -1;
> +
>  	for (i = 0; i < env->prog->len; i++, insn++) {
> +		if (bpf_is_ldimm64(insn)) {
> +			i++;
> +			insn++;
> +			continue;
> +		}
> +		if (insn->code == (BPF_JMP | BPF_EXIT))
> +			bpf_find_containing_subprog(env, i)->bail_insn = i;
>  		if (bpf_is_unwind_exit(insn)) {
>  			bpf_find_containing_subprog(env, i)->can_unwind = true;
>  			seen = true;

[Severity: Medium]
check_unwind_insns() runs before bpf_compute_const_regs() and
bpf_prune_dead_branches(), recording the last BPF_EXIT in each subprogram
as bail_insn.

If a subprogram has two BPF_EXIT instructions and the second one is in a
branch that gets pruned by bpf_prune_dead_branches(), bail_insn will not be
in env->cfg.insn_postorder, so bpf_compute_live_registers() leaves
live_regs_before as 0 at bail_insn.

When check_loop_guard()->push_budget_exit() later sets R0 = 0 and pushes a
state to sub->bail_insn, flow_arrive()->bpf_clean_verifier_state() scrubs R0
to NOT_INIT because live_regs_before is 0, causing check_return_code() at
bail_insn to fail with -EACCES. Additionally, if bail_insn is in an
unreached branch, verifying the synthetic state from push_budget_exit() at
bail_insn runs sanitize_mark_insn_seen(env), marking the dead BPF_EXIT as
seen. Should bail_insn be selected after dead branch pruning, or handled
without marking the target instruction as seen?

[ ... ]
> +static int check_loop_guard(struct bpf_verifier_env *env)
> +{
> +	struct bpf_insn_aux_data *aux = &env->insn_aux_data[env->insn_idx];
> +	struct bpf_verifier_state *branch;
> +	struct bpf_func_state *frame = cur_func(env);
> +	struct loop_stack_entry *entry;
> +	struct bpf_loop *loop;
> +	int h, err;
> +
> +	h = bpf_loop_at_index(env, env->insn_idx);
> +	/* The callback came back to the helper that calls it: the program is not in front of it. */
> +	if (h < 0 || !frame->loop_stack_cnt || frame->callback_depth)
> +		return 0;
> +	loop = env->insn_aux_data[h].loop;
> +	entry = &frame->loop_stack[frame->loop_stack_cnt - 1];
> +	if (loop->rt_bounded || !env->insn_aux_data[env->insn_idx].guard_place ||
> +	    entry->loop_id != h)
> +		return 0;
> +	if (verifier_bug_if(!entry->terminates && !entry->guarded, env,
> +			    "nothing stops the loop at %d", h))
> +		return -EFAULT;
> +	if (!entry->guarded && !bpf_loop_walk_may_give_up(entry))
> +		return 0;
> +
> +	/* the device runs the insns that the driver was given, without may_goto */
> +	if (bpf_prog_is_offloaded(env->prog->aux)) {
> +		verbose(env, "loop at insn %d has no known bound in an offloaded program\n", h);
> +		return -EINVAL;
> +	}

[Severity: Medium]
When a loop is not counted by SCEV, bpf_flow_loop_enter() starts a patience
walk via flow_try_walk() with entry->guarded == false and
bpf_loop_walk_may_give_up(entry) == true. If the walk finishes within its
patience budget, no may_goto is needed or inserted.

Because check_loop_guard() checks bpf_prog_is_offloaded(env->prog->aux)
before checking whether entry->guarded is true, won't an offloaded program
be rejected on the first iteration of a patience walk even when the walk
would complete normally without needing may_goto?

> +
> +	/*
> +	 * A guard has one way out, and only that one is looked at.
> +	 *
> +	 * Leave the subprog, if that is possible every time the program gets here:
> +	 *	do { p = lookup(); } while (!p); *p
> +	 * The code that follows the loop counts on what the jump that leaves it has found out.
> +	 *
> +	 * Otherwise leave the loop:
> +	 *	lock(); do { ... } while (...); unlock();
> +	 * The code that follows the loop releases what is held.
> +	 *
> +	 * It's the same way for all states that get here. As long as they leave the subprog
> +	 * what would leave the loop is dropped. Both are dropped as long as the loop has
> +	 * no may_goto: the state is in a walk that may get to the end of the loop.
> +	 */
> +	if (!aux->guard_no_unwind && !budget_can_unwind(env, env->cur_state)) {
> +		aux->guard_no_unwind = true;
> +		/* What would leave the loop from the states that were here is gone. All again. */
> +		if (aux->guard_edge_dropped && loop->guarded)
> +			env->guards_late = true;
> +	}
> +	if (!aux->guard_no_unwind) {
> +		err = push_budget_exit(env);
> +		if (err)
> +			return err;
> +		env->head->guard_edge = BPF_GUARD_LEAVES_SUBPROG;
> +	}
> +
> +	branch = push_stack(env, env->insn_aux_data[env->insn_idx].guard_to, env->insn_idx, false);
> +	if (IS_ERR(branch))
> +		return PTR_ERR(branch);
> +	env->head->guard_edge = BPF_GUARD_LEAVES_LOOP;
> +	return 0;
> +}

[Severity: High]
When a loop has no dominating exit condition, flow_place_guards() sets
guard_place and guard_at_header at the loop header, and check_loop_guard()
pushes a synthetic BPF_GUARD_LEAVES_LOOP edge from the loop header to
guard_to.

While bpf_compute_const_regs(), compute_subprog_args(), and
bpf_compute_live_registers() account for t = bpf_head_guard_target(env, idx),
kernel/bpf/liveness.c:update_insn() and
kernel/bpf/flow.c:flow_compute_need_const() only iterate over
bpf_insn_successors(env, idx):

kernel/bpf/liveness.c:update_insn() {
    succ = bpf_insn_successors(env, insn_idx);
    if (succ->cnt == 0)
        return false;

    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];
    }
}

If a stack slot (such as fp-8) holds a value or a spilled kernel pointer
before the loop header h, is overwritten on all normal in-loop paths before
reaching guard_to (setting FM_MUST_WRITE inside the loop), and is read at
or after guard_to (setting FM_LIVE_BEFORE at guard_to), update_insn() does
not propagate FM_LIVE_BEFORE across bpf_head_guard_target(env, h), so fp-8
is marked dead at h.

When a state arrives at h, flow_arrive()->bpf_clean_verifier_state() marks
fp-8 as STACK_POISON and clears spilled_ptr. check_loop_guard() then pushes
this poisoned state from h to guard_to (when aux->guard_no_unwind is true,
e.g. while holding a lock, reference, or RCU read lock across the loop).

At guard_to:
1. If !env->allow_uninit_stack or no other state joins at guard_to, reading
   fp-8 fails verification with "slot poisoned by dead code elimination".
2. If env->allow_uninit_stack is true and the header guard state joins at
   guard_to with a normal loop-exit state that overwrote fp-8 with a scalar
   (STACK_SPILL scalar, STACK_MISC, or STACK_ZERO), join_slot() in
   kernel/bpf/join.c merges that slot with STACK_POISON into STACK_INVALID.
   Subsequent stack reads at guard_to then treat fp-8 as an initialized
   SCALAR_VALUE, even though at runtime the may_goto inserted at h jumps
   directly to guard_to with the original pre-loop kernel pointer still in
   fp-8.

Should update_insn() and flow_compute_need_const() also propagate across
bpf_head_guard_target()?

[ ... ]
> @@ -21669,6 +21854,10 @@ static int do_check(struct bpf_verifier_env *env)
>  		if (state->speculative && insn_aux->nospec)
>  			goto process_bpf_exit;
>  
> +		err = check_loop_guard(env);
> +		if (err)
> +			return err;
> +
>  		err = do_check_insn(env, &do_print_state);
>  		if (error_recoverable_with_nospec(err) && state->speculative) {
>  			/* Prevent this speculative path from ever reaching the
> @@ -21690,19 +21879,9 @@ static int do_check(struct bpf_verifier_env *env)
>  		}
>  
>  		if (state->speculative && insn_aux->nospec_result) {
[ ... ]
>  process_bpf_exit:
>  			account_current_path(env);
>  			mark_verifier_state_scratched(env);
> -			err = bpf_update_branch_counts(env, env->cur_state);
> -			if (err)
> -				return err;
> -			err = pop_stack(env, &prev_insn_idx, &env->insn_idx,
> -					pop_log);
> -			if (err < 0) {
> -				if (err != -ENOENT)
> -					return err;
> -				break;
> -			} else {
> -				do_print_state = true;
> -				continue;
> -			}
> +			bpf_free_verifier_state(state, false);
> +			memset(state, 0, sizeof(*state));
> +			return flow_drain(env);
> +		}

[Severity: Medium]
When state->speculative is true and do_check_insn() fails with a
recoverable error, do_check_block() sets insn_aux->nospec = true to place a
speculation barrier before env->insn_idx and jumps to process_bpf_exit.

However, check_loop_guard() has already run before do_check_insn() (and
do_check_insn() itself may have pushed branches onto env->head before
failing, such as in push_callback_call() or check_kfunc_call() for
KF_bpf_res_spin_lock), and process_bpf_exit then calls flow_drain(env),
delivering all states queued on env->head instead of discarding them.

Should check_loop_guard() be skipped or should states pushed during the
aborted speculative instruction be discarded before jumping to
process_bpf_exit?

[ ... ]
> @@ -23118,6 +23317,44 @@ static int do_check_main(struct bpf_verifier_env *env)
>  	return ret;
>  }
>  
> +/*
> + * What stops a loop is assumed before the main pass and checked in it, see flow_is_bound(). The
> + * main prog and global functions may get to the same loop. It has may_goto for all of them or
> + * for none, so all are done again when the assumption doesn't hold, whatever came out.
> + * The same when a loop gets may_goto, or its may_goto gets another way out, and what went through
> + * the loop before is not there any more, see bpf_flow_loop_gets_guards().
> + *
> + * A round that is dropped counts as paths that never run. What it found out about the insns, the
> + * subprogs and the prog stays. Each of these is made for more than one state that gets to an insn:
> + * it grows to the safe side, or another value is refused, or the last one that gets there sets it.
> + * Where the round got to is dropped with its verdict: the passes that follow take an insn that was
> + * seen for one that passed its checks, and a function that is called has to be safe.
> + */
> +static int do_check_all(struct bpf_verifier_env *env)
> +{
> +	struct bpf_func_info_aux *sub_aux;
> +	u64 log_pos = env->log.end_pos;
> +	int i, ret;
> +
> +	for (;;) {
> +		bpf_flow_new_round(env);
> +		ret = do_check_main(env);
> +		ret = ret ?: do_check_subprogs(env);
> +		if (!(env->restart && bpf_flow_loops_lost_bound(env)) && !env->guards_late)
> +			return ret;
> +		/* the log is dropped when a function is found to be safe */
> +		bpf_vlog_reset(&env->log, min(log_pos, env->log.end_pos));
> +		for (i = 0; i < env->prog->len; i++)
> +			env->insn_aux_data[i].seen = 0;
> +		for (i = 1; env->prog->aux->func_info && i < env->subprog_cnt; i++) {
> +			sub_aux = subprog_aux(env, i);
> +			memset(sub_aux->called, 0, sizeof(sub_aux->called));
> +			memset(sub_aux->verified, 0, sizeof(sub_aux->verified));
> +			sub_aux->called_with_pkt_ptrs = false;
> +		}
> +	}
> +}

[Severity: Medium]
Two questions about restarting a round in do_check_all():

1. During a round, bpf_flow_guard_edge() sets aux[prev_insn_idx].loop_guard = true.
   When a round is restarted, do_check_all() clears aux[i].seen = 0 and
   bpf_flow_new_round() clears aux[i].guard_edge_dropped, but neither
   clears aux[i].loop_guard. If an instruction had loop_guard set in the
   first round on a path that becomes unreachable in the next round (leaving
   aux[i].seen == 0), won't bpf_insert_loop_guards() and append_budget_exit()
   still patch a may_goto at that dead instruction and force seen = 1 on the
   appended budget exit instructions?

2. If env->guards_late or env->restart was set earlier in the round and
   do_check_main() or do_check_subprogs() subsequently aborts with a fatal
   error such as -EAGAIN, -ENOMEM, or -EFAULT, should do_check_all() return
   ret immediately rather than resetting the log and starting another round?

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

  parent reply	other threads:[~2026-11-05 22:45 UTC|newest]

Thread overview: 66+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-05 20:44 [PATCH bpf-next v2 00/35] bpf: A verifier that joins states Alexei Starovoitov
2026-11-05 20:44 ` [PATCH bpf-next v2 01/35] bpf: Add may_goto to the loops that the verifier marks Alexei Starovoitov
2026-11-05 21:14   ` sashiko-bot
2026-11-05 20:44 ` [PATCH bpf-next v2 02/35] bpf: Limit depth and time of recursive subprogs at run time Alexei Starovoitov
2026-11-05 21:35   ` bot+bpf-ci
2026-11-05 20:44 ` [PATCH bpf-next v2 03/35] bpf: Add union and widening of the range of a register Alexei Starovoitov
2026-11-05 21:34   ` bot+bpf-ci
2026-11-05 20:44 ` [PATCH bpf-next v2 04/35] bpf: Add join of registers and stack slots Alexei Starovoitov
2026-11-05 21:16   ` sashiko-bot
2026-11-05 21:35   ` bot+bpf-ci
2026-11-05 20:44 ` [PATCH bpf-next v2 05/35] bpf: Add join of verifier states Alexei Starovoitov
2026-11-05 21:35   ` bot+bpf-ci
2026-11-05 21:40   ` sashiko-bot
2026-11-05 20:44 ` [PATCH bpf-next v2 06/35] bpf: Tell which arguments of a call a join must leave alone Alexei Starovoitov
2026-11-05 20:44 ` [PATCH bpf-next v2 07/35] bpf: Add the data structures of the main pass over the control flow graph Alexei Starovoitov
2026-11-05 20:44 ` [PATCH bpf-next v2 08/35] bpf: Order the insns, find what stops a loop and where may_goto can go Alexei Starovoitov
2026-11-05 20:44 ` [PATCH bpf-next v2 09/35] bpf: Find the registers that hold a number or a pointer to arena Alexei Starovoitov
2026-11-05 21:35   ` bot+bpf-ci
2026-11-05 21:40   ` sashiko-bot
2026-11-05 20:44 ` [PATCH bpf-next v2 10/35] bpf: Find the registers and stack slots that later checks depend on Alexei Starovoitov
2026-11-05 21:35   ` bot+bpf-ci
2026-11-05 20:44 ` [PATCH bpf-next v2 11/35] bpf: Add the sets of states at an insn and the entries of functions Alexei Starovoitov
2026-11-05 20:44 ` [PATCH bpf-next v2 12/35] bpf: Compare states of different iterations of a loop Alexei Starovoitov
2026-11-05 20:44 ` [PATCH bpf-next v2 13/35] bpf: Decide which states are not joined Alexei Starovoitov
2026-11-05 21:35   ` bot+bpf-ci
2026-11-05 20:44 ` [PATCH bpf-next v2 14/35] bpf: Merge the state that arrives into the set at an insn Alexei Starovoitov
2026-11-05 21:35   ` bot+bpf-ci
2026-11-05 20:44 ` [PATCH bpf-next v2 15/35] bpf: Move states along edges, into loops and subprogs and out of them Alexei Starovoitov
2026-11-05 21:35   ` bot+bpf-ci
2026-11-05 20:44 ` [PATCH bpf-next v2 16/35] bpf: Make the state after a call from the caller's state and an exit state Alexei Starovoitov
2026-11-05 20:44 ` [PATCH bpf-next v2 17/35] bpf: Enter and leave loops in the main pass, build flow.c Alexei Starovoitov
2026-11-05 21:35   ` bot+bpf-ci
2026-11-05 20:44 ` [PATCH bpf-next v2 18/35] bpf: Tell the passes over the graph where an added may_goto goes Alexei Starovoitov
2026-11-05 22:19   ` sashiko-bot
2026-11-05 20:44 ` [PATCH bpf-next v2 19/35] bpf: Verify programs as a fixpoint over the control flow graph Alexei Starovoitov
2026-11-05 21:35   ` bot+bpf-ci
2026-11-05 22:45   ` sashiko-bot [this message]
2026-11-05 20:44 ` [PATCH bpf-next v2 20/35] bpf: Keep the count of a loop when a register has no closed form Alexei Starovoitov
2026-11-05 21:35   ` bot+bpf-ci
2026-11-05 20:44 ` [PATCH bpf-next v2 21/35] bpf: Verify static subprogs on their own Alexei Starovoitov
2026-11-05 21:51   ` bot+bpf-ci
2026-11-05 22:45   ` sashiko-bot
2026-11-05 20:44 ` [PATCH bpf-next v2 22/35] bpf: Allow recursive subprogs Alexei Starovoitov
2026-11-05 21:51   ` bot+bpf-ci
2026-11-05 23:09   ` sashiko-bot
2026-11-05 20:45 ` [PATCH bpf-next v2 23/35] bpf: Remove is_state_visited(), bpf_compute_scc() and iter.depth Alexei Starovoitov
2026-11-05 20:45 ` [PATCH bpf-next v2 24/35] bpf: Remove precision tracking Alexei Starovoitov
2026-11-05 20:45 ` [PATCH bpf-next v2 25/35] bpf: Remove prune points, levels of state comparison and pop_stack() Alexei Starovoitov
2026-11-05 20:45 ` [PATCH bpf-next v2 26/35] bpf: Update comments about paths, pruning and explored states Alexei Starovoitov
2026-11-05 20:45 ` [PATCH bpf-next v2 27/35] bpf: Track a pointer to one of a set of functions Alexei Starovoitov
2026-11-05 20:45 ` [PATCH bpf-next v2 28/35] bpf: callx reads what the subprogs whose address is taken read Alexei Starovoitov
2026-11-05 20:45 ` [PATCH bpf-next v2 29/35] selftests/bpf: Adjust tests to log lines that are gone Alexei Starovoitov
2026-11-05 21:35   ` bot+bpf-ci
2026-11-05 20:45 ` [PATCH bpf-next v2 30/35] selftests/bpf: Adjust tests to new verdicts, messages and order Alexei Starovoitov
2026-11-05 21:35   ` bot+bpf-ci
2026-11-05 20:45 ` [PATCH bpf-next v2 31/35] selftests/bpf: Test states that are not joined Alexei Starovoitov
2026-11-05 21:35   ` bot+bpf-ci
2026-11-05 20:45 ` [PATCH bpf-next v2 32/35] selftests/bpf: Test static subprogs that are verified on their own Alexei Starovoitov
2026-11-05 21:35   ` bot+bpf-ci
2026-11-05 20:45 ` [PATCH bpf-next v2 33/35] selftests/bpf: Test loops that are counted, walked or widened Alexei Starovoitov
2026-11-05 20:45 ` [PATCH bpf-next v2 34/35] selftests/bpf: Test progs that run out of budget Alexei Starovoitov
2026-11-05 21:35   ` bot+bpf-ci
2026-11-05 23:19   ` sashiko-bot
2026-11-05 20:45 ` [PATCH bpf-next v2 35/35] selftests/bpf: Test callx of one of a set of functions Alexei Starovoitov
2026-11-05 23:17   ` sashiko-bot
2026-11-06  0:34 ` [PATCH bpf-next v2 00/35] bpf: A verifier that joins states 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=sashiko-outbox-200329@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