summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Xing <kernelxing@tencent.com>2026-05-02 23:07:19 +0300
committerJakub Kicinski <kuba@kernel.org>2026-05-06 05:27:50 +0300
commit3dec153ae484e3b2ddac841156e197ba54c8df94 (patch)
tree39f1736e97855cd758ea24f6fffd70b02505dbff
parent0f3776583d282550dbafe6082a914efcf9094d59 (diff)
downloadlinux-3dec153ae484e3b2ddac841156e197ba54c8df94.tar.xz
xsk: prevent CQ desync when freeing half-built skbs in xsk_build_skb()
Once xsk_skb_init_misc() has been called on an skb, its destructor is set to xsk_destruct_skb(), which submits the descriptor address(es) to the completion queue and advances the CQ producer. If such an skb is subsequently freed via kfree_skb() along an error path - before the skb has ever been handed to the driver - the destructor still runs and submits a bogus, half-initialized address to the CQ. Postpone the init phase when we believe the allocation of first frag is successfully completed. Before this init, skb can be safely freed by kfree_skb(). Closes: https://lore.kernel.org/all/20260419045822.843BFC2BCAF@smtp.kernel.org/ Fixes: c30d084960cf ("xsk: avoid overwriting skb fields for multi-buffer traffic") 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-6-kerneljasonxing@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
-rw-r--r--net/xdp/xsk.c5
1 files changed, 2 insertions, 3 deletions
diff --git a/net/xdp/xsk.c b/net/xdp/xsk.c
index 55378c3855d5..af3c5752bb63 100644
--- a/net/xdp/xsk.c
+++ b/net/xdp/xsk.c
@@ -819,8 +819,6 @@ static struct sk_buff *xsk_build_skb_zerocopy(struct xdp_sock *xs,
return ERR_PTR(err);
skb_reserve(skb, hr);
-
- xsk_skb_init_misc(skb, xs, desc->addr);
if (desc->options & XDP_TX_METADATA) {
err = xsk_skb_metadata(skb, buffer, desc, pool, hr);
if (unlikely(err))
@@ -917,7 +915,6 @@ static struct sk_buff *xsk_build_skb(struct xdp_sock *xs,
if (unlikely(err))
goto free_err;
- xsk_skb_init_misc(skb, xs, desc->addr);
if (desc->options & XDP_TX_METADATA) {
err = xsk_skb_metadata(skb, buffer, desc,
xs->pool, hr);
@@ -967,6 +964,8 @@ static struct sk_buff *xsk_build_skb(struct xdp_sock *xs,
}
}
+ if (!xs->skb)
+ xsk_skb_init_misc(skb, xs, desc->addr);
xsk_inc_num_desc(skb);
return skb;