[PATCH bpf 2/3] bpf: Fix bpf_dynptr_copy() for overlapping ranges in one packet
From: Ayushman Rout
Date: Sat Oct 24 2026 - 05:42:14 EST
When neither dynptr can be sliced, which happens when both ranges cross
a segment boundary, bpf_dynptr_copy() copies through a 256 byte stack
buffer. It copies the chunks from the start to the end.
If both dynptrs point into the same packet, the ranges overlap and the
destination is above the source, a chunk written to the destination can
overwrite source bytes that a later chunk has not read yet.
Example: a 1200 byte copy with the destination 100 bytes above the
source. The first chunk writes source bytes 100..355, so the second
chunk reads bytes 256..355 after they were overwritten.
In that case, copy the chunks from the end to the start. This only
applies when src->data == dst->data and the destination is above the
source. All other copies stay as they are.
The selftests added later in this series fail without this patch.
Fixes: daec295a7094 ("bpf/helpers: Introduce bpf_dynptr_copy kfunc")
Signed-off-by: Ayushman Rout <ayushmanrout27@xxxxxxxxx>
Assisted-by: LLM
---
kernel/bpf/helpers.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
index 648abe1ba63a..8eb600cc9d12 100644
--- a/kernel/bpf/helpers.c
+++ b/kernel/bpf/helpers.c
@@ -3293,6 +3293,7 @@ __bpf_kfunc int bpf_dynptr_copy(const struct bpf_dynptr *dst_ptr, u64 dst_off,
const struct bpf_dynptr_kern *src = (struct bpf_dynptr_kern *)src_ptr;
void *src_slice, *dst_slice;
char buf[256];
+ bool rev;
u64 off;
src_slice = bpf_dynptr_slice(src_ptr, src_off, NULL, size);
@@ -3313,15 +3314,17 @@ __bpf_kfunc int bpf_dynptr_copy(const struct bpf_dynptr *dst_ptr, u64 dst_off,
bpf_dynptr_check_off_len(src, src_off, size))
return -E2BIG;
+ rev = src->data == dst->data && dst->offset + dst_off > src->offset + src_off;
off = 0;
while (off < size) {
u64 chunk_sz = min_t(u64, sizeof(buf), size - off);
+ u64 pos = rev ? size - off - chunk_sz : off;
int err;
- err = __bpf_dynptr_read(buf, chunk_sz, src, src_off + off, 0);
+ err = __bpf_dynptr_read(buf, chunk_sz, src, src_off + pos, 0);
if (err)
return err;
- err = __bpf_dynptr_write(dst, dst_off + off, buf, chunk_sz, 0);
+ err = __bpf_dynptr_write(dst, dst_off + pos, buf, chunk_sz, 0);
if (err)
return err;
--
2.54.0