From: sashiko-bot@kernel.org
To: "Alexei Starovoitov" <alexei.starovoitov@gmail.com>, bpf@vger.kernel.org
Subject: Re: [PATCH bpf-next v3 01/45] bpf: Add may_goto to the loops that the verifier marks
Date: Fri, 06 Nov 2026 04:22:33 +0000 [thread overview]
Message-ID: <sashiko-outbox-200712@kernel.org> (raw)
In-Reply-To: <20261106035111.3315285-2-alexei.starovoitov@gmail.com>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] bpf: bpf_insert_loop_guards() logs shifted insn index instead of orig_idx
--
commit 4a3883a17feaa6708a44e871a9a6eab87f5197bc
Author: Alexei Starovoitov <ast@kernel.org>
bpf: Add may_goto to the loops that the verifier marks
This commit introduces bpf_insert_loop_guards() to insert may_goto
instructions in front of loop instructions marked by the verifier, along
with per-subprogram budget exit sequences when needed.
> diff --git a/kernel/bpf/fixups.c b/kernel/bpf/fixups.c
> index f95af2ca3591b..6fd79c2fbdc1e 100644
> --- a/kernel/bpf/fixups.c
> +++ b/kernel/bpf/fixups.c
> @@ -587,6 +587,225 @@ static int bpf_adj_moved_insn(struct bpf_insn *insn, u32 delta)
[ ... ]
> +int bpf_insert_loop_guards(struct bpf_verifier_env *env)
> +{
> + struct bpf_insn_aux_data *aux = env->insn_aux_data;
> + int len = env->prog->len, i, r, s, to, n, jmp, err = 0;
> + struct bpf_insn *patch, *insn;
> + int *target, *leave, *moved;
> + bool indirect;
> + u16 *zero;
> + s64 off;
> +
> + for (i = 0; i < len; i++)
> + if (aux[i].loop_guard)
> + break;
> + if (i == len)
> + return 0;
> +
> + /*
> + * Where the subprog has 'r0 = 0; exit', 0 if it has none. And how far that moved
> + * the subprog: guard_to is from the time before.
> + */
> + leave = kvcalloc(2 * env->subprog_cnt, sizeof(int), GFP_KERNEL_ACCOUNT);
> + if (!leave)
> + return -ENOMEM;
> + moved = leave + env->subprog_cnt;
> + for (s = 0; s < env->subprog_cnt && !err; s++) {
> + leave[s] = append_budget_exit(env, s);
> + if (leave[s] < 0)
> + err = leave[s];
> + }
> + /* A guard cannot jump into a patch that is in the list: 'r0 = 0' has no index yet. */
> + err = err ?: bpf_patch_list_commit(env);
[ ... ]
> + for (i = 0; i < len; i++) {
> + to = target[i];
> + if (to == -1)
> + continue;
> + /*
> + * may_goto to or may_goto +1
> + * insn goto +N
> + * r0 = 0, ...
> + * exit
> + * insn
> + */
> + n = 0;
> + if (zero[i]) {
> + patch[n++] = BPF_RAW_INSN(BPF_JMP | BPF_JCOND, 0, 0, 1, 0);
> + patch[n++] = BPF_JMP_A(hweight16(zero[i]) + 1);
> + for (r = BPF_REG_0; r < BPF_REG_FP; r++)
> + if (zero[i] & BIT(r))
> + patch[n++] = BPF_MOV64_IMM(r, 0);
> + }
> + jmp = n++;
> + /* What is behind moves with this patch. The other patches are not there yet. */
> + if (to == -2)
> + off = 0;
> + else if (to > i)
> + off = to - i + n - jmp - 1;
> + else
> + off = to - (i + jmp) - 1;
> + if (off > S16_MAX || off < S16_MIN) {
> + verbose(env, "exit of the loop is too far from insn %d for may_goto\n", i);
> + err = -ERANGE;
> + break;
> + }
> + patch[jmp] = BPF_RAW_INSN(BPF_JMP | BPF_JCOND, 0, 0, off, 0);
> + if (to == -2)
> + patch[jmp] = budget_exit_insn(env, bpf_find_containing_subprog(env, i));
> + patch[n] = env->prog->insnsi[i];
> + /* A jump to itself is a back edge. It goes through may_goto like the others. */
> + if (jumps_to_itself(&patch[n]))
> + patch[n].off -= n;
> + else
> + err = bpf_adj_moved_insn(&patch[n], n);
> + if (err) {
> + verbose(env, "insn %d cannot be patched due to 16-bit range\n", i);
> + break;
> + }
[Severity: Low]
As reported by Sashiko on v2 [1], should these two verbose() calls in
bpf_insert_loop_guards() log aux[i].orig_idx instead of i?
The first pass in bpf_insert_loop_guards() calls append_budget_exit() for
each subprogram with a near loop guard that leaves the subprogram, and
commits those patches via bpf_patch_list_commit(env). Each appended budget
exit adds 2 or 3 instructions to the end of its subprogram, shifting the
instruction index i in all subsequent subprograms by moved[s]. If the
second pass then fails because off overflows 16 bits or
bpf_adj_moved_insn() returns -ERANGE, logging i reports the shifted index
rather than the original instruction index from the user program (unlike
bpf_patch_list_insert(), bpf_patch_list_commit(), and
bpf_convert_ctx_accesses() in kernel/bpf/fixups.c, which log orig_idx).
Similarly, in kernel/bpf/verifier.c:bpf_check():
if (ret == 0)
ret = bpf_insert_loop_guards(env);
skip_full_check:
kvfree(env->explored_states);
/* might decrease stack depth, keep it before passes that
* allocate additional slots.
*/
if (ret == 0)
ret = bpf_remove_fastcall_spills_fills(env);
if (ret == 0)
ret = check_max_stack_depth(env);
/* instruction rewrites happen after this point */
if (ret == 0)
ret = bpf_optimize_bpf_loop(env);
bpf_insert_loop_guards() is called before check_max_stack_depth(), ahead of
the "instruction rewrites happen after this point" boundary. Because helpers
called by check_max_stack_depth() (such as find_call_insn() in
check_exception_cb() and check_recursion(), as well as check_callbacks())
log raw instruction indices in env->prog->insnsi rather than orig_idx,
rewriting the program in bpf_insert_loop_guards() before
check_max_stack_depth() will also shift the instruction indices reported by
those diagnostics. Should bpf_insert_loop_guards() be moved after
check_max_stack_depth() with the other instruction rewrite passes?
[1] https://lore.kernel.org/r/20261105204513.2230344-2-alexei.starovoitov@gmail.com
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261106035111.3315285-1-alexei.starovoitov@gmail.com?part=1
next prev parent reply other threads:[~2026-11-06 4:22 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 [this message]
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
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-200712@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