[PATCH RFC] netdevsim: remove debugfs files before freeing net_device

0 views
Skip to first unread message

syzbot

unread,
Jun 23, 2026, 10:31:04 AM (2 days ago) Jun 23
to syzkaller-upst...@googlegroups.com, syz...@lists.linux.dev
A KASAN slab-use-after-free was detected in debugfs_u32_get() when reading
a debugfs file associated with a netdevsim port.

BUG: KASAN: slab-use-after-free in debugfs_u32_get+0x6c/0x70
Read of size 4 at addr ffff88810cd6db00

Call Trace:
debugfs_u32_get+0x6c/0x70
simple_attr_read+0x227/0x490
debugfs_attr_read+0x76/0x130
vfs_read+0x213/0xa80

The root cause is that the net_device (and its embedded netdevsim private
data) is freed before its associated debugfs files are removed. When a user
reads a debugfs file like rx_max_pending, debugfs_u32_get() dereferences a
pointer to the freed memory. This happens because nsim_destroy() calls
free_netdev() but does not remove the debugfs files created by
nsim_ethtool_init() or nsim_bpf_init(). These files are only removed later
when nsim_dev_port_debugfs_exit() is called. A similar issue exists in the
error path of nsim_create().

To fix this, swap the teardown order in __nsim_dev_port_del() and the
__nsim_dev_port_add() error path so that nsim_dev_port_debugfs_exit() is
called before nsim_destroy(). This ensures the debugfs directory is
recursively removed before the net_device is freed. Additionally, remove
explicit debugfs_remove() calls from various subsystem teardown functions
(like nsim_psp_uninit, nsim_ipsec_teardown, etc.) since the parent
directory is now removed earlier, which would otherwise lead to a
use-after-free of the dentry itself. Finally, ensure the debugfs directory
is removed before free_netdev() is called in the nsim_create() error path.

Fixes: e05b2d141fef ("netdevsim: move netdev creation/destruction to dev probe")
Assisted-by: Gemini:gemini-3.1-pro-preview Gemini:gemini-3-flash-preview syzbot
Reported-by: syzbot+6c25f4...@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=6c25f4750230faf70be9
Link: https://syzkaller.appspot.com/ai_job?id=84a7c962-d10e-424d-a37a-bf27d4830a40
To: "Andrew Lunn" <andrew...@lunn.ch>
To: "David S. Miller" <da...@davemloft.net>
To: "Eric Dumazet" <edum...@google.com>
To: "Jakub Kicinski" <ku...@kernel.org>
To: <net...@vger.kernel.org>
To: "Paolo Abeni" <pab...@redhat.com>
Cc: <linux-...@vger.kernel.org>

---
diff --git a/drivers/net/netdevsim/dev.c b/drivers/net/netdevsim/dev.c
index f00fc2f9e..beecc0c6e 100644
--- a/drivers/net/netdevsim/dev.c
+++ b/drivers/net/netdevsim/dev.c
@@ -1524,7 +1524,9 @@ static int __nsim_dev_port_add(struct nsim_dev *nsim_dev, enum nsim_dev_port_typ
return 0;

err_nsim_destroy:
+ nsim_dev_port_debugfs_exit(nsim_dev_port);
nsim_destroy(nsim_dev_port->ns);
+ goto err_port_resource_unregister;
err_port_debugfs_exit:
nsim_dev_port_debugfs_exit(nsim_dev_port);
err_port_resource_unregister:
@@ -1544,8 +1546,8 @@ static void __nsim_dev_port_del(struct nsim_dev_port *nsim_dev_port)
list_del(&nsim_dev_port->list);
if (nsim_dev_port_is_vf(nsim_dev_port))
devl_rate_leaf_destroy(&nsim_dev_port->devlink_port);
- nsim_destroy(nsim_dev_port->ns);
nsim_dev_port_debugfs_exit(nsim_dev_port);
+ nsim_destroy(nsim_dev_port->ns);
if (nsim_dev_port_is_pf(nsim_dev_port))
devl_port_resources_unregister(devlink_port);
devl_port_unregister(devlink_port);
diff --git a/drivers/net/netdevsim/ipsec.c b/drivers/net/netdevsim/ipsec.c
index 36a1be492..0bc9f42a5 100644
--- a/drivers/net/netdevsim/ipsec.c
+++ b/drivers/net/netdevsim/ipsec.c
@@ -292,5 +292,4 @@ void nsim_ipsec_teardown(struct netdevsim *ns)
if (ipsec->count)
netdev_err(ns->netdev, "tearing down IPsec offload with %d SAs left\n",
ipsec->count);
- debugfs_remove_recursive(ipsec->pfile);
}
diff --git a/drivers/net/netdevsim/netdev.c b/drivers/net/netdevsim/netdev.c
index a75076891..6918679ca 100644
--- a/drivers/net/netdevsim/netdev.c
+++ b/drivers/net/netdevsim/netdev.c
@@ -1164,6 +1164,8 @@ struct netdevsim *nsim_create(struct nsim_dev *nsim_dev,
return ns;

err_free_netdev:
+ debugfs_remove_recursive(nsim_dev_port->ddir);
+ nsim_dev_port->ddir = NULL;
free_netdev(dev);
return ERR_PTR(err);
}
@@ -1174,10 +1176,6 @@ void nsim_destroy(struct netdevsim *ns)
struct netdevsim *peer;
u16 vid;

- debugfs_remove(ns->vlan_dfs);
- debugfs_remove(ns->qr_dfs);
- debugfs_remove(ns->pp_dfs);
-
if (ns->nb.notifier_call)
unregister_netdevice_notifier_dev_net(ns->netdev, &ns->nb,
&ns->nn);
diff --git a/drivers/net/netdevsim/psp.c b/drivers/net/netdevsim/psp.c
index 6936ecb81..2f27a2114 100644
--- a/drivers/net/netdevsim/psp.c
+++ b/drivers/net/netdevsim/psp.c
@@ -227,7 +227,6 @@ static void __nsim_psp_uninit(struct netdevsim *ns, bool teardown)

void nsim_psp_uninit(struct netdevsim *ns)
{
- debugfs_remove(ns->psp.rereg);
mutex_destroy(&ns->psp.rereg_lock);
__nsim_psp_uninit(ns, true);
}
diff --git a/drivers/net/netdevsim/udp_tunnels.c b/drivers/net/netdevsim/udp_tunnels.c
index 89fff76e5..a69b15f12 100644
--- a/drivers/net/netdevsim/udp_tunnels.c
+++ b/drivers/net/netdevsim/udp_tunnels.c
@@ -188,9 +188,6 @@ int nsim_udp_tunnels_info_create(struct nsim_dev *nsim_dev,

void nsim_udp_tunnels_info_destroy(struct net_device *dev)
{
- struct netdevsim *ns = netdev_priv(dev);
-
- debugfs_remove_recursive(ns->udp_ports.ddir);
kfree(dev->udp_tunnel_nic_info);
dev->udp_tunnel_nic_info = NULL;
}


base-commit: 8cd9520d35a6c38db6567e97dd93b1f11f185dc6
--
This is an AI-generated patch subject to moderation.
Reply with '#syz upstream' to Sign-off the patch as a human author
and send it to the upstream kernel mailing lists.
Reply with '#syz reject' to reject it ('#syz unreject' to undo).

See https://goo.gle/syzbot-ai-patches for information about AI-generated patches.
You can comment on the patch as usual, syzbot will try to address
the comments and send a new version of the patch if necessary.
syzbot engineers can be reached at syzk...@googlegroups.com.

Aleksandr Nogikh

unread,
Jun 24, 2026, 5:56:40 AM (yesterday) Jun 24
to syzbot, syzkaller-upst...@googlegroups.com, syz...@lists.linux.dev
On Tue, Jun 23, 2026 at 4:31 PM 'syzbot' via
syzkaller-upstream-moderation
goto to goto looks very weird..
Maybe we can simplify it with an `if (nsim_dev_port->ns != NULL)`
check? Then `err_nsim_destroy` could be dropped.
Now that vlan_dfs, qr_dfs, pp_dfs are not used for debugfs_remove, do
we actually still need those fields?

syzbot

unread,
Jun 24, 2026, 9:04:47 AM (yesterday) Jun 24
to syzkaller-upst...@googlegroups.com, syz...@lists.linux.dev
Link: https://syzkaller.appspot.com/ai_job?id=f0f1a72a-a527-478e-a31c-7b83cdfee8d1
To: "Andrew Lunn" <andrew...@lunn.ch>
To: "David S. Miller" <da...@davemloft.net>
To: "Eric Dumazet" <edum...@google.com>
To: "Jakub Kicinski" <ku...@kernel.org>
To: <net...@vger.kernel.org>
To: "Paolo Abeni" <pab...@redhat.com>
Cc: <linux-...@vger.kernel.org>

---
v2:
- Removed unused dentry pointers (pp_dfs, qr_dfs, vlan_dfs) from struct netdevsim.
- Updated nsim_create() to create debugfs files without storing their dentries.
- Added IS_ERR_OR_NULL check for ns in __nsim_dev_port_add() error path.

v1:
https://lore.kernel.org/all/d0941a03-e111-4b0d...@mail.kernel.org/T/
---
diff --git a/drivers/net/netdevsim/dev.c b/drivers/net/netdevsim/dev.c
index f00fc2f9e..4c2c9aa1e 100644
--- a/drivers/net/netdevsim/dev.c
+++ b/drivers/net/netdevsim/dev.c
@@ -1516,17 +1516,17 @@ static int __nsim_dev_port_add(struct nsim_dev *nsim_dev, enum nsim_dev_port_typ
err = devl_rate_leaf_create(&nsim_dev_port->devlink_port,
nsim_dev_port, NULL);
if (err)
- goto err_nsim_destroy;
+ goto err_port_debugfs_exit;
}

list_add(&nsim_dev_port->list, &nsim_dev->port_list);

return 0;

-err_nsim_destroy:
- nsim_destroy(nsim_dev_port->ns);
err_port_debugfs_exit:
nsim_dev_port_debugfs_exit(nsim_dev_port);
+ if (!IS_ERR_OR_NULL(nsim_dev_port->ns))
+ nsim_destroy(nsim_dev_port->ns);
err_port_resource_unregister:
if (nsim_dev_port_is_pf(nsim_dev_port))
devl_port_resources_unregister(devlink_port);
@@ -1544,8 +1544,8 @@ static void __nsim_dev_port_del(struct nsim_dev_port *nsim_dev_port)
list_del(&nsim_dev_port->list);
if (nsim_dev_port_is_vf(nsim_dev_port))
devl_rate_leaf_destroy(&nsim_dev_port->devlink_port);
- nsim_destroy(nsim_dev_port->ns);
nsim_dev_port_debugfs_exit(nsim_dev_port);
+ nsim_destroy(nsim_dev_port->ns);
if (nsim_dev_port_is_pf(nsim_dev_port))
devl_port_resources_unregister(devlink_port);
devl_port_unregister(devlink_port);
diff --git a/drivers/net/netdevsim/ipsec.c b/drivers/net/netdevsim/ipsec.c
index 36a1be492..0bc9f42a5 100644
--- a/drivers/net/netdevsim/ipsec.c
+++ b/drivers/net/netdevsim/ipsec.c
@@ -292,5 +292,4 @@ void nsim_ipsec_teardown(struct netdevsim *ns)
if (ipsec->count)
netdev_err(ns->netdev, "tearing down IPsec offload with %d SAs left\n",
ipsec->count);
- debugfs_remove_recursive(ipsec->pfile);
}
diff --git a/drivers/net/netdevsim/netdev.c b/drivers/net/netdevsim/netdev.c
index a75076891..240107369 100644
--- a/drivers/net/netdevsim/netdev.c
+++ b/drivers/net/netdevsim/netdev.c
@@ -1154,16 +1154,17 @@ struct netdevsim *nsim_create(struct nsim_dev *nsim_dev,
if (err)
goto err_free_netdev;

- ns->pp_dfs = debugfs_create_file("pp_hold", 0600, nsim_dev_port->ddir,
- ns, &nsim_pp_hold_fops);
- ns->qr_dfs = debugfs_create_file("queue_reset", 0200,
- nsim_dev_port->ddir, ns,
- &nsim_qreset_fops);
- ns->vlan_dfs = debugfs_create_file("vlan", 0400, nsim_dev_port->ddir,
- ns, &nsim_vlan_fops);
+ debugfs_create_file("pp_hold", 0600, nsim_dev_port->ddir, ns,
+ &nsim_pp_hold_fops);
+ debugfs_create_file("queue_reset", 0200, nsim_dev_port->ddir, ns,
+ &nsim_qreset_fops);
+ debugfs_create_file("vlan", 0400, nsim_dev_port->ddir, ns,
+ &nsim_vlan_fops);
return ns;

err_free_netdev:
+ debugfs_remove_recursive(nsim_dev_port->ddir);
+ nsim_dev_port->ddir = NULL;
free_netdev(dev);
return ERR_PTR(err);
}
@@ -1174,10 +1175,6 @@ void nsim_destroy(struct netdevsim *ns)
struct netdevsim *peer;
u16 vid;

- debugfs_remove(ns->vlan_dfs);
- debugfs_remove(ns->qr_dfs);
- debugfs_remove(ns->pp_dfs);
-
if (ns->nb.notifier_call)
unregister_netdevice_notifier_dev_net(ns->netdev, &ns->nb,
&ns->nn);
diff --git a/drivers/net/netdevsim/netdevsim.h b/drivers/net/netdevsim/netdevsim.h
index d909c4160..29cbf004a 100644
--- a/drivers/net/netdevsim/netdevsim.h
+++ b/drivers/net/netdevsim/netdevsim.h
@@ -153,9 +153,6 @@ struct netdevsim {
} udp_ports;

struct page *page;
- struct dentry *pp_dfs;
- struct dentry *qr_dfs;
- struct dentry *vlan_dfs;

struct nsim_ethtool ethtool;
struct netdevsim __rcu *peer;
Reply all
Reply to author
Forward
0 new messages