Thread (9 messages) 9 messages, 2 authors, 22d ago

Re: [BUG] KFENCE: use-after-free read in udp_tunnel_nic_device_sync_work

From: Eric Dumazet <edumazet@google.com>
Date: 2026-06-24 10:01:28
Also in: lkml
Subsystem: networking [general], the rest · Maintainers: "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds

On Wed, Jun 24, 2026 at 2:01 AM Yue Sun [off-list ref] wrote:
Hello,

I hit a reproducible use-after-free in the UDP tunnel NIC offload work item.
The original local crash was reported by KFENCE as:

  KFENCE: use-after-free read in udp_tunnel_nic_device_sync_work

On current mainline, the C reproducer below triggers the same lifetime bug,
reported by KASAN before KFENCE samples the object:

  BUG: KASAN: slab-use-after-free in __mutex_lock
  Workqueue: udp_tunnel_nic udp_tunnel_nic_device_sync_work

Tested kernel:

  840ef6c78e6a ("Merge tag 'nfs-for-7.2-1' of git://git.linux-nfs.org/projects/anna/linux-nfs")
  Linux 7.1.0-11240-g840ef6c78e6a #31 SMP PREEMPT_DYNAMIC

Thanks or the report.

Can you test the following patch?
diff --git a/net/ipv4/udp_tunnel_nic.c b/net/ipv4/udp_tunnel_nic.c
index 9944ed923ddfd10f9adf6ad788c0740daeaf2adb..c5f8d2f9d325de8f4d2247ddaa52e33378851857
100644
--- a/net/ipv4/udp_tunnel_nic.c
+++ b/net/ipv4/udp_tunnel_nic.c
@@ -304,8 +304,8 @@ udp_tunnel_nic_device_sync(struct net_device *dev,
struct udp_tunnel_nic *utn)
        if (!utn->need_sync)
                return;

-       queue_work(udp_tunnel_nic_workqueue, &utn->work);
        utn->work_pending = 1;
+       queue_work(udp_tunnel_nic_workqueue, &utn->work);
 }

 static bool
@@ -866,6 +866,11 @@ udp_tunnel_nic_unregister(struct net_device *dev,
struct udp_tunnel_nic *utn)

        udp_tunnel_nic_lock(dev);

+       if (utn->work_pending) {
+               udp_tunnel_nic_unlock(dev);
+               return;
+       }
+
        /* For a shared table remove this dev from the list of sharing devices
         * and if there are other devices just detach.
         */
@@ -901,12 +906,6 @@ udp_tunnel_nic_unregister(struct net_device *dev,
struct udp_tunnel_nic *utn)
        udp_tunnel_nic_flush(dev, utn);
        udp_tunnel_nic_unlock(dev);

-       /* Wait for the work to be done using the state, netdev core will
-        * retry unregister until we give up our reference on this device.
-        */
-       if (utn->work_pending)
-               return;
-
        udp_tunnel_nic_free(utn);
 release_dev:
        dev->udp_tunnel_nic = NULL;
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help