BPF verifier fix stops bogus packet reads after loop widening
Scalar evolution had been shrinking a packet pointer's upper bound without cutting the recorded valid length, so counted loops could pass checks for bytes past the end of the packet.
Alexei Starovoitov has posted a two-patch series for the BPF verifier that closes a hole where programs with counted loops could be accepted even though they read past the end of a packet.
The flaw sits in how scalar evolution widens packet pointers at loop heads. The verifier treats only a limited number of bytes past a packet pointer as still inside the packet: roughly the tracked range minus the pointer's upper bound. When evolution installs new bounds, a later sync step can lower that upper bound (for example from 58 down to 56 when the step is 8) while leaving the range unchanged. The verifier then believes two extra bytes are still valid and allows loads that a kernel without scalar evolution would reject. The same class of mistake appears for pointers that step downward and for unions that tighten variable offsets.
Sashiko spotted the issue while reviewing related scalar-evolution work. Starovoitov’s fix shrinks the range by the same amount the upper bound shrinks, so the number of bytes known to be inside the packet never grows. A mark that a pointer is already at or beyond the packet end is also cleared when the pointer is widened, because that mark is only meaningful on the first iteration.
Selftests cover the step-down, clamp, and union cases that previously loaded or only failed on a later pass. Starovoitov reports unchanged verdicts and instruction counts across thousands of Cilium and sched-ext programs from weekly builds, and no new failures in the usual BPF test suites on x86-64.
Automated review of the series raised further questions about clamp paths and signed ranges that may still need tightening before the change lands.