From: Jiayuan Chen <jiayuan.chen@linux.dev>
To: bpf@vger.kernel.org, netdev@vger.kernel.org
Cc: Jiayuan Chen <jiayuan.chen@linux.dev>,
syzbot+237bbeed8dfe0699b7f5@syzkaller.appspotmail.com,
Daniel Borkmann <daniel@iogearbox.net>,
John Fastabend <john.fastabend@gmail.com>,
Stanislav Fomichev <sdf@fomichev.me>,
Martin KaFai Lau <martin.lau@linux.dev>,
Alexei Starovoitov <ast@kernel.org>,
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>,
"David S. Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
Simon Horman <horms@kernel.org>,
Jesper Dangaard Brouer <hawk@kernel.org>,
Toke Hoiland-Jorgensen <toke@redhat.com>,
Lorenzo Bianconi <lorenzo@kernel.org>,
linux-kernel@vger.kernel.org
Subject: [PATCH bpf] bpf: free page_pool frags via the page_pool path in bpf_xdp_shrink_data
Date: Sun, 16 Aug 2026 11:12:44 +0800 [thread overview]
Message-ID: <20260816031245.268898-1-jiayuan.chen@linux.dev> (raw)
syzbot reported a "Bad page state ... page_pool leak" when a generic XDP
program shrinks an skb into its frags on the tun write() path:
page_frag_free
__xdp_return
bpf_xdp_shrink_data
bpf_xdp_frags_shrink_tail
bpf_xdp_adjust_tail
When a program shrinks a whole frag, bpf_xdp_shrink_data() frees it via
__xdp_return() using xdp->rxq->mem.type. For skb-backed XDP the skb is
first rebuilt into page_pool memory (skb_cow_data_for_xdp() for generic
XDP, skb_pp_cow_data() for veth), so the frag is a page_pool page. But the
rxq was registered as MEM_TYPE_PAGE_SHARED, so __xdp_return() calls
page_frag_free() on a page_pool page: its base refcount drops to 0 and the
page is freed to the buddy allocator with pp_magic still set.
The rxq mem model cannot be relied on here because the rxq is shared and
does not describe the frag's real memory. The netdev generic rxq is used
both by generic XDP (page_pool frags) and by bpf_prog_test_run_xdp(), which
borrows the loopback rxq for plain alloc_page() frags; veth uses one rxq
for cow'd (page_pool) skbs and for redirected frames of any memory type. A
single rxq->mem.type can be wrong in either direction.
The memory type is really a property of the page. Check the frag itself
with netmem_is_pp() and return page_pool frags to their pool, keeping the
rxq mem type only for non page_pool pages. The page_pool is taken from the
page (netmem_get_pp()), so no rxq registration is involved.
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>
---
net/core/filter.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/net/core/filter.c b/net/core/filter.c
index 3423734124a5..4536bd147c25 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -89,6 +89,7 @@
#include <net/ip6_route.h>
#include "dev.h"
+#include "netmem_priv.h"
/* Keep the struct bpf_fib_lookup small so that it fits into a cacheline */
static_assert(sizeof(struct bpf_fib_lookup) == 64, "struct bpf_fib_lookup size check");
@@ -4293,6 +4294,14 @@ 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 (netmem_is_pp(netmem)) {
+ /* The rxq mem model does not always describe how a released
+ * frag must be freed: the generic-XDP and veth paths run the
+ * program on a shared rxq while the frag has been cow'd into
+ * page_pool memory. Trust the page itself and return a
+ * page_pool frag to its pool regardless of rxq->mem.type.
+ */
+ mem_type = MEM_TYPE_PAGE_POOL;
}
if (release) {
--
2.43.0
next reply other threads:[~2026-08-16 3:13 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-16 3:12 Jiayuan Chen [this message]
2026-08-16 3:37 ` [PATCH bpf] bpf: free page_pool frags via the page_pool path in bpf_xdp_shrink_data sashiko-bot
2026-08-16 5:10 ` Jiayuan Chen
2026-08-16 3:57 ` bot+bpf-ci
2026-08-16 5:16 ` Jiayuan Chen
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=20260816031245.268898-1-jiayuan.chen@linux.dev \
--to=jiayuan.chen@linux.dev \
--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=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=lorenzo@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=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.