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

From: Eric Dumazet

Date: Wed Jun 24 2026 - 06:02:54 EST


On Wed, Jun 24, 2026 at 2:01 AM Yue Sun <samsun1006219@xxxxxxxxx> 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;