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 v3 27/45] bpf: Track a pointer to one of a set of functions
Date: Fri, 06 Nov 2026 04:49:52 +0000	[thread overview]
Message-ID: <sashiko-outbox-200769@kernel.org> (raw)
In-Reply-To: <20261106035111.3315285-28-alexei.starovoitov@gmail.com>

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] bpf: unconditional R1-R5 split in do_check_insn() causes state explosion
--

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

bpf: Track a pointer to one of a set of functions

This commit tracks a pointer read from a function table as a single
register state representing a set of target functions (func_set) instead
of branching states at the load instruction. The function set is later
expanded into individual function targets when a callx instruction or a
helper/kfunc call requires a specific function.

> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index 437a3fc03d0bf..41500f03b41be 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
[ ... ]
> @@ -12028,13 +12072,93 @@ static int check_func_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
[ ... ]
> +/* The insn needs to know the function: go on with each function of the set. */
> +static int split_func_set(struct bpf_verifier_env *env, int regno)
> +{
> +	struct bpf_reg_state *reg = reg_state(env, regno);
> +	struct bpf_verifier_state *branch;
> +	struct bpf_func_set *set;
> +	u32 i;
> +
> +	if (reg->type != PTR_TO_FUNC || !reg->func_set)
> +		return 0;
> +	set = env->func_sets[reg->func_set - 1];
> +	reg->func_set = 0;
> +	for (i = 0; i < set->cnt; i++) {
> +		reg->subprogno = set->subprog[i];
> +		if (i == set->cnt - 1)
> +			break;
> +		branch = push_stack(env, env->insn_idx, env->insn_idx, false);
> +		if (IS_ERR(branch))
> +			return PTR_ERR(branch);
> +	}
> +	return 0;
> +}
[ ... ]
> @@ -20952,6 +21068,12 @@ static int do_check_insn(struct bpf_verifier_env *env, bool *do_print_state)
>  				return check_func_callx(env, insn, &env->insn_idx);
>  			if (insn->src_reg == BPF_PSEUDO_CALL)
>  				return check_func_call(env, insn, &env->insn_idx);
> +			/* a callback is one function */
> +			for (i = BPF_REG_1; i <= BPF_REG_5; i++) {
> +				err = split_func_set(env, i);
> +				if (err)
> +					return err;
> +			}
>  			if (insn->src_reg == BPF_PSEUDO_KFUNC_CALL)
>  				return check_kfunc_call(env, insn, &env->insn_idx);
>  			return check_helper_call(env, insn, &env->insn_idx);

[Severity: Medium]
In do_check_insn(), split_func_set() is called unconditionally across all
registers BPF_REG_1 through BPF_REG_5 before every kfunc and helper call,
without checking whether the register is actually a callback argument or
even live at env->insn_idx.

Within a basic block, helper and kfunc calls that do not invoke synchronous
callbacks do not have a flow point set, so do_check_block() steps into the
call instruction without running bpf_flow_deliver() or
bpf_clean_verifier_state():

  do_check_block()
    do_check_insn()
      split_func_set()

If a caller-saved register in R1..R5 was loaded with a func_set of size N
earlier in the block and copied to a callee-saved register R6..R9 or
spilled to the stack before a helper or kfunc call that does not overwrite
that register, the dead register still holds PTR_TO_FUNC with reg->func_set
set when reaching the call.

In that case, split_func_set() clones env->cur_state N - 1 times onto
env->head at env->insn_idx. After env->cur_state finishes the call,
flow_drain() delivers those N - 1 states to env->insn_idx, allocating N - 1
flow_state objects, cleaning the dead register in flow_arrive(), and queuing
a duplicate pending state at env->insn_idx that re-verifies the call and the
rest of the basic block a second time.

Furthermore, if a second register in R1..R5 is marked live in
live_regs_before at the call while also holding a func_set, looping over
BPF_REG_1..BPF_REG_5 splits both registers and produces all N * N
combinations at env->insn_idx. For example, bpf_timer_set_callback_proto
sets arg3_type = ARG_PTR_TO_PROG_AUX, which causes bpf_get_call_summary() to
set arg_slot_cnt = 3 and compute_insn_live_regs() to mark R3 live in
live_regs_before even though the BPF program only passes R1 and R2. If a
program loads a callback from a table of N >= 33 functions into R3 and
copies r2 = r3 before calling bpf_timer_set_callback(), splitting both R2
and R3 creates N * N >= 1089 unjoinable states at env->insn_idx, exceeding
BPF_FLOW_MAX_STATES (1024) in flow_merge() and failing verification with
-E2BIG.

Should split_func_set() only be invoked for registers that correspond to
actual callback arguments (such as inside check_func_arg() /
process_kf_arg_ptr_to_func(), or gated on the call prototype and
live_regs_before)?

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

  reply	other threads:[~2026-11-06  4:49 UTC|newest]

Thread overview: 77+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-06  3:50 [PATCH bpf-next v3 00/45] bpf: A verifier that joins states Alexei Starovoitov
2026-11-06  3:50 ` [PATCH bpf-next v3 01/45] bpf: Add may_goto to the loops that the verifier marks Alexei Starovoitov
2026-11-06  4:22   ` sashiko-bot
2026-11-06  4:38   ` bot+bpf-ci
2026-11-06  3:50 ` [PATCH bpf-next v3 02/45] bpf: Limit depth and time of recursive subprogs at run time Alexei Starovoitov
2026-11-06  3:50 ` [PATCH bpf-next v3 03/45] bpf: Add union and widening of the range of a register Alexei Starovoitov
2026-11-06  3:50 ` [PATCH bpf-next v3 04/45] bpf: Add join of registers and stack slots Alexei Starovoitov
2026-11-06  4:39   ` sashiko-bot
2026-11-06  3:50 ` [PATCH bpf-next v3 05/45] bpf: Add join of verifier states Alexei Starovoitov
2026-11-06  4:25   ` sashiko-bot
2026-11-06  4:38   ` bot+bpf-ci
2026-11-06  3:50 ` [PATCH bpf-next v3 06/45] bpf: Tell which arguments of a call a join must leave alone Alexei Starovoitov
2026-11-06  3:50 ` [PATCH bpf-next v3 07/45] bpf: Add the data structures of the main pass over the control flow graph Alexei Starovoitov
2026-11-06  4:24   ` bot+bpf-ci
2026-11-06  3:50 ` [PATCH bpf-next v3 08/45] bpf: Order the insns, find what stops a loop and where may_goto can go Alexei Starovoitov
2026-11-06  3:50 ` [PATCH bpf-next v3 09/45] bpf: Find the registers that hold a number or a pointer to arena Alexei Starovoitov
2026-11-06  3:50 ` [PATCH bpf-next v3 10/45] bpf: Find the registers and stack slots that later checks depend on Alexei Starovoitov
2026-11-06  4:08   ` sashiko-bot
2026-11-06  3:50 ` [PATCH bpf-next v3 11/45] bpf: Add the sets of states at an insn and the entries of functions Alexei Starovoitov
2026-11-06  3:50 ` [PATCH bpf-next v3 12/45] bpf: Compare states of different iterations of a loop Alexei Starovoitov
2026-11-06  3:50 ` [PATCH bpf-next v3 13/45] bpf: Decide which states are not joined Alexei Starovoitov
2026-11-06  4:38   ` bot+bpf-ci
2026-11-06  3:50 ` [PATCH bpf-next v3 14/45] bpf: Merge the state that arrives into the set at an insn Alexei Starovoitov
2026-11-06  4:24   ` bot+bpf-ci
2026-11-06  3:50 ` [PATCH bpf-next v3 15/45] bpf: Move states along edges, into loops and subprogs and out of them Alexei Starovoitov
2026-11-06  3:50 ` [PATCH bpf-next v3 16/45] bpf: Make the state after a call from the caller's state and an exit state Alexei Starovoitov
2026-11-06  4:34   ` sashiko-bot
2026-11-06  3:50 ` [PATCH bpf-next v3 17/45] bpf: Enter and leave loops in the main pass, build flow.c Alexei Starovoitov
2026-11-06  4:38   ` bot+bpf-ci
2026-11-06  3:50 ` [PATCH bpf-next v3 18/45] bpf: Tell the passes over the graph where an added may_goto goes Alexei Starovoitov
2026-11-06  4:26   ` sashiko-bot
2026-11-06  3:50 ` [PATCH bpf-next v3 19/45] bpf: Verify programs as a fixpoint over the control flow graph Alexei Starovoitov
2026-11-06  4:38   ` bot+bpf-ci
2026-11-06  4:55   ` sashiko-bot
2026-11-06  3:50 ` [PATCH bpf-next v3 20/45] bpf: Keep the count of a loop when a register has no closed form Alexei Starovoitov
2026-11-06  4:38   ` bot+bpf-ci
2026-11-06  3:50 ` [PATCH bpf-next v3 21/45] bpf: Verify static subprogs on their own Alexei Starovoitov
2026-11-06  4:50   ` bot+bpf-ci
2026-11-06  4:53   ` sashiko-bot
2026-11-06  3:50 ` [PATCH bpf-next v3 22/45] bpf: Allow recursive subprogs Alexei Starovoitov
2026-11-06  4:38   ` bot+bpf-ci
2026-11-06  5:09   ` sashiko-bot
2026-11-06  3:50 ` [PATCH bpf-next v3 23/45] bpf: Remove is_state_visited(), bpf_compute_scc() and iter.depth Alexei Starovoitov
2026-11-06  3:50 ` [PATCH bpf-next v3 24/45] bpf: Remove precision tracking Alexei Starovoitov
2026-11-06  4:24   ` bot+bpf-ci
2026-11-06  3:50 ` [PATCH bpf-next v3 25/45] bpf: Remove prune points, levels of state comparison and pop_stack() Alexei Starovoitov
2026-11-06  3:50 ` [PATCH bpf-next v3 26/45] bpf: Update comments about paths, pruning and explored states Alexei Starovoitov
2026-11-06  4:19   ` sashiko-bot
2026-11-06  4:24   ` bot+bpf-ci
2026-11-06  3:50 ` [PATCH bpf-next v3 27/45] bpf: Track a pointer to one of a set of functions Alexei Starovoitov
2026-11-06  4:49   ` sashiko-bot [this message]
2026-11-06  3:50 ` [PATCH bpf-next v3 28/45] bpf: callx reads what the subprogs whose address is taken read Alexei Starovoitov
2026-11-06  3:50 ` [PATCH bpf-next v3 29/45] bpf: Don't take what bpf_core_cast() returns for a number Alexei Starovoitov
2026-11-06  3:50 ` [PATCH bpf-next v3 30/45] bpf: Don't widen away a register that only the loop sets Alexei Starovoitov
2026-11-06  3:50 ` [PATCH bpf-next v3 31/45] bpf: A base that nothing is known about can be the context Alexei Starovoitov
2026-11-06  3:50 ` [PATCH bpf-next v3 32/45] bpf: Keep the frames of the caller for a subprog that loads data_end Alexei Starovoitov
2026-11-06  4:24   ` bot+bpf-ci
2026-11-06  3:50 ` [PATCH bpf-next v3 33/45] bpf: Keep the frames of the caller for ctx of struct_ops with a reference Alexei Starovoitov
2026-11-06  4:24   ` bot+bpf-ci
2026-11-06  3:50 ` [PATCH bpf-next v3 34/45] bpf: R0 is live at the exit that an added may_goto goes to Alexei Starovoitov
2026-11-06  3:50 ` [PATCH bpf-next v3 35/45] bpf: Keep the step of a number in the union of two ranges Alexei Starovoitov
2026-11-06  3:51 ` [PATCH bpf-next v3 36/45] bpf: Keep the first iteration of a counted loop apart Alexei Starovoitov
2026-11-06  4:38   ` bot+bpf-ci
2026-11-06  3:51 ` [PATCH bpf-next v3 37/45] bpf: What a call returns in each iteration is like what the loop loads Alexei Starovoitov
2026-11-06  3:51 ` [PATCH bpf-next v3 38/45] bpf: Find where the jumps of a loop stop a number Alexei Starovoitov
2026-11-06  3:51 ` [PATCH bpf-next v3 39/45] selftests/bpf: Adjust tests to log lines that are gone Alexei Starovoitov
2026-11-06  4:38   ` bot+bpf-ci
2026-11-06  3:51 ` [PATCH bpf-next v3 40/45] selftests/bpf: Adjust tests to new verdicts, messages and order Alexei Starovoitov
2026-11-06  4:25   ` bot+bpf-ci
2026-11-06  4:34   ` sashiko-bot
2026-11-06  3:51 ` [PATCH bpf-next v3 41/45] selftests/bpf: Test states that are not joined Alexei Starovoitov
2026-11-06  3:51 ` [PATCH bpf-next v3 42/45] selftests/bpf: Test static subprogs that are verified on their own Alexei Starovoitov
2026-11-06  3:51 ` [PATCH bpf-next v3 43/45] selftests/bpf: Test loops that are counted, walked or widened Alexei Starovoitov
2026-11-06  3:51 ` [PATCH bpf-next v3 44/45] selftests/bpf: Test progs that run out of budget Alexei Starovoitov
2026-11-06  3:51 ` [PATCH bpf-next v3 45/45] selftests/bpf: Test callx of one of a set of functions Alexei Starovoitov
2026-11-06  4:52   ` sashiko-bot
2026-11-06 18:08 ` [PATCH bpf-next v3 00/45] bpf: A verifier that joins states Eduard Zingerman

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-200769@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