From: "Emil Tsalapatis" <emil@etsalapatis.com>
To: "Jiayuan Chen" <jiayuan.chen@linux.dev>, <bpf@vger.kernel.org>,
<netdev@vger.kernel.org>
Cc: syzbot+237bbeed8dfe0699b7f5@syzkaller.appspotmail.com,
"Andrew Lunn" <andrew+netdev@lunn.ch>,
"David S. Miller" <davem@davemloft.net>,
"Eric Dumazet" <edumazet@google.com>,
"Jakub Kicinski" <kuba@kernel.org>,
"Paolo Abeni" <pabeni@redhat.com>,
"Alexei Starovoitov" <ast@kernel.org>,
"Daniel Borkmann" <daniel@iogearbox.net>,
"Jesper Dangaard Brouer" <hawk@kernel.org>,
"John Fastabend" <john.fastabend@gmail.com>,
"Stanislav Fomichev" <sdf@fomichev.me>,
"Simon Horman" <horms@kernel.org>,
"Martin KaFai Lau" <martin.lau@linux.dev>,
"Andrii Nakryiko" <andrii@kernel.org>,
"Eduard Zingerman" <eddyz87@gmail.com>,
"Kumar Kartikeya Dwivedi" <memxor@gmail.com>,
"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>,
"Shuah Khan" <shuah@kernel.org>,
"Kuniyuki Iwashima" <kuniyu@google.com>,
"Hangbin Liu" <liuhangbin@gmail.com>,
"Krishna Kumar" <krikku@gmail.com>,
"Martin Karsten" <mkarsten@uwaterloo.ca>,
"Toke Høiland-Jørgensen" <toke@redhat.com>,
"Lorenzo Bianconi" <lorenzo.bianconi@oss.qualcomm.com>,
linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org
Subject: Re: [PATCH bpf v2 1/2] bpf, veth: xdp: fix page_pool page leak on skb-backed XDP
Date: Fri, 04 Sep 2026 19:16:28 -0400 [thread overview]
Message-ID: <DL6WY5J4EPB0.3KT7XUU9US5CW@etsalapatis.com> (raw)
In-Reply-To: <20260824030705.266049-1-jiayuan.chen@linux.dev>
On Sun Aug 23, 2026 at 11:06 PM EDT, Jiayuan Chen wrote:
> bpf_xdp_shrink_data() frees a released frag via __xdp_return() using
> xdp->rxq->mem.type, but that type is wrong for skb-backed XDP: the skb is
> cow'd into page_pool memory while the rxq still says MEM_TYPE_PAGE_SHARED,
> so the page_pool page is freed with page_frag_free() and we hit
> "Bad page state ... page_pool leak".
>
> Both generic XDP and veth are affected. A non-linear skb is cow'd into
> page_pool memory (skb_cow_data_for_xdp() -> skb_pp_cow_data() for generic
> XDP, veth_convert_skb_to_xdp_buff() for veth), so its frags become
> page_pool pages while the rxq keeps MEM_TYPE_PAGE_SHARED.
>
> We can't just fix rxq->mem.type in place:
> - generic XDP: xdp->rxq is dev->_rx[queue].xdp_rxq (see
> bpf_prog_run_generic_xdp()), a shared rxq that other CPUs may access in
> parallel, so we must not write to it.
> - veth: rq->xdp_rxq.mem is shared per-queue state that veth resets on XDP
> teardown, and with GRO that reset runs without stopping in-flight NAPI,
> so a type stashed there can be clobbered under a packet still in flight.
>
> Adding a check in __xdp_return() or bpf_xdp_shrink_data() itself is not an
> option either: without recording it somewhere, both can only guess the
> frag's memory type, which quickly gets confusing.
>
> So record it in the xdp_buff. Add a XDP_FLAGS_FRAGS_PAGE_POOL flag; the two
> skb-cow sites set it, and bpf_xdp_shrink_data() frees the frag to the
> page_pool when it is set, otherwise it keeps falling back to
> xdp->rxq->mem.type unchanged. No other path changes behaviour.
>
> Fixes: e6d5dbdd20aa ("xdp: add multi-buff support for xdp running in generic mode")
> Fixes: 0ebab78cbcbf ("net: veth: add page_pool for page recycling")
> Reported-by: syzbot+237bbeed8dfe0699b7f5@syzkaller.appspotmail.com
> Closes: https://syzkaller.appspot.com/bug?extid=237bbeed8dfe0699b7f5
> Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
Hi Jiayuan,
> ---
> drivers/net/veth.c | 5 +++++
> include/net/xdp.h | 14 ++++++++++++++
> net/core/dev.c | 5 +++++
> net/core/filter.c | 7 +++++++
> 4 files changed, 31 insertions(+)
>
> diff --git a/drivers/net/veth.c b/drivers/net/veth.c
> index 6ed3ee81153f..0afa0661ada1 100644
> --- a/drivers/net/veth.c
> +++ b/drivers/net/veth.c
> @@ -775,6 +775,11 @@ static int veth_convert_skb_to_xdp_buff(struct veth_rq *rq,
> if (skb_shinfo(skb)->nr_frags) {
> skb_shinfo(skb)->xdp_frags_size = skb->data_len;
> xdp_buff_set_frags_flag(xdp);
> + /* A nonlinear skb was cow'd into rq->page_pool above, so the
> + * frags must be freed to that pool, not via the rxq's
> + * MEM_TYPE_PAGE_SHARED.
> + */
> + xdp_buff_set_frag_pp(xdp);
> } else {
> xdp_buff_clear_frags_flag(xdp);
> }
> diff --git a/include/net/xdp.h b/include/net/xdp.h
> index aa742f413c35..b389dc527adc 100644
> --- a/include/net/xdp.h
> +++ b/include/net/xdp.h
> @@ -81,6 +81,10 @@ enum xdp_buff_flags {
> * XDP program is not attached.
> */
> XDP_FLAGS_FRAGS_UNREADABLE = BIT(2),
> + /* frags are page_pool memory even though rxq->mem.type is not: a
> + * skb-backed XDP buff (generic XDP, veth) is cow'd into a page_pool.
> + */
> + XDP_FLAGS_FRAGS_PAGE_POOL = BIT(3),
> };
>
> struct xdp_buff {
> @@ -131,6 +135,16 @@ static __always_inline void xdp_buff_set_frag_unreadable(struct xdp_buff *xdp)
> xdp->flags |= XDP_FLAGS_FRAGS_UNREADABLE;
> }
>
> +static __always_inline void xdp_buff_set_frag_pp(struct xdp_buff *xdp)
> +{
> + xdp->flags |= XDP_FLAGS_FRAGS_PAGE_POOL;
> +}
For veth_xdp_rcv_skb() we also need to clear the flag in XDP_TX and XDP_REDIRECT.
The veth_xdp_get() call takes page refs but not page pool refs, while consume_skb()
drops the page pool reference. We should be clearing the new flag so that __xdp_return()
doesn't try to free it back to the page pool, otherwise we get a similar mismatch-related
splat to the original bug's.
pw-bot: cr
> +
> +static __always_inline bool xdp_buff_is_frag_pp(const struct xdp_buff *xdp)
> +{
> + return !!(xdp->flags & XDP_FLAGS_FRAGS_PAGE_POOL);
> +}
> +
> static __always_inline u32 xdp_buff_get_skb_flags(const struct xdp_buff *xdp)
> {
> return xdp->flags;
> diff --git a/net/core/dev.c b/net/core/dev.c
> index 38336858c168..be36020484b6 100644
> --- a/net/core/dev.c
> +++ b/net/core/dev.c
> @@ -5532,6 +5532,11 @@ u32 bpf_prog_run_generic_xdp(struct sk_buff *skb, struct xdp_buff *xdp,
> if (skb_is_nonlinear(skb)) {
> skb_shinfo(skb)->xdp_frags_size = skb->data_len;
> xdp_buff_set_frags_flag(xdp);
> + /* A nonlinear skb was cow'd into page_pool memory by
> + * skb_cow_data_for_xdp() before we got here, so the frags must
> + * be freed to that pool, not via the rxq's MEM_TYPE_PAGE_SHARED.
> + */
> + xdp_buff_set_frag_pp(xdp);
> } else {
> xdp_buff_clear_frags_flag(xdp);
> }
> diff --git a/net/core/filter.c b/net/core/filter.c
> index 61940e753552..d34ba56d79d8 100644
> --- a/net/core/filter.c
> +++ b/net/core/filter.c
> @@ -4378,6 +4378,13 @@ static bool bpf_xdp_shrink_data(struct xdp_buff *xdp, skb_frag_t *frag,
> if (mem_type == MEM_TYPE_XSK_BUFF_POOL) {
> netmem = 0;
> zc_frag = bpf_xdp_shrink_data_zc(xdp, shrink, tail, release);
> + } else if (xdp_buff_is_frag_pp(xdp)) {
> + /*
> + * Skb-backed XDP (generic XDP, veth) cow's the frags into a
> + * page_pool while the rxq stays MEM_TYPE_PAGE_SHARED, so free
> + * the frag to the pool, not via page_frag_free().
> + */
> + mem_type = MEM_TYPE_PAGE_POOL;
> }
>
> if (release) {
prev parent reply other threads:[~2026-09-04 23:16 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-24 3:02 [PATCH bpf v2 0/2] net: xdp: fix bpf_xdp_shrink_data() page handling on generic XDP and veth Jiayuan Chen
2026-08-24 3:06 ` [PATCH bpf v2 1/2] bpf, veth: xdp: fix page_pool page leak on skb-backed XDP Jiayuan Chen
2026-08-24 3:06 ` [PATCH bpf v2 2/2] selftests/bpf: add xdp_shrink_frags Jiayuan Chen
2026-08-24 3:58 ` bot+bpf-ci
2026-08-24 4:53 ` Jiayuan Chen
2026-08-27 19:19 ` Jakub Kicinski
2026-08-24 4:11 ` [PATCH bpf v2 1/2] bpf, veth: xdp: fix page_pool page leak on skb-backed XDP bot+bpf-ci
2026-08-24 10:31 ` Lorenzo Bianconi
2026-08-24 12:19 ` Jiayuan Chen
2026-08-24 14:50 ` Lorenzo Bianconi
2026-08-25 12:06 ` Jiayuan Chen
2026-08-27 19:19 ` Jakub Kicinski
2026-08-27 19:20 ` Jakub Kicinski
2026-09-04 23:16 ` Emil Tsalapatis [this message]
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=DL6WY5J4EPB0.3KT7XUU9US5CW@etsalapatis.com \
--to=emil@etsalapatis.com \
--cc=andrew+netdev@lunn.ch \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=davem@davemloft.net \
--cc=eddyz87@gmail.com \
--cc=edumazet@google.com \
--cc=hawk@kernel.org \
--cc=horms@kernel.org \
--cc=ihor.solodrai@linux.dev \
--cc=jiayuan.chen@linux.dev \
--cc=john.fastabend@gmail.com \
--cc=jolsa@kernel.org \
--cc=krikku@gmail.com \
--cc=kuba@kernel.org \
--cc=kuniyu@google.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=liuhangbin@gmail.com \
--cc=lorenzo.bianconi@oss.qualcomm.com \
--cc=martin.lau@linux.dev \
--cc=memxor@gmail.com \
--cc=mkarsten@uwaterloo.ca \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=sdf@fomichev.me \
--cc=shuah@kernel.org \
--cc=song@kernel.org \
--cc=syzbot+237bbeed8dfe0699b7f5@syzkaller.appspotmail.com \
--cc=toke@redhat.com \
--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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.