From 8f92b56d228d8fa4d372f7b410c1ced1e92eb664 Mon Sep 17 00:00:00 2001 From: Ayushman Rout Date: Mon, 26 Oct 2026 21:58:09 +0530 Subject: [PATCH] selftests/bpf: Test overlapping dynptr copies on xdp frags Add dynptr tests for copies within one xdp packet with frags, where the source and the destination overlap and the destination is above the source: - test_dynptr_copy_xdp_overlap: both ranges cross from the linear part into frag0. bpf_dynptr_copy() of 1200 bytes with the destination 100 bytes above the source. - test_dynptr_copy_xdp_overlap_src_linear: the source is in the linear part and the destination crosses into frag0. - test_dynptr_copy_xdp_overlap_dst_frag: the source crosses into frag0 and the destination is in frag0. The new tests set err when the data is wrong. The existing test_dynptr_copy_xdp does not, so it can pass on corrupted data. Without the fix to bpf_dynptr_copy(), test_dynptr_copy_xdp_overlap fails. With it, all the new tests pass. Signed-off-by: Ayushman Rout Signed-off-by: Alexei Starovoitov Link: https://patch.msgid.link/20261026162810.12862-3-ayushmanrout27@gmail.com --- .../testing/selftests/bpf/prog_tests/dynptr.c | 3 + .../selftests/bpf/progs/dynptr_success.c | 90 +++++++++++++++++++ 2 files changed, 93 insertions(+) diff --git a/tools/testing/selftests/bpf/prog_tests/dynptr.c b/tools/testing/selftests/bpf/prog_tests/dynptr.c index 4396560365e8..cbb2cc9969be 100644 --- a/tools/testing/selftests/bpf/prog_tests/dynptr.c +++ b/tools/testing/selftests/bpf/prog_tests/dynptr.c @@ -22,6 +22,9 @@ static struct { {"test_dynptr_data", SETUP_SYSCALL_SLEEP}, {"test_dynptr_copy", SETUP_SYSCALL_SLEEP}, {"test_dynptr_copy_xdp", SETUP_XDP_PROG}, + {"test_dynptr_copy_xdp_overlap", SETUP_XDP_PROG}, + {"test_dynptr_copy_xdp_overlap_src_linear", SETUP_XDP_PROG}, + {"test_dynptr_copy_xdp_overlap_dst_frag", SETUP_XDP_PROG}, {"test_dynptr_memset_zero", SETUP_SYSCALL_SLEEP}, {"test_dynptr_memset_notzero", SETUP_SYSCALL_SLEEP}, {"test_dynptr_memset_zero_offset", SETUP_SYSCALL_SLEEP}, diff --git a/tools/testing/selftests/bpf/progs/dynptr_success.c b/tools/testing/selftests/bpf/progs/dynptr_success.c index b668ebd61fc7..56be4eafc270 100644 --- a/tools/testing/selftests/bpf/progs/dynptr_success.c +++ b/tools/testing/selftests/bpf/progs/dynptr_success.c @@ -759,6 +759,96 @@ int test_dynptr_copy_xdp(struct xdp_md *xdp) return XDP_DROP; } +static __always_inline int fill_xdp(struct bpf_dynptr *ptr, __u32 start, __u32 n) +{ + __u8 b; + int i; + + bpf_for(i, 0, n) { + b = (start + i) % 251; + if (bpf_dynptr_write(ptr, start + i, &b, 1, 0)) + return 1; + } + return 0; +} + +static __always_inline int check_xdp(struct bpf_dynptr *ptr, __u32 at, __u32 n, __u32 from) +{ + __u8 b; + int i; + + bpf_for(i, 0, n) { + if (bpf_dynptr_read(&b, 1, ptr, at + i, 0)) + return 1; + if (b != (__u8)((from + i) % 251)) + return 1; + } + return 0; +} + +SEC("?xdp") +int test_dynptr_copy_xdp_overlap(struct xdp_md *xdp) +{ + void *data_end = (void *)(long)xdp->data_end; + void *data = (void *)(long)xdp->data; + __u32 off = data_end - data - 1000; + struct bpf_dynptr ptr; + + bpf_dynptr_from_xdp(xdp, 0, &ptr); + if (fill_xdp(&ptr, off, 1300)) { + err = 1; + return XDP_DROP; + } + err = bpf_dynptr_copy(&ptr, off + 100, &ptr, off, 1200); + if (err) + return XDP_DROP; + if (check_xdp(&ptr, off + 100, 1200, off)) + err = 2; + return XDP_DROP; +} + +SEC("?xdp") +int test_dynptr_copy_xdp_overlap_src_linear(struct xdp_md *xdp) +{ + void *data_end = (void *)(long)xdp->data_end; + void *data = (void *)(long)xdp->data; + __u32 lin = data_end - data; + struct bpf_dynptr ptr; + + bpf_dynptr_from_xdp(xdp, 0, &ptr); + if (fill_xdp(&ptr, lin - 64, 118)) { + err = 1; + return XDP_DROP; + } + err = bpf_dynptr_copy(&ptr, lin - 10, &ptr, lin - 64, 64); + if (err) + return XDP_DROP; + if (check_xdp(&ptr, lin - 10, 64, lin - 64)) + err = 2; + return XDP_DROP; +} + +SEC("?xdp") +int test_dynptr_copy_xdp_overlap_dst_frag(struct xdp_md *xdp) +{ + void *data_end = (void *)(long)xdp->data_end; + void *data = (void *)(long)xdp->data; + __u32 lin = data_end - data; + struct bpf_dynptr ptr; + + bpf_dynptr_from_xdp(xdp, 0, &ptr); + if (fill_xdp(&ptr, lin - 10, 84)) { + err = 1; + return XDP_DROP; + } + err = bpf_dynptr_copy(&ptr, lin + 10, &ptr, lin - 10, 64); + if (err) + return XDP_DROP; + if (check_xdp(&ptr, lin + 10, 64, lin - 10)) + err = 2; + return XDP_DROP; +} + char memset_zero_data[] = "data to be zeroed"; SEC("?tp/syscalls/sys_enter_nanosleep")