selftests/bpf: Test packet pointer class displacement pruning

Add two paths whose packet pointer ranges are individually compatible at
a join but whose members have different relative displacements. The first
path proves an eight-byte access through one member. On the second path,
the same guard only proves that the access starts before data_end.

An affected verifier prunes the second path and accepts the program. With
packet pointer class displacement preserved, it explores that path and
rejects the out-of-bounds access.

Read the unknown offset and branch selector directly from XDP context
fields, and force state checkpoints so the pruning attempt does not
depend on the verifier checkpoint heuristics.

Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Link: https://patch.msgid.link/20260917233222.2542500-4-memxor@gmail.com
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
This commit is contained in:
Kumar Kartikeya Dwivedi 2026-09-18 01:32:11 +02:00 committed by Eduard Zingerman
parent fd16449a9b
commit 2059d9af54

View File

@ -1719,4 +1719,39 @@ l0_%=: r0 = 0; \
: __clobber_all);
}
SEC("xdp")
__description("XDP pkt regsafe preserves packet pointer class displacement")
__failure __msg("R2 min value is outside of the allowed memory range")
__flag(BPF_F_ANY_ALIGNMENT) __flag(BPF_F_TEST_STATE_FREQ)
__naked void pkt_regsafe_class_displacement(void)
{
asm volatile (" \
r8 = *(u32 *)(r1 + %[xdp_md_data_end]); \
r9 = *(u32 *)(r1 + %[xdp_md_data]); \
r4 = *(u32 *)(r1 + %[xdp_md_rx_queue_index]); \
r4 &= 15; \
r0 = *(u32 *)(r1 + %[xdp_md_ingress_ifindex]); \
if r0 != 0 goto l0_%=; \
r2 = r9; \
r2 += r4; \
r3 = r2; \
r3 += 8; \
goto l1_%=; \
l0_%=: r4 &= 3; \
r4 += 8; \
r2 = r9; \
r2 += r4; \
r3 = r2; \
l1_%=: if r3 > r8 goto l2_%=; \
r0 = *(u64 *)(r2 + 0); \
l2_%=: r0 = 0; \
exit; \
" :
: __imm_const(xdp_md_data, offsetof(struct xdp_md, data)),
__imm_const(xdp_md_data_end, offsetof(struct xdp_md, data_end)),
__imm_const(xdp_md_rx_queue_index, offsetof(struct xdp_md, rx_queue_index)),
__imm_const(xdp_md_ingress_ifindex, offsetof(struct xdp_md, ingress_ifindex))
: __clobber_all);
}
char _license[] SEC("license") = "GPL";