From: Jason Xing <kernelxing@tencent.com> mainline inclusion from mainline-v7.1-rc3 commit 0f3776583d282550dbafe6082a914efcf9094d59 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/17327 CVE: CVE-2026-74559 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i... -------------------------------- When xsk_build_skb() processes multi-buffer packets in copy mode, the first descriptor stores data into the skb linear area without adding any frags, so nr_frags stays at 0. The caller then sets xs->skb = skb to accumulate subsequent descriptors. If a continuation descriptor fails (e.g. alloc_page returns NULL with -EAGAIN), we jump to free_err where the condition: if (skb && !skb_shinfo(skb)->nr_frags) kfree_skb(skb); evaluates to true because nr_frags is still 0 (the first descriptor used the linear area, not frags). This frees the skb while xs->skb still points to it, creating a dangling pointer. On the next transmit attempt or socket close, xs->skb is dereferenced, causing a use-after-free or double-free. Fix by using a !xs->skb check to handle first frag situation, ensuring we only free skbs that were freshly allocated in this call (xs->skb is NULL) and never free an in-progress multi-buffer skb that the caller still references. Closes: https://lore.kernel.org/all/20260415082654.21026-4-kerneljasonxing@gmail.com... Fixes: 6b9c129c2f93 ("xsk: remove @first_frag from xsk_build_skb()") Acked-by: Stanislav Fomichev <sdf@fomichev.me> Signed-off-by: Jason Xing <kernelxing@tencent.com> Reviewed-by: Alexander Lobakin <aleksander.lobakin@intel.com> Link: https://patch.msgid.link/20260502200722.53960-5-kerneljasonxing@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org> Conflicts: net/xdp/xsk.c [Free the skb at the free_err label uniformly to stay consistent with mainline, in preparation for the follow-up merge of 203cee647f55 ("xsk: fix u64 descriptor address truncation on 32-bit architectures"). Mainline made these changes across 0c0d0f42ffa6, 6b9c129c2f93, and 0f3776583d28, but as the metadata part has not been merged separately, fold it into this patch.] Signed-off-by: Zhang Changzhong <zhangchangzhong@huawei.com> --- net/xdp/xsk.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/net/xdp/xsk.c b/net/xdp/xsk.c index 9288215..ca25327 100644 --- a/net/xdp/xsk.c +++ b/net/xdp/xsk.c @@ -731,6 +731,7 @@ static struct sk_buff *xsk_build_skb(struct xdp_sock *xs, skb = xsk_build_skb_zerocopy(xs, desc); if (IS_ERR(skb)) { err = PTR_ERR(skb); + skb = NULL; goto free_err; } } else { @@ -751,10 +752,8 @@ static struct sk_buff *xsk_build_skb(struct xdp_sock *xs, skb_put(skb, len); err = skb_store_bits(skb, 0, buffer, len); - if (unlikely(err)) { - kfree_skb(skb); + if (unlikely(err)) goto free_err; - } } else { int nr_frags = skb_shinfo(skb)->nr_frags; struct xsk_addrs *xsk_addr; @@ -805,6 +804,9 @@ static struct sk_buff *xsk_build_skb(struct xdp_sock *xs, return skb; free_err: + if (skb && !xs->skb) + kfree_skb(skb); + if (err == -EOVERFLOW) { /* Drop the packet */ xsk_inc_num_desc(xs->skb); -- 2.9.5