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

Jason Xing <[email protected]>
Newsgroups org.kernel.vger.netdev,org.kernel.vger.bpf,org.kernel.vger.linux-kernel
Message-ID <CAL+tcoBCsSuN_+uypBoP5KdKUkto7X0T8A7qN2Vx6TqqGe-Ymw@mail.gmail.com>
On Fri, Aug 14, 2026 at 5:53 AM Cen Zhang (Microsoft) <[email protected]> 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: [email protected]
> Signed-off-by: Cen Zhang (Microsoft) <[email protected]>

Thanks for working on different approaches!

Reviewed-by: Jason Xing <[email protected]>

> ---

I think it'd be better to put the previous discussion links like [1]
here and then explain a bit about what you've changed through
iterations next time. It would be beneficial for network folks to
effortlessly trace your patches.

[1]: https://lore.kernel.org/all/[email protected]/

Thanks,
Jason

>  net/xdp/xsk.c | 30 +++++++++++++++++++++++++++---
>  1 file changed, 27 insertions(+), 3 deletions(-)
>
> diff --git a/net/xdp/xsk.c b/net/xdp/xsk.c
> index 7855ee09c4b6..33475b180ea6 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,45 @@ 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.52.0
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.