bpf: Fix packet range of pointers sharing an id

Since commit 022ac0750883 ("bpf: use reg->var_off instead of reg->off
for pointers"), find_good_pkt_pointers() sets the range of all packet
pointers sharing an id from the umax of the compared pointer, and
check_packet_access() requires umax + off + size <= range.  That assumes
the umax of two such pointers differ by exactly their constant distance.
reg_bounds_sync() breaks it when var_off tightens one umax and not the
other:

	r4 &= 0x38
	if r4 > 50 goto exit     ; umax 50, var_off (0x0; 0x38)
	r5 = pkt + r4            ; umax 50
	r6 = r5
	r6 += 8                  ; umax 56, not 58

Comparing r6 with pkt_end sets the range to 56, and the valid 8-byte
load at r5 is rejected (50 + 8 > 56).  Comparing r5 sets it to 50, and
the out-of-bounds 1-byte load at r6 - 7, i.e. r5 + 1, is accepted
(56 - 7 + 1 <= 50).

Don't call reg_bounds_sync() on a packet pointer that keeps its id (a
constant was added or subtracted) or its range (an unknown non-negative
value was subtracted), so that var_off cannot tighten its umax.  Only
update the 32-bit bounds from var_off: reg_bounds_sanity_check() wants
them constant when the lower half of var_off is, e.g. for pkt + 8.

This relies on nothing else changing the 64-bit bounds of a packet
pointer, which holds today.

var_off of such a pointer is no longer narrowed by its bounds.  Adjust
three verifier_align expectations; the low bits, which the alignment
checks use, don't change.  veristat on the selftests shows no verdict
changes and +0.8% insns in test_cls_redirect_subprogs.

Fixes: 022ac0750883 ("bpf: use reg->var_off instead of reg->off for pointers")
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://lore.kernel.org/bpf/20261001145255.855630-1-alexei.starovoitov@gmail.com
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
2 files changed