]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
xsk: prevent CQ desync when freeing half-built skbs in xsk_build_skb()
authorJason Xing <kernelxing@tencent.com>
Sat, 2 May 2026 20:07:19 +0000 (23:07 +0300)
committerJakub Kicinski <kuba@kernel.org>
Wed, 6 May 2026 02:27:50 +0000 (19:27 -0700)
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>
net/xdp/xsk.c

index 55378c3855d5d08d8f4b4b5195f820bd092d2c25..af3c5752bb63db9902dee5df29282d22733edfef 100644 (file)
@@ -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;