Commit 0bb7a9ca authored by Jason Xing's avatar Jason Xing Committed by Jakub Kicinski
Browse files

xsk: free the skb when hitting the upper bound MAX_SKB_FRAGS



Fix it by explicitly adding kfree_skb() before returning back to its
caller.

How to reproduce it in virtio_net:
1. the current skb is the first one (which means xs->skb is NULL) and
   hit the limit MAX_SKB_FRAGS.
2. xsk_build_skb_zerocopy() returns -EOVERFLOW.
3. the caller xsk_build_skb() clears skb by using 'skb = NULL;'. This
   is why bug can be triggered.
4. there is no chance to free this skb anymore.

Note that if in this case the xs->skb is not NULL, xsk_build_skb() will
call xsk_drop_skb(xs->skb) to do the right thing.

Fixes: cf24f5a5 ("xsk: add support for AF_XDP multi-buffer on Tx path")
Acked-by: default avatarStanislav Fomichev <sdf@fomichev.me>
Signed-off-by: default avatarJason Xing <kernelxing@tencent.com>
Reviewed-by: default avatarAlexander Lobakin <aleksander.lobakin@intel.com>
Link: https://patch.msgid.link/20260502200722.53960-3-kerneljasonxing@gmail.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent d73a9a63
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -856,8 +856,11 @@ static struct sk_buff *xsk_build_skb_zerocopy(struct xdp_sock *xs,
	addr = buffer - pool->addrs;

	for (copied = 0, i = skb_shinfo(skb)->nr_frags; copied < len; i++) {
		if (unlikely(i >= MAX_SKB_FRAGS))
		if (unlikely(i >= MAX_SKB_FRAGS)) {
			if (!xs->skb)
				kfree_skb(skb);
			return ERR_PTR(-EOVERFLOW);
		}

		page = pool->umem->pgs[addr >> PAGE_SHIFT];
		get_page(page);