bpf.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Björn Töpel" <bjorn@kernel.org>, bpf@vger.kernel.org
Subject: Re: [PATCH net-next v1 03/11] xdp: Copy buffers with restricted lifetime
Date: Wed, 11 Nov 2026 10:22:43 +0000	[thread overview]
Message-ID: <sashiko-outbox-208786@kernel.org> (raw)
In-Reply-To: <20261110102039.1002605-4-bjorn@kernel.org>

Thank you for your contribution! Sashiko AI review found 2 potential
issues to consider:
- [High] xdp: missing xdp_data_meta_unsupported() check in
  xdp_build_skb_from_zc()
- [High] xdp: skb_shared_info overwrite in xdp_build_skb_from_zc() via
  aligned memcpy
It also noticed 2 related pre-existing issues this patch does not
introduce:
- [Critical] bpf: double free and memory leak in xdp_do_redirect() [1]
- [Critical] xdp: double-free in xdp_return_buff() [2]
--

commit b80d3a81c03c102ec5d4e46044e260ec432b9137
Author: Björn Töpel <bjorn@kernel.org>

xdp: Copy buffers with restricted lifetime

This commit adds the MP_CAP_RETAIN memory provider capability and copies XDP
buffers from providers without MP_CAP_RETAIN when building an skb, converting
to an xdp_frame, or redirecting outside XSKMAP.

> diff --git a/net/core/filter.c b/net/core/filter.c
> index 80380f89adf90..f93839b493b25 100644
> --- a/net/core/filter.c
> +++ b/net/core/filter.c
> @@ -4774,12 +4774,28 @@ int xdp_do_redirect(struct net_device *dev, struct xdp_buff *xdp,
>  {
>  	struct bpf_redirect_info *ri = bpf_net_ctx_get_ri();
>  	enum bpf_map_type map_type = ri->map_type;
> +	struct xdp_frame *xdpf;
> +	int err;
>  
>  	if (map_type == BPF_MAP_TYPE_XSKMAP)
>  		return __xdp_do_redirect_xsk(ri, dev, xdp, xdp_prog);
>  
> -	return __xdp_do_redirect_frame(ri, dev, xdp_convert_buff_to_frame(xdp),
> -				       xdp_prog);
> +	if (likely(!xdp_buff_needs_copy(xdp)))
> +		return __xdp_do_redirect_frame(ri, dev,
> +					       xdp_convert_buff_to_frame(xdp),
> +					       xdp_prog);
> +
> +	/* Release the source only after the target took the copy. */
> +	xdpf = xdp_copy_buff_to_frame(xdp);
> +	err = __xdp_do_redirect_frame(ri, dev, xdpf, xdp_prog);

[Severity: Critical]
This problem wasn't introduced by this patch, but can redirecting a
MEM_TYPE_XSK_BUFF_POOL buffer still double free xdp and leak xdpf [1]
when __xdp_do_redirect_frame() fails?

For MEM_TYPE_XSK_BUFF_POOL buffers, xdp_buff_needs_copy(xdp) is false, so
xdp_do_redirect() takes the xdp_convert_buff_to_frame() ->
xdp_convert_zc_to_xdp_frame() path, which frees xdp via xsk_buff_free() before
__xdp_do_redirect_frame() runs.  If __xdp_do_redirect_frame() returns an
error, the allocated xdpf is leaked and the caller frees xdp a second time on
its error path.

> diff --git a/net/core/xdp.c b/net/core/xdp.c
> index 1d679e8fd6493..0cf46d492d91b 100644
> --- a/net/core/xdp.c
> +++ b/net/core/xdp.c
> @@ -559,10 +561,41 @@ void xdp_return_buff(struct xdp_buff *xdp)
>  			     xdp->rxq->mem.type, true, xdp);
>  
>  out:
> -	__xdp_return(virt_to_netmem(xdp->data), xdp->rxq->mem.type, true, xdp);
> +	__xdp_return(xdp_buff_head_netmem(xdp), xdp->rxq->mem.type, true, xdp);
>  }

[Severity: Critical]
This problem wasn't introduced by this patch, but does xdp_return_buff() call
xsk_buff_free(xdp) once per fragment [2] on multi-fragment
MEM_TYPE_XSK_BUFF_POOL buffers?

When xdp->rxq->mem.type is MEM_TYPE_XSK_BUFF_POOL, __xdp_return() ignores the
netmem argument and calls xsk_buff_free(xdp), which frees the head buffer and
all attached fragments at once.  Looping over sinfo->nr_frags before the final
__xdp_return() frees the same xdp_buff 1 + nr_frags times, corrupting the XSK
buffer pool.

[ ... ]

> @@ -638,6 +689,9 @@ struct sk_buff *xdp_build_skb_from_buff(const struct xdp_buff *xdp)
>  	u32 nr_frags = 0;
>  	int metalen;
>  
> +	if (unlikely(xdp_buff_needs_copy(xdp)))
> +		return xdp_build_skb_from_zc(xdp);

[Severity: High]
Does delegating to xdp_build_skb_from_zc() drop the first byte of the packet
when xdp_data_meta_unsupported(xdp) is true?

When a driver passes meta_valid == false to xdp_prepare_buff(), or calls
xdp_set_data_meta_invalid(), xdp->data_meta is set to xdp->data + 1.  Unlike
xdp_copy_buff_to_frame(), xdp_build_skb_from_zc() does not check
xdp_data_meta_unsupported(xdp):

net/core/xdp.c:xdp_build_skb_from_zc() {
	const struct xdp_rxq_info *rxq = xdp->rxq;
	u32 len = xdp->data_end - xdp->data_meta;
	...
	skb_reserve(skb, xdp->data_meta - xdp->data_hard_start);

	memcpy(__skb_put(skb, len), xdp->data_meta, LARGEST_ALIGN(len));

	metalen = xdp->data - xdp->data_meta;
	if (metalen > 0) {
		skb_metadata_set(skb, metalen);
		__skb_pull(skb, metalen);
	}
}

With xdp->data_meta == xdp->data + 1, this copies from xdp->data + 1, sets
skb->len one byte short, and skips __skb_pull() because metalen is -1,
corrupting the packet header on XDP_PASS.

[ ... ]

> @@ -781,7 +835,7 @@ struct sk_buff *xdp_build_skb_from_zc(struct xdp_buff *xdp)
>  		goto out;
>  	}
>  
> -	xsk_buff_free(xdp);
> +	xdp_release_copied(xdp);

[Severity: High]
Can the LARGEST_ALIGN(len) memcpy in xdp_build_skb_from_zc() overwrite
skb_shinfo(skb) when copying a buffer that reaches xdp_data_hard_end(xdp)?

In xdp_build_skb_from_zc(), napi_build_skb(data, truesize) initializes
skb_shinfo(skb) at data + truesize - SKB_DATA_ALIGN(sizeof(struct
skb_shared_info)), and then:

	skb_reserve(skb, xdp->data_meta - xdp->data_hard_start);

	memcpy(__skb_put(skb, len), xdp->data_meta, LARGEST_ALIGN(len));

When truesize equals xdp->frame_sz, skb->end is at the same offset from data
as xdp_data_hard_end(xdp) is from xdp->data_hard_start.  If an XDP program
adjusts xdp->data or xdp->data_meta to an offset that is not 16-byte aligned
and the head buffer is full up to xdp_data_hard_end(xdp), LARGEST_ALIGN(len)
extends up to 15 bytes past skb->end and overwrites skb_shinfo(skb) (including
nr_frags and frag_list) with bytes from xdp->data_end.

[1] https://sashiko.dev/#/bug/linux-c51b4a6d-8f07-471a-858e-04053743c6d2
[2] https://sashiko.dev/#/bug/linux-ad1513d6-3423-4560-95ce-a92871813ba4

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261110102039.1002605-1-bjorn@kernel.org?part=3

  parent reply	other threads:[~2026-11-11 10:22 UTC|newest]

Thread overview: 49+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-10 10:20 [PATCH net-next v1 00/11] xsk: Zero copy through page-pool memory providers Björn Töpel
2026-11-10 10:20 ` [PATCH net-next v1 01/11] net: Get skb fragment addresses through netmem Björn Töpel
2026-11-12  8:32   ` saeed bishara
2026-11-10 10:20 ` [PATCH net-next v1 02/11] net: Add memory provider capabilities Björn Töpel
2026-11-10 22:19   ` Stanislav Fomichev
2026-11-11 12:41     ` Björn Töpel
2026-11-11 23:01       ` Stanislav Fomichev
2026-11-11 10:22   ` sashiko-bot
2026-11-11 22:41   ` netdev-bot+sashiko
2026-11-10 10:20 ` [PATCH net-next v1 03/11] xdp: Copy buffers with restricted lifetime Björn Töpel
2026-11-10 22:32   ` Stanislav Fomichev
2026-11-11 13:27     ` Björn Töpel
2026-11-11 23:05       ` Stanislav Fomichev
2026-11-11 10:22   ` sashiko-bot [this message]
2026-11-11 22:41   ` netdev-bot+sashiko
2026-11-10 10:20 ` [PATCH net-next v1 04/11] xsk: Allocate UMEM chunks through page_pool Björn Töpel
2026-11-10 15:08   ` Magnus Karlsson
2026-11-11 13:51     ` Björn Töpel
2026-11-10 23:02   ` Stanislav Fomichev
2026-11-11 13:59     ` Björn Töpel
2026-11-11 23:09       ` Stanislav Fomichev
2026-11-11 22:41   ` netdev-bot+sashiko
2026-11-10 10:20 ` [PATCH net-next v1 05/11] xsk: Install UMEM page pool providers in the core Björn Töpel
2026-11-10 23:50   ` Stanislav Fomichev
2026-11-11 14:01     ` Björn Töpel
2026-11-11  8:59   ` Magnus Karlsson
2026-11-11 19:26     ` Björn Töpel
2026-11-12  8:08       ` Magnus Karlsson
2026-11-11 10:22   ` sashiko-bot
2026-11-11 22:41   ` netdev-bot+sashiko
2026-11-10 10:20 ` [PATCH net-next v1 06/11] page_pool: Coordinate refill with memory providers Björn Töpel
2026-11-10 23:51   ` Stanislav Fomichev
2026-11-11 19:37     ` Björn Töpel
2026-11-11 23:13       ` Stanislav Fomichev
2026-11-11 10:22   ` sashiko-bot
2026-11-11 22:41   ` netdev-bot+sashiko
2026-11-10 10:20 ` [PATCH net-next v1 07/11] xsk: Deliver provider chunks without copying Björn Töpel
2026-11-11 22:41   ` netdev-bot+sashiko
2026-11-11 23:20   ` Stanislav Fomichev
2026-11-10 10:20 ` [PATCH net-next v1 08/11] eth: fbnic: Support XDP redirect Björn Töpel
2026-11-11 10:22   ` sashiko-bot
2026-11-10 10:20 ` [PATCH net-next v1 09/11] eth: fbnic: Use netmem for RX headers and XDP_TX Björn Töpel
2026-11-10 10:20 ` [PATCH net-next v1 10/11] eth: fbnic: Support RX buffers it cannot split Björn Töpel
2026-11-11 10:22   ` sashiko-bot
2026-11-11 21:45   ` Dimitri Daskalakis
2026-11-11 22:41   ` netdev-bot+sashiko
2026-11-10 10:20 ` [PATCH net-next v1 11/11] eth: fbnic: Support AF_XDP page pool zero copy Björn Töpel
2026-11-11 10:22   ` sashiko-bot
2026-11-11 22:41   ` netdev-bot+sashiko

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=sashiko-outbox-208786@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=bjorn@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=sashiko-reviews@lists.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;
as well as URLs for NNTP newsgroup(s).