BPF List
 help / color / mirror / Atom feed
* [PATCH bpf-next 0/8] bpf: Verify loops without walking every iteration
@ 2026-09-23 22:35 Alexei Starovoitov
  2026-09-23 22:35 ` [PATCH bpf-next 1/8] bpf: Trim range ends to var_off members Alexei Starovoitov
                   ` (7 more replies)
  0 siblings, 8 replies; 20+ messages in thread
From: Alexei Starovoitov @ 2026-09-23 22:35 UTC (permalink / raw)
  To: bpf; +Cc: daniel, andrii, eddyz87, memxor

From: Alexei Starovoitov <ast@kernel.org>

This is RFC, but without RFC tag. See patch 6 for numbers.
I can clean it up for core idea looks good.

bot time...

The verifier walks a bounded loop one iteration at a time. The work is
proportional to the number of iterations, and the loop with too many of
them is rejected with "BPF program is too large" no matter how simple
it is.

Verify loops the way open coded iterators are verified. The state that
comes back to the loop head is either within the state that went around
the loop, and then there is nothing new to see, or its scalars are widened
and it goes around again. The range of the counter ends at the constant
the loop compares it with, so that a loop like

  for (i = 0; i != 1000000; i += 4)
          sum += *(u32 *)(val + i);

is verified in two trips around the loop and 24 insns.

The loop that is verified this way is not known to terminate:
 - if no state leaves the loop the program never leaves it either.
   Such loop is rejected as before.
 - otherwise the verifier adds may_goto to the back-edge. When may_goto
   is out of budget the program ends with bpf_throw(). Loops that go
   through may_goto or iterator already, and loops that are walked to the
   end are not touched.

Patch 1 trims range ends to var_off members. Without it the loop above
doesn't converge: the range of 'i' is [4, 1000003] after 'i += 4' and
'!=' cannot cut it.
Patch 2 marks loop heads.
Patch 3 widens states at loop heads.
Patch 4 detects loops that never exit.
Patch 5 adds may_goto.
Patch 6 turns it all on.
Patches 7 and 8 are selftests.

Widening gives up precision and bpf_throw() cannot be called everywhere,
so patch 6 walks the program with widening first and walks it the old
way when that fails. Nothing that is accepted today is rejected.
veristat for selftests (5251 programs):
 - 4 programs that were rejected are accepted: loop3/while_true,
   verifier_cfg/conditional_loop, verifier_movsx/mov64sx_s32_varoff_1,
   verifier_search_pruning/short_loop1. All have may_goto added.
 - 163 programs have different stats. 126 programs are walked twice and
   have the same stats as before.
 - insns processed in programs accepted before and after:
   5569499 -> 4774715 plus 88708 in walks that failed (-12.7%).
   loop1/nested_loops 361349 -> 135.
Patches 1-5 alone don't change stats of any program.

Not done:
 - pointers are not widened, only scalars. The loop that advances
   a pointer is walked every iteration.
 - constants that the counter is compared with come from 'if rX op imm'
   only. The bound in a register is not used.
 - may_goto is added to every loop that converged, also to the one that
   is bounded by its counter. It is a few insns per iteration.
 - when the program is rejected or has a loop that cannot have may_goto
   all of it is walked twice. The second walk of the rejected program
   can take 1M insns.

Alexei Starovoitov (8):
  bpf: Trim range ends to var_off members
  bpf: Mark loop heads in check_cfg()
  bpf: Widen scalars at loop heads
  bpf: Detect loops that never exit
  bpf: Add may_goto to loops that are not walked to the end
  bpf: Walk loops with widened states first
  selftests/bpf: Adjust tests to widened loops
  selftests/bpf: Add tests for widened loops

 include/linux/bpf_verifier.h                  |  31 +
 kernel/bpf/cfg.c                              |   8 +-
 kernel/bpf/fixups.c                           | 153 +++++
 kernel/bpf/states.c                           | 144 ++++-
 kernel/bpf/verifier.c                         | 609 +++++++++++++++++-
 .../bpf/prog_tests/bpf_verif_scale.c          |   4 +-
 .../selftests/bpf/prog_tests/verifier.c       |   2 +
 .../selftests/bpf/progs/verifier_cfg.c        |   4 +-
 .../selftests/bpf/progs/verifier_loop_widen.c | 344 ++++++++++
 .../selftests/bpf/progs/verifier_movsx.c      |   2 +-
 .../selftests/bpf/progs/verifier_precision.c  |  29 +-
 .../bpf/progs/verifier_search_pruning.c       |   3 +-
 tools/testing/selftests/bpf/verifier/calls.c  |   5 +-
 13 files changed, 1306 insertions(+), 32 deletions(-)
 create mode 100644 tools/testing/selftests/bpf/progs/verifier_loop_widen.c


base-commit: 91f8613d95ad8cd99d8baf094806d1ef98bc6380
-- 
2.55.0


^ permalink raw reply	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2026-09-23 23:48 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-23 22:35 [PATCH bpf-next 0/8] bpf: Verify loops without walking every iteration Alexei Starovoitov
2026-09-23 22:35 ` [PATCH bpf-next 1/8] bpf: Trim range ends to var_off members Alexei Starovoitov
2026-09-23 23:37   ` bot+bpf-ci
2026-09-23 22:35 ` [PATCH bpf-next 2/8] bpf: Mark loop heads in check_cfg() Alexei Starovoitov
2026-09-23 23:05   ` sashiko-bot
2026-09-23 23:37   ` bot+bpf-ci
2026-09-23 22:35 ` [PATCH bpf-next 3/8] bpf: Widen scalars at loop heads Alexei Starovoitov
2026-09-23 23:37   ` bot+bpf-ci
2026-09-23 22:35 ` [PATCH bpf-next 4/8] bpf: Detect loops that never exit Alexei Starovoitov
2026-09-23 23:25   ` sashiko-bot
2026-09-23 23:37   ` bot+bpf-ci
2026-09-23 22:35 ` [PATCH bpf-next 5/8] bpf: Add may_goto to loops that are not walked to the end Alexei Starovoitov
2026-09-23 23:37   ` bot+bpf-ci
2026-09-23 23:48   ` sashiko-bot
2026-09-23 22:35 ` [PATCH bpf-next 6/8] bpf: Walk loops with widened states first Alexei Starovoitov
2026-09-23 23:23   ` bot+bpf-ci
2026-09-23 22:35 ` [PATCH bpf-next 7/8] selftests/bpf: Adjust tests to widened loops Alexei Starovoitov
2026-09-23 23:37   ` bot+bpf-ci
2026-09-23 22:35 ` [PATCH bpf-next 8/8] selftests/bpf: Add tests for " Alexei Starovoitov
2026-09-23 23:23   ` bot+bpf-ci

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox