From: sashiko-bot@kernel.org
To: "Alexei Starovoitov" <alexei.starovoitov@gmail.com>, bpf@vger.kernel.org
Subject: Re: [PATCH bpf-next v2 34/35] selftests/bpf: Test progs that run out of budget
Date: Thu, 05 Nov 2026 23:19:04 +0000 [thread overview]
Message-ID: <sashiko-outbox-200365@kernel.org> (raw)
In-Reply-To: <20261105204513.2230344-35-alexei.starovoitov@gmail.com>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] selftests/bpf: use RUN_JITED() in serial_test_verifier_budget()
- [Medium] selftests/bpf: loop_in_main() and loop_in_main_rcu() never run out of budget
--
commit a539b7e8368514c3719738508a3c302fb0c6d907
Author: Alexei Starovoitov <ast@kernel.org>
selftests/bpf: Test progs that run out of budget
This commit adds BPF verifier selftests for programs that exhaust their loop
or recursion runtime budget, along with a test for packet pointer invalidation
after indirect calls in verifier_callx.c.
> diff --git a/tools/testing/selftests/bpf/prog_tests/verifier.c b/tools/testing/selftests/bpf/prog_tests/verifier.c
> index 1424dc3036c5d..5b3eacb36a6cc 100644
> --- a/tools/testing/selftests/bpf/prog_tests/verifier.c
> +++ b/tools/testing/selftests/bpf/prog_tests/verifier.c
[ ... ]
> @@ -235,6 +236,8 @@ void test_verifier_bounds_mix_sign_unsign(void) { RUN(verifier_bounds_mix_sign_u
> void test_verifier_bpf_get_stack(void) { RUN(verifier_bpf_get_stack); }
> void test_verifier_bpf_trap(void) { RUN(verifier_bpf_trap); }
> void test_verifier_bswap(void) { RUN(verifier_bswap); }
> +/* Serial: many progs spin for 250 ms in an RCU read-side critical section, see timed_may_goto.c */
> +void serial_test_verifier_budget(void) { RUN(verifier_budget); }
[Severity: Medium]
Should serial_test_verifier_budget() use RUN_JITED(verifier_budget) instead of
RUN(verifier_budget) (matching test_verifier_callx() and
test_verifier_callx_rodata())?
When BPF JIT is disabled (for example with bpf_jit_enable=0),
is_jit_enabled() is false and prog->jit_requested is 0, while none of the
subtests in verifier_budget.c specify __load_if_JITed():
1. callback_arms_itself() has no architecture filter and passes a callback to
bpf_timer_set_callback(), which jit_subprogs() rejects with "callbacks are not
allowed in non-JITed programs".
2. Subtests with recursive subprograms (such as recursion(),
recursion_too_deep(), recursion_ends_in_the_middle(), and others) fail in
check_recursion() with -EOPNOTSUPP because bpf_prog_has_invocation_budget()
requires prog->jit_requested.
3. Subtests using unwind_goto or unwind_exit (such as loop_in_subprog_caught()
and loop_in_subprog_locked()) set prog->jit_required = 1 in
check_unwind_insns() and fail to load without JIT.
4. guard_all_regs_live() asserts per-cpu timed may_goto instructions
("r0 = &(void __percpu *)(r0)") via __xlated, which bpf_do_misc_fixups() only
emits when timed_may_goto is enabled.
5. In may_goto_stays_in_loop(), without timed may_goto in JIT,
bpf_do_misc_fixups() expands both may_goto_self and the verifier-added
may_goto at the loop head with separate stack counters via may_goto_expand().
Each time may_goto_self counts down 8M iterations and jumps to the loop head,
the outer may_goto decrements once and may_goto_self re-initializes to 8M,
resulting in 2^46 iterations in the interpreter.
> diff --git a/tools/testing/selftests/bpf/progs/verifier_budget.c b/tools/testing/selftests/bpf/progs/verifier_budget.c
> new file mode 100644
> index 0000000000000..1aa5b3eff712d
> --- /dev/null
> +++ b/tools/testing/selftests/bpf/progs/verifier_budget.c
> @@ -0,0 +1,1873 @@
[ ... ]
> +/* The verifier doesn't know what is in there */
> +unsigned long zero;
> +unsigned long one = 1;
[ ... ]
> +SEC("socket")
> +__description("budget: a loop in the main prog ends it")
> +__arch_x86_64
> +__arch_arm64
> +__success __retval(1)
> +__naked void loop_in_main(void)
> +{
> + asm volatile (
> + "r6 = %[zero] ll;"
> + "1:"
> + "r1 = *(u64 *)(r6 + 0);"
> + "if r1 != 0 goto 1b;"
> + "r0 = 1;"
> + "exit;"
> + :
> + : __imm_addr(zero)
> + : __clobber_all
> + );
> +}
> +
> +SEC("socket")
> +__description("budget: a loop in the main prog that holds something is left")
> +__arch_x86_64
> +__arch_arm64
> +__success __retval(1)
> +__naked void loop_in_main_rcu(void)
> +{
> + asm volatile (
> + "r6 = %[zero] ll;"
> + "call %[bpf_rcu_read_lock];"
> + "1:"
> + "r1 = *(u64 *)(r6 + 0);"
> + "if r1 != 0 goto 1b;"
> + "call %[bpf_rcu_read_unlock];"
> + "r0 = 1;"
> + "exit;"
> + :
> + : __imm_addr(zero),
> + __imm(bpf_rcu_read_lock),
> + __imm(bpf_rcu_read_unlock)
> + : __clobber_all
> + );
> +}
[Severity: Medium]
Should loop_in_main() and loop_in_main_rcu() load the address of one instead
of zero (and should loop_in_main() expect __retval(0))?
Because r6 is initialized from zero, "r1 = *(u64 *)(r6 + 0);" loads 0 on the
first trip and "if r1 != 0 goto 1b;" falls through immediately without
spinning or running out of budget.
In loop_in_main(), falling through executes "r0 = 1; exit;" instead of timing
out on the verifier-added may_goto and jumping to the budget exit ("r0 = 0;
exit;") when the main prog holds nothing. In loop_in_main_rcu(), the loop
exits via the normal branch condition on the first trip rather than timing out
via the verifier-added may_goto while holding the RCU read lock.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261105204513.2230344-1-alexei.starovoitov@gmail.com?part=34
next prev parent reply other threads:[~2026-11-05 23:19 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
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 [this message]
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-200365@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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.