Re: [PATCH net] net: devmem: fix TX binding UAF on netdevice unregister

From: Mina Almasry

Date: Fri Sep 11 2026 - 14:11:00 EST


On Thu, Sep 10, 2026 at 7:37 AM Felix Hoffmann <f3lix.dev@xxxxxx> wrote:
>
> RX dma-buf bindings are invalidated by their memory provider when a
> netdevice is unregistered. TX bindings have no bound RX queues and no
> equivalent uninstall callback, so their physical and virtual netdevice
> pointers remain live after the devices are freed.
>
> Closing the owning netlink socket after device removal then makes
> netdev_nl_sock_priv_destroy() dereference the freed physical netdevice to
> hold and lock it. KASAN reports a slab-use-after-free and the kernel can
> panic.
>
> The binding can also outlive the device used for its dma-buf attachment.
> Since dma_buf_attach() does not hold a reference to that device, deferred
> binding cleanup can pass a freed device to dma_buf_unmap_attachment().
>
> Invalidate TX bindings that refer to either the physical or virtual
> netdevice during unregister. Keep a reference on the exact DMA device
> until the attachment is unmapped. The netlink socket destructor then uses
> the existing device-gone path, while delayed dma-buf cleanup retains a
> valid DMA device.
>
> NETDEV_CMD_BIND_TX does not require GENL_ADMIN_PERM. The failure was
> reproduced with the binding owned by UID 65534 across module removal.
>
> Fixes: bd61848900bf ("net: devmem: Implement TX path")
> Cc: stable@xxxxxxxxxxxxxxx
> Assisted-by: Codex:gpt-5
> Signed-off-by: Felix Hoffmann <f3lix.dev@xxxxxx>
> ---
> The reproducer is available privately on request.
>
> Testing:
> - Full x86-64 kernel build with generic KASAN enabled
> - Unpatched kernel: UID 65534 bind, netdevice removal, and socket close
> produced the reported KASAN use-after-free and panic
> - Patched kernel: the identical sequence completed without a KASAN report
> - Patched kernel: 10 additional bind, removal, and close iterations passed
>
> net/core/dev.c | 2 ++
> net/core/devmem.c | 47 +++++++++++++++++++++++++++++++++++++++++++++--
> net/core/devmem.h | 7 +++++++
> 3 files changed, 54 insertions(+), 2 deletions(-)
>
> diff --git a/net/core/dev.c b/net/core/dev.c
> index ecfbd72d5d1a..c325fa7e0d6f 100644
> --- a/net/core/dev.c
> +++ b/net/core/dev.c
> @@ -12401,6 +12401,8 @@ static void dev_memory_provider_uninstall(struct net_device *dev)
>
> __netif_mp_uninstall_rxq(rxq, &rxq->mp_params);
> }
> +
> + net_devmem_uninstall_tx_bindings(dev);
> }
>
> /* devices must be UP and netdev_lock()'d */
> diff --git a/net/core/devmem.c b/net/core/devmem.c
> index f4d60654ce7f..a21a8fe92f58 100644
> --- a/net/core/devmem.c
> +++ b/net/core/devmem.c
> @@ -77,6 +77,7 @@ void __net_devmem_dmabuf_binding_free(struct work_struct *wq)
> dma_buf_unmap_attachment_unlocked(binding->attachment, binding->sgt,
> binding->direction);
> dma_buf_detach(binding->dmabuf, binding->attachment);
> + put_device(binding->dma_dev);
> dma_buf_put(binding->dmabuf);
> xa_destroy(&binding->bound_rxqs);
> percpu_ref_exit(&binding->ref);
> @@ -153,6 +154,46 @@ void net_devmem_unbind_dmabuf(struct net_devmem_dmabuf_binding *binding)
> percpu_ref_kill(&binding->ref);
> }
>
> +void net_devmem_uninstall_tx_bindings(struct net_device *dev)
> +{
> + struct net_devmem_dmabuf_binding *binding;
> + struct net_devmem_dmabuf_binding *found;
> + unsigned long xa_idx;
> +
> + /* Unlike RX bindings, TX bindings have no memory provider whose
> + * uninstall callback can invalidate their net_device pointers.
> + */

Please remove these LLM generated comments that make no sense. The
comment is correct but no one reading this code is wondering if the TX
binding have a memory provider.

> +again:
> + found = NULL;
> + rcu_read_lock();
> + xa_for_each(&net_devmem_dmabuf_bindings, xa_idx, binding) {
> + if (binding->direction != DMA_TO_DEVICE ||
> + (READ_ONCE(binding->dev) != dev &&
> + READ_ONCE(binding->vdev) != dev))
> + continue;
> +

Can you do a deeper investigation on what to do here or explain why
this is correct. I'm not sure we should do anything on the vdev
unregestiring? hmm...

FWIW I think probably an in-tree test would not go to net, but would
be a separate patch that goes to net-next? Maybe? IDK. Up to stan.

--
Thanks,
Mina