Thread (9 messages) flat view 9 messages, 3 authors, 2026-08-03

Re: [PATCH net v2] xsk: fix NULL pointer dereference in __xsk_rcv()

From: Jason Xing <hidden>
Date: 2026-07-25 09:14:11
Also in: bpf, lkml

On Sat, Jul 25, 2026 at 11:43 AM Cen Zhang (Microsoft)
[off-list ref] wrote:
In the __xsk_rcv() multi-buffer path, xsk_buff_alloc() is called in a
loop without checking its return value. xsk_buff_can_alloc() only
counts fill queue entries without validating their addresses, so it
can succeed while xsk_buff_alloc() rejects all remaining entries and
returns NULL.

  Oops: general protection fault, probably for non-canonical address
   0xdffffc0000000000
  KASAN: null-ptr-deref in range
   [0x0000000000000000-0x0000000000000007]
  RIP: 0010:__xsk_rcv+0x426/0xc20 (net/xdp/xsk.c:350)
  Call Trace:
   xsk_generic_rcv+0x26d/0x5f0
   xdp_do_generic_redirect+0x3c5/0xcf0
   do_xdp_generic+0x92f/0xe70
   __netif_receive_skb_core.constprop.0+0xf7e/0x2b30

Fix this with a two-stage transaction. First allocate and stage all
buffers required for the packet, recycling all staged buffers with
xsk_buff_free() if any allocation fails. Only after this stage
succeeds, copy the data, reserve the RX descriptors, and release the
buffers in an error-free loop.

Fixes: 804627751b42 ("xsk: add support for AF_XDP multi-buffer on Rx path")
Reported-by: AutonomousCodeSecurity@microsoft.com
Signed-off-by: Cen Zhang (Microsoft) <redacted>
You sent two patches within 24 hour, which obeys the basic rule of the
netdev community.

Please wait.

Thanks,
Jason

quoted hunk ↗ jump to hunk
---
v2:
 - Allocate all packet buffers before reserving RX descriptors.
 - Recycle partially allocated buffers instead of only cancelling the
  RX producer reservations.
Link: https://lore.kernel.org/netdev/20260724164719.99563-1-blbllhy@gmail.com (local)

 net/xdp/xsk.c | 29 ++++++++++++++++++++++++++---
 1 file changed, 26 insertions(+), 3 deletions(-)
diff --git a/net/xdp/xsk.c b/net/xdp/xsk.c
index f906d51b6699..383fc2b1de48 100644
--- a/net/xdp/xsk.c
+++ b/net/xdp/xsk.c
@@ -298,9 +298,11 @@ static int __xsk_rcv(struct xdp_sock *xs, struct xdp_buff *xdp, u32 len)
        u32 frame_size = __xsk_pool_get_rx_frame_size(xs->pool);
        void *copy_from = xsk_copy_xdp_start(xdp), *copy_to;
        u32 from_len, meta_len, rem, num_desc;
-       struct xdp_buff_xsk *xskb;
+       struct xdp_buff_xsk *xskb, *tmp;
        struct xdp_buff *xsk_xdp;
+       LIST_HEAD(xsk_buffs);
        skb_frag_t *frag;
+       u32 i;

        from_len = xdp->data_end - copy_from;
        meta_len = xdp->data - copy_from;
@@ -343,23 +345,44 @@ static int __xsk_rcv(struct xdp_sock *xs, struct xdp_buff *xdp, u32 len)
                frag =  &sinfo->frags[0];
        }

+       for (i = 0; i < num_desc; i++) {
+               xsk_xdp = xsk_buff_alloc(xs->pool);
+               if (!xsk_xdp)
+                       goto err_alloc;
+
+               xskb = container_of(xsk_xdp, struct xdp_buff_xsk, xdp);
+               if (unlikely(!list_empty(&xskb->list_node)))
+                       goto err_alloc;
+               list_add_tail(&xskb->list_node, &xsk_buffs);
+       }
+
        do {
                u32 to_len = frame_size + meta_len;
                u32 copied;

-               xsk_xdp = xsk_buff_alloc(xs->pool);
+               xskb = list_first_entry(&xsk_buffs, struct xdp_buff_xsk,
+                                       list_node);
+               list_del_init(&xskb->list_node);
+               xsk_xdp = &xskb->xdp;
                copy_to = xsk_xdp->data - meta_len;

                copied = xsk_copy_xdp(copy_to, &copy_from, to_len, &from_len, &frag, rem);
                rem -= copied;

-               xskb = container_of(xsk_xdp, struct xdp_buff_xsk, xdp);
                __xsk_rcv_zc_safe(xs, xskb, copied - meta_len,
                                  rem ? XDP_PKT_CONTD : 0);
                meta_len = 0;
        } while (rem);

        return 0;
+
+err_alloc:
+       list_for_each_entry_safe(xskb, tmp, &xsk_buffs, list_node) {
+               list_del_init(&xskb->list_node);
+               xsk_buff_free(&xskb->xdp);
+       }
+       xs->rx_dropped++;
+       return -ENOMEM;
 }

 static bool xsk_tx_writeable(struct xdp_sock *xs)
--
2.53.0
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help