netdevsim: remove ethtool debugfs files before freeing netdev

The ethtool debugfs files point directly into struct netdevsim, which is
allocated as net_device private data. Their containing port directory is
removed only after nsim_destroy() calls free_netdev().

An open simple-attribute file can consequently dereference the freed
private data before the directory is removed. KASAN observed this in
debugfs_u32_get() during network namespace teardown.

Track and remove the ethtool subtree before free_netdev() on both the
normal and registration-failure paths. debugfs removal drains active
file users before returning.

Fixes: ff1f7c17fb ("netdevsim: add pause frame stats")
Reported-by: syzbot+6c25f4750230faf70be9@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=6c25f4750230faf70be9
Cc: <stable+noautosel@kernel.org> # netdevsim is a test harness, it's never loaded on production systems
Signed-off-by: Yousef Alhouseen <alhouseenyousef@gmail.com>
Link: https://patch.msgid.link/20260628002804.24214-1-alhouseenyousef@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Yousef Alhouseen 2026-06-28 02:28:04 +02:00 committed by Jakub Kicinski
parent 9facb861dc
commit 2e996ca81f
3 changed files with 10 additions and 0 deletions

View File

@ -252,6 +252,7 @@ void nsim_ethtool_init(struct netdevsim *ns)
ns->ethtool.channels = ns->nsim_bus_dev->num_queues;
ethtool = debugfs_create_dir("ethtool", ns->nsim_dev_port->ddir);
ns->ethtool_ddir = ethtool;
debugfs_create_u32("get_err", 0600, ethtool, &ns->ethtool.get_err);
debugfs_create_u32("set_err", 0600, ethtool, &ns->ethtool.set_err);
@ -272,3 +273,8 @@ void nsim_ethtool_init(struct netdevsim *ns)
debugfs_create_u32("tx_max_pending", 0600, dir,
&ns->ethtool.ring.tx_max_pending);
}
void nsim_ethtool_fini(struct netdevsim *ns)
{
debugfs_remove(ns->ethtool_ddir);
}

View File

@ -1165,6 +1165,7 @@ struct netdevsim *nsim_create(struct nsim_dev *nsim_dev,
return ns;
err_free_netdev:
nsim_ethtool_fini(ns);
free_netdev(dev);
return ERR_PTR(err);
}
@ -1178,6 +1179,7 @@ void nsim_destroy(struct netdevsim *ns)
debugfs_remove(ns->vlan_dfs);
debugfs_remove(ns->qr_dfs);
debugfs_remove(ns->pp_dfs);
nsim_ethtool_fini(ns);
if (ns->nb.notifier_call)
unregister_netdevice_notifier_dev_net(ns->netdev, &ns->nb,

View File

@ -154,6 +154,7 @@ struct netdevsim {
struct dentry *pp_dfs;
struct dentry *qr_dfs;
struct dentry *vlan_dfs;
struct dentry *ethtool_ddir;
struct nsim_ethtool ethtool;
struct netdevsim __rcu *peer;
@ -169,6 +170,7 @@ void nsim_destroy(struct netdevsim *ns);
bool netdev_is_nsim(struct net_device *dev);
void nsim_ethtool_init(struct netdevsim *ns);
void nsim_ethtool_fini(struct netdevsim *ns);
void nsim_udp_tunnels_debugfs_create(struct nsim_dev *nsim_dev);
int nsim_udp_tunnels_info_create(struct nsim_dev *nsim_dev,