Yes, I will add a selftest with a truly varying offset, as suggested. I will include this in the next version.
> -----Original Messages----- > From: "Eduard Zingerman" <[email protected]> > Send time:Friday, 05/06/2026 10:23:41 > To: "Nuoqi Gui" <[email protected]>, [email protected], > [email protected], [email protected] > Cc: "Martin KaFai Lau" <[email protected]>, "Kumar Kartikeya Dwivedi" > <[email protected]>, "Song Liu" <[email protected]>, "Yonghong Song" > <[email protected]>, "Jiri Olsa" <[email protected]>, "Shuah Khan" > <[email protected]>, "Shenghao Yuan" <[email protected]>, "Yazhou Tang" > <[email protected]>, "Matt Bobrowski" <[email protected]>, > "Emil Tsalapatis" <[email protected]>, [email protected], > [email protected], [email protected] > Subject: Re: [PATCH bpf-next v2 2/2] selftests/bpf: add tests for > PTR_TO_FLOW_KEYS constant offset bounds > > On Fri, 2026-06-05 at 02:07 +0800, Nuoqi Gui wrote: > > Add verifier tests covering constant pointer arithmetic on a > > PTR_TO_FLOW_KEYS register, which regressed with commit 022ac0750883 > > ("bpf: use reg->var_off instead of reg->off for pointers"): an > > out-of-bounds offset introduced as flow_keys += K and then dereferenced > > at insn->off 0 was accepted, while the equivalent flow_keys + K direct > > offset was rejected. > > > > The tests check that: > > - in-bounds constant arithmetic on the keys pointer is still accepted, > > - an out-of-bounds offset introduced via constant arithmetic is rejected > > for both read and write, with the same diagnostic as the direct > > insn->off form. > > > > Signed-off-by: Nuoqi Gui <[email protected]> > > --- > > .../selftests/bpf/prog_tests/verifier.c | 2 + > > .../selftests/bpf/progs/verifier_flow_keys.c | 77 +++++++++++++++++++ > > 2 files changed, 79 insertions(+) > > create mode 100644 tools/testing/selftests/bpf/progs/verifier_flow_keys.c > > > > diff --git a/tools/testing/selftests/bpf/prog_tests/verifier.c > > b/tools/testing/selftests/bpf/prog_tests/verifier.c > > index 219ff2969868..dae26dda3782 100644 > > --- a/tools/testing/selftests/bpf/prog_tests/verifier.c > > +++ b/tools/testing/selftests/bpf/prog_tests/verifier.c > > @@ -38,6 +38,7 @@ > > #include "verifier_div0.skel.h" > > #include "verifier_div_mod_bounds.skel.h" > > #include "verifier_div_overflow.skel.h" > > +#include "verifier_flow_keys.skel.h" > > #include "verifier_global_subprogs.skel.h" > > #include "verifier_global_ptr_args.skel.h" > > #include "verifier_gotol.skel.h" > > @@ -189,6 +190,7 @@ void test_verifier_direct_stack_access_wraparound(void) > > { RUN(verifier_direct_st > > void test_verifier_div0(void) { RUN(verifier_div0); } > > void test_verifier_div_mod_bounds(void) { > > RUN(verifier_div_mod_bounds); } > > void test_verifier_div_overflow(void) { > > RUN(verifier_div_overflow); } > > +void test_verifier_flow_keys(void) { RUN(verifier_flow_keys); } > > void test_verifier_global_subprogs(void) { > > RUN(verifier_global_subprogs); } > > void test_verifier_global_ptr_args(void) { > > RUN(verifier_global_ptr_args); } > > void test_verifier_gotol(void) { RUN(verifier_gotol); } > > diff --git a/tools/testing/selftests/bpf/progs/verifier_flow_keys.c > > b/tools/testing/selftests/bpf/progs/verifier_flow_keys.c > > new file mode 100644 > > index 000000000000..512e5d1d2665 > > --- /dev/null > > +++ b/tools/testing/selftests/bpf/progs/verifier_flow_keys.c > > @@ -0,0 +1,77 @@ > > +// SPDX-License-Identifier: GPL-2.0 > > +/* Constant-offset bounds checks for PTR_TO_FLOW_KEYS pointer arithmetic. > > */ > > + > > +#include "vmlinux.h" > > +#include <bpf/bpf_helpers.h> > > +#include "bpf_misc.h" > > + > > +/* sizeof(struct bpf_flow_keys) is well under 4096, so +0x1000 is OOB. */ > > + > > +SEC("flow_dissector") > > +__description("flow_keys: in-bounds constant pointer arithmetic accepted") > > +__success > > +__naked void flow_keys_const_inbounds(void) > > +{ > > + asm volatile (" \ > > + r1 = *(u64 *)(r1 + %[flow_keys]); \ > > + r1 += 8; \ > > + r0 = *(u64 *)(r1 + 0); \ > > + r0 = 0; \ > > + exit; \ > > +" : > > + : __imm_const(flow_keys, offsetof(struct __sk_buff, flow_keys)) > > + : __clobber_all); > > +} > > + > > +SEC("flow_dissector") > > +__description("flow_keys: OOB via constant pointer arithmetic rejected") > > +__failure __msg("invalid access to flow keys off=4096 size=8") > > +__naked void flow_keys_const_oob_read(void) > > +{ > > + asm volatile (" \ > > + r1 = *(u64 *)(r1 + %[flow_keys]); \ > > + r1 += 4096; \ > > + r0 = *(u64 *)(r1 + 0); \ > > + r0 = 0; \ > > + exit; \ > > +" : > > + : __imm_const(flow_keys, offsetof(struct __sk_buff, flow_keys)) > > + : __clobber_all); > > +} > > + > > +SEC("flow_dissector") > > +__description("flow_keys: OOB write via constant pointer arithmetic > > rejected") > > +__failure __msg("invalid access to flow keys off=4096 size=8") > > +__naked void flow_keys_const_oob_write(void) > > +{ > > + asm volatile (" \ > > + r1 = *(u64 *)(r1 + %[flow_keys]); \ > > + r1 += 4096; \ > > + r2 = 0; \ > > + *(u64 *)(r1 + 0) = r2; \ > > + r0 = 0; \ > > + exit; \ > > +" : > > + : __imm_const(flow_keys, offsetof(struct __sk_buff, flow_keys)) > > + : __clobber_all); > > +} > > + > > +/* Equivalent OOB expressed directly in insn->off; this form was always > > + * rejected and is kept to show both forms now share one diagnostic. > > + */ > > +SEC("flow_dissector") > > +__description("flow_keys: OOB via insn->off rejected") > > +__failure __msg("invalid access to flow keys off=4096 size=8") > > +__naked void flow_keys_insn_off_oob(void) > > +{ > > + asm volatile (" \ > > + r1 = *(u64 *)(r1 + %[flow_keys]); \ > > + r0 = *(u64 *)(r1 + 4096); \ > > + r0 = 0; \ > > + exit; \ > > +" : > > + : __imm_const(flow_keys, offsetof(struct __sk_buff, flow_keys)) > > + : __clobber_all); > > +} > > + > > +char _license[] SEC("license") = "GPL"; > > Could you please also add a test with a truly varying offset? > Like below: > > __naked void flow_keys_var_read(void) > { > asm volatile (" \ > r6 = r1; \ > call %[bpf_get_prandom_u32]; \ > r0 &= 0xFFFF; \ > r1 = *(u64 *)(r6 + %[flow_keys]); \ > r1 += r0; \ > r0 = *(u64 *)(r1 + 0); \ > r0 = 0; \ > exit; \ > " : > : __imm_const(flow_keys, offsetof(struct __sk_buff, flow_keys)), > __imm(bpf_get_prandom_u32) > : __clobber_all); > }

