From: Ayushman Rout <ayushmanrout27@gmail.com>
To: bpf@vger.kernel.org
Cc: ast@kernel.org, Ayushman Rout <ayushmanrout27@gmail.com>,
Daniel Borkmann <daniel@iogearbox.net>,
Andrii Nakryiko <andrii@kernel.org>,
Eduard Zingerman <eddyz87@gmail.com>,
Kumar Kartikeya Dwivedi <memxor@gmail.com>,
Martin KaFai Lau <martin.lau@linux.dev>,
Song Liu <song@kernel.org>,
Yonghong Song <yonghong.song@linux.dev>,
Jiri Olsa <jolsa@kernel.org>,
Emil Tsalapatis <emil@etsalapatis.com>,
Ihor Solodrai <ihor.solodrai@linux.dev>,
John Fastabend <john.fastabend@gmail.com>,
Stanislav Fomichev <sdf@fomichev.me>,
"David S. Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@kernel.org>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
Simon Horman <horms@kernel.org>,
Jesper Dangaard Brouer <hawk@kernel.org>,
Daniel Rosenberg <drosen@google.com>,
netdev@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH bpf 1/3] bpf: Fix bpf_xdp_copy_buf() when the buffer overlaps the packet
Date: Sat, 24 Oct 2026 14:56:56 +0530 [thread overview]
Message-ID: <20261024092659.76422-2-ayushmanrout27@gmail.com> (raw)
In-Reply-To: <20261024092659.76422-1-ayushmanrout27@gmail.com>
bpf_xdp_copy_buf() moves data between a caller buffer and an xdp_buff
one segment at a time (the linear part, then each frag) with memcpy().
bpf_xdp_load_bytes(), bpf_xdp_store_bytes() and bpf_dynptr_slice() with
a buffer all use it.
The buffer does not have to be outside the packet. A program can pass a
slice of the same packet, for example one from bpf_dynptr_slice_rdwr().
Then a piece that is copied early can overwrite bytes that a later piece
still has to read. memcpy() is also not valid for overlapping memory.
Example: a 100 byte linear part, a 4096 byte frag0, a buffer at
frag0 + 10 and a 64 byte load from offset 90. The first piece copies
linear[90..100) to frag0[10..20), which destroys data that the second
piece needs from frag0[0..54). A store fails in the same way.
Commit ab08863c58b1 ("bpf: Use memmove() to store bytes in an
xdp_buff") fixed the case where the range is inside one segment. A
range that crosses from the linear part into a frag still goes through
here and is not covered.
Use memmove() for every piece. For a load, copy the piece that is in the
same segment as the buffer first. For a store, copy it last. This
assumes that the frags do not overlap each other.
The selftests added later in this series fail without this patch.
Fixes: 2012c867c800 ("bpf: verifier: Accept dynptr mem as mem in helpers")
Signed-off-by: Ayushman Rout <ayushmanrout27@gmail.com>
Assisted-by: LLM
---
net/core/filter.c | 59 ++++++++++++++++++++++++++++-------------------
1 file changed, 35 insertions(+), 24 deletions(-)
diff --git a/net/core/filter.c b/net/core/filter.c
index 09c60a58c82a..716efafe7e0a 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -4210,47 +4210,58 @@ static const struct bpf_func_proto bpf_xdp_adjust_head_proto = {
void bpf_xdp_copy_buf(struct xdp_buff *xdp, unsigned long off,
void *buf, unsigned long len, bool flush)
{
- unsigned long ptr_len, ptr_off = 0;
+ unsigned long ptr_len, ptr_off, o, l;
skb_frag_t *next_frag, *end_frag;
struct skb_shared_info *sinfo;
+ u8 *ptr_buf, *b, *orig = buf;
void *src, *dst;
- u8 *ptr_buf;
+ int pass;
if (likely(xdp->data_end - xdp->data >= off + len)) {
src = flush ? buf : xdp->data + off;
dst = flush ? xdp->data + off : buf;
- memcpy(dst, src, len);
+ memmove(dst, src, len);
return;
}
sinfo = xdp_get_shared_info_from_buff(xdp);
end_frag = &sinfo->frags[sinfo->nr_frags];
- next_frag = &sinfo->frags[0];
- ptr_len = xdp->data_end - xdp->data;
- ptr_buf = xdp->data;
+ for (pass = 0; pass < 2; pass++) {
+ o = off;
+ l = len;
+ b = buf;
+ ptr_off = 0;
+ ptr_len = xdp->data_end - xdp->data;
+ ptr_buf = xdp->data;
+ next_frag = &sinfo->frags[0];
+
+ while (true) {
+ if (o < ptr_off + ptr_len) {
+ unsigned long copy_off = o - ptr_off;
+ unsigned long copy_len = min(l, ptr_len - copy_off);
+ bool self = orig >= ptr_buf && orig < ptr_buf + ptr_len;
+ bool turn = pass == flush;
+
+ if (self == turn) {
+ src = flush ? b : ptr_buf + copy_off;
+ dst = flush ? ptr_buf + copy_off : b;
+ memmove(dst, src, copy_len);
+ }
- while (true) {
- if (off < ptr_off + ptr_len) {
- unsigned long copy_off = off - ptr_off;
- unsigned long copy_len = min(len, ptr_len - copy_off);
+ o += copy_len;
+ l -= copy_len;
+ b += copy_len;
+ }
- src = flush ? buf : ptr_buf + copy_off;
- dst = flush ? ptr_buf + copy_off : buf;
- memcpy(dst, src, copy_len);
+ if (!l || next_frag == end_frag)
+ break;
- off += copy_len;
- len -= copy_len;
- buf += copy_len;
+ ptr_off += ptr_len;
+ ptr_buf = skb_frag_address(next_frag);
+ ptr_len = skb_frag_size(next_frag);
+ next_frag++;
}
-
- if (!len || next_frag == end_frag)
- break;
-
- ptr_off += ptr_len;
- ptr_buf = skb_frag_address(next_frag);
- ptr_len = skb_frag_size(next_frag);
- next_frag++;
}
}
--
2.54.0
next parent reply other threads:[~2026-10-24 9:28 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <20261024092659.76422-1-ayushmanrout27@gmail.com>
2026-10-24 9:26 ` Ayushman Rout [this message]
2026-10-24 9:26 ` [PATCH bpf 2/3] bpf: Fix bpf_dynptr_copy() for overlapping ranges in one packet Ayushman Rout
2026-10-24 9:26 ` [PATCH bpf 3/3] selftests/bpf: Test overlapping dynptr copies on xdp frags Ayushman Rout
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261024092659.76422-2-ayushmanrout27@gmail.com \
--to=ayushmanrout27@gmail.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=davem@davemloft.net \
--cc=drosen@google.com \
--cc=eddyz87@gmail.com \
--cc=edumazet@kernel.org \
--cc=emil@etsalapatis.com \
--cc=hawk@kernel.org \
--cc=horms@kernel.org \
--cc=ihor.solodrai@linux.dev \
--cc=john.fastabend@gmail.com \
--cc=jolsa@kernel.org \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=martin.lau@linux.dev \
--cc=memxor@gmail.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=sdf@fomichev.me \
--cc=song@kernel.org \
--cc=yonghong.song@linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®