From: Alexander Lobakin <aleksander.lobakin@intel.com>
To: Clement Lecigne <clecigne@google.com>
Cc: <edumazet@google.com>, <netdev@vger.kernel.org>,
<bpf@vger.kernel.org>, <linux-kernel@vger.kernel.org>,
<kuba@kernel.org>, <sdf@fomichev.me>, <horms@kernel.org>,
<john.fastabend@gmail.com>, <ast@kernel.org>,
<daniel@iogearbox.net>
Subject: Re: [PATCH] xsk: fix memory corruptions in net/core/xdp.c
Date: Thu, 25 Jun 2026 17:14:06 +0200 [thread overview]
Message-ID: <0922ce5d-48d8-44e7-983c-e547f3126ef4@intel.com> (raw)
In-Reply-To: <20260624084130.2382335-1-clecigne@google.com>
From: Clement Lecigne <clecigne@google.com>
Date: Wed, 24 Jun 2026 08:41:28 +0000
> From: Clément Lecigne <clecigne@google.com>
>
> Commit 560d958c6c68 ("xsk: add generic XSk &xdp_buff -> skb conversion")
> introduced a vulnerability in the handling of XDP_PASS for AF_XDP zero-copy
> frames.
>
> Note: Currently, this specific AF_XDP zero-copy conversion path is only
> reachable from the drivers/net/ethernet/intel/ice driver.
idpf uses this, too (every driver based on libeth_xdp in general,
currently these two).
>
> When building an skb, xdp_build_skb_from_zc() uses the chunk size
> (xdp->frame_sz) for the allocation. However, napi_build_skb() automatically
> reserves space at the end of the allocation for the skb_shared_info
> structure.
>
> Most high performance UMEM applications use 4K chunks, where the
> corruption cannot happen. However, if the UMEM is configured with 2KB
> chunks (a very common configuration to maximize packet density in memory),
> a standard 1500 MTU packet will trigger the corruption because the required
> space exceeds the 2048 byte chunk size:
>
> Headroom (256) + Packet (1514) + skb_shared_info (320) = 2090 bytes
>
> Because 2090 bytes > 2048 bytes and __skb_put() does not perform bounds
> checking, the memcpy() writes past the available linear data area and
> corrupts the skb_shared_info structure. This can lead to arbitrary code
> execution if pointers like destructor_arg are overwritten.
>
> Additionally, in xdp_copy_frags_from_zc(), the allocation size is set
> strictly to the fragment size (len), but the subsequent memcpy() uses
> LARGEST_ALIGN(len). This mismatch results in an out-of-bounds write of
> up to 7 bytes, which triggers KASAN warnings and is unsafe despite typical
> page pool allocator padding.
>
> Fix the skb allocation in xdp_build_skb_from_zc() by dynamically
> calculating the exact truesize required: the sum of the headroom, the
> packet length, and the skb_shared_info overhead, properly aligned via
> SKB_DATA_ALIGN.
>
> Fix the out-of-bounds write in xdp_copy_frags_from_zc() by rounding up
> the allocation request using LARGEST_ALIGN(len) to match the copy
> operation.
>
> Fixes: 560d958c6c68 ("xsk: add generic XSk &xdp_buff -> skb conversion")
> CC: Alexander Lobakin <aleksander.lobakin@intel.com>
> CC: Eric Dumazet <edumazet@google.com>
> Signed-off-by: Clément Lecigne <clecigne@google.com>
> ---
> diff --git a/net/core/xdp.c b/net/core/xdp.c
> index 9890a30584ba..f36d1fb875ab 100644
> --- a/net/core/xdp.c
> +++ b/net/core/xdp.c
> @@ -699,7 +699,7 @@ static noinline bool xdp_copy_frags_from_zc(struct sk_buff *skb,
> for (u32 i = 0; i < nr_frags; i++) {
> const skb_frag_t *frag = &xinfo->frags[i];
> u32 len = skb_frag_size(frag);
> - u32 offset, truesize = len;
> + u32 offset, truesize = LARGEST_ALIGN(len);
I think you need to re-sort this to keep RCT, now that the truesize
initialization is way longer than it was.
const skb_frag_t *frag = &xinfo->frags[i];
u32 offset, len = skb_frag_size(frag);
u32 truesize = LARGEST_ALIGN(len);
struct page *page;
> struct page *page;
>
> page = page_pool_dev_alloc(pp, &offset, &truesize);
BTW usually LARGEST_ALIGN() aligns to 16, I've never seen a bigger one.
IIRC Page Pool never returns a truesize aligned to a smaller value. But
if you're really able to trigger this, it probably does?
> @@ -740,7 +740,9 @@ struct sk_buff *xdp_build_skb_from_zc(struct xdp_buff *xdp)
> {
> const struct xdp_rxq_info *rxq = xdp->rxq;
> u32 len = xdp->data_end - xdp->data_meta;
> - u32 truesize = xdp->frame_sz;
> + u32 headroom = xdp->data_meta - xdp->data_hard_start;
> + u32 truesize = SKB_DATA_ALIGN(headroom + len) +
> + SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
Ah now I get it: xdp->frame_sz doesn't account the shinfo for
single-buffer frames, only for multi-buffer ones. The fix looks correct,
but I'd use SKB_HEAD_ALIGN() since it does exactly what you're
open-coding here and sort the declarations:
{
u32 hr = xdp->data_meta - xdp->data_hard_start;
const struct xdp_rxq_info *rxq = xdp->rxq;
u32 len = xdp->data_end - xdp->data_meta;
u32 truesize = SKB_HEAD_ALIGN(hr + len);
struct sk_buff *skb = NULL;
struct page_pool *pp;
int metalen;
void *data;
if (!IS_ENABLED(CONFIG_PAGE_POOL))
return NULL;
...
> struct sk_buff *skb = NULL;
> struct page_pool *pp;
> int metalen;
> @@ -762,7 +764,7 @@ struct sk_buff *xdp_build_skb_from_zc(struct xdp_buff *xdp)
> }
>
> skb_mark_for_recycle(skb);
> - skb_reserve(skb, xdp->data_meta - xdp->data_hard_start);
> + skb_reserve(skb, headroom);
>
> memcpy(__skb_put(skb, len), xdp->data_meta, LARGEST_ALIGN(len));
Thanks,
Olek
next prev parent reply other threads:[~2026-06-25 15:14 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-24 8:41 [PATCH] xsk: fix memory corruptions in net/core/xdp.c Clement Lecigne
2026-06-24 8:53 ` sashiko-bot
2026-06-25 15:14 ` Alexander Lobakin [this message]
2026-06-26 8:52 ` [PATCH v2] " Clement Lecigne
2026-06-26 9:08 ` sashiko-bot
2026-06-26 9:12 ` [PATCH] " Clement Lecigne
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=0922ce5d-48d8-44e7-983c-e547f3126ef4@intel.com \
--to=aleksander.lobakin@intel.com \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=clecigne@google.com \
--cc=daniel@iogearbox.net \
--cc=edumazet@google.com \
--cc=horms@kernel.org \
--cc=john.fastabend@gmail.com \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=sdf@fomichev.me \
/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.