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: 4+ 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-25 15:14 ` Alexander Lobakin [this message]
2026-06-26 8:52 ` [PATCH v2] " Clement Lecigne
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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox