Skip to content

Commit 9d0a67b

Browse files
tirthendu-intelborkmann
authored andcommitted
xsk: Fix xsk_build_skb() error: 'skb' dereferencing possible ERR_PTR()
Currently, xsk_build_skb() is a function that builds skb in two possible ways and then is ended with common error handling. We can distinguish four possible error paths and handling in xsk_build_skb(): 1. sock_alloc_send_skb fails: Retry (skb is NULL). 2. skb_store_bits fails : Free skb and retry. 3. MAX_SKB_FRAGS exceeded: Free skb, cleanup and drop packet. 4. alloc_page fails for frag: Retry page allocation w/o freeing skb 1] and 3] can happen in xsk_build_skb_zerocopy(), which is one of the two code paths responsible for building skb. Common error path in xsk_build_skb() assumes that in case errno != -EAGAIN, skb is a valid pointer, which is wrong as kernel test robot reports that in xsk_build_skb_zerocopy() other errno values are returned for skb being NULL. To fix this, set -EOVERFLOW as error when MAX_SKB_FRAGS are exceeded and packet needs to be dropped in both xsk_build_skb() and xsk_build_skb_zerocopy() and use this to distinguish against all other error cases. Also, add explicit kfree_skb() for 3] so that handling of 1], 2], and 3] becomes identical where allocation needs to be retried. Fixes: cf24f5a ("xsk: add support for AF_XDP multi-buffer on Tx path") Reported-by: kernel test robot <[email protected]> Reported-by: Dan Carpenter <[email protected]> Signed-off-by: Tirthendu Sarkar <[email protected]> Signed-off-by: Daniel Borkmann <[email protected]> Acked-by: Magnus Karlsson <[email protected]> Closes: https://lore.kernel.org/r/[email protected] Link: https://lore.kernel.org/bpf/[email protected]
1 parent 6a8faf1 commit 9d0a67b

File tree

1 file changed

+13
-9
lines changed

1 file changed

+13
-9
lines changed

net/xdp/xsk.c

+13-9
Original file line numberDiff line numberDiff line change
@@ -602,7 +602,7 @@ static struct sk_buff *xsk_build_skb_zerocopy(struct xdp_sock *xs,
602602

603603
for (copied = 0, i = skb_shinfo(skb)->nr_frags; copied < len; i++) {
604604
if (unlikely(i >= MAX_SKB_FRAGS))
605-
return ERR_PTR(-EFAULT);
605+
return ERR_PTR(-EOVERFLOW);
606606

607607
page = pool->umem->pgs[addr >> PAGE_SHIFT];
608608
get_page(page);
@@ -655,15 +655,17 @@ static struct sk_buff *xsk_build_skb(struct xdp_sock *xs,
655655
skb_put(skb, len);
656656

657657
err = skb_store_bits(skb, 0, buffer, len);
658-
if (unlikely(err))
658+
if (unlikely(err)) {
659+
kfree_skb(skb);
659660
goto free_err;
661+
}
660662
} else {
661663
int nr_frags = skb_shinfo(skb)->nr_frags;
662664
struct page *page;
663665
u8 *vaddr;
664666

665667
if (unlikely(nr_frags == (MAX_SKB_FRAGS - 1) && xp_mb_desc(desc))) {
666-
err = -EFAULT;
668+
err = -EOVERFLOW;
667669
goto free_err;
668670
}
669671

@@ -690,12 +692,14 @@ static struct sk_buff *xsk_build_skb(struct xdp_sock *xs,
690692
return skb;
691693

692694
free_err:
693-
if (err == -EAGAIN) {
694-
xsk_cq_cancel_locked(xs, 1);
695-
} else {
696-
xsk_set_destructor_arg(skb);
697-
xsk_drop_skb(skb);
695+
if (err == -EOVERFLOW) {
696+
/* Drop the packet */
697+
xsk_set_destructor_arg(xs->skb);
698+
xsk_drop_skb(xs->skb);
698699
xskq_cons_release(xs->tx);
700+
} else {
701+
/* Let application retry */
702+
xsk_cq_cancel_locked(xs, 1);
699703
}
700704

701705
return ERR_PTR(err);
@@ -738,7 +742,7 @@ static int __xsk_generic_xmit(struct sock *sk)
738742
skb = xsk_build_skb(xs, &desc);
739743
if (IS_ERR(skb)) {
740744
err = PTR_ERR(skb);
741-
if (err == -EAGAIN)
745+
if (err != -EOVERFLOW)
742746
goto out;
743747
err = 0;
744748
continue;

0 commit comments

Comments
 (0)