diff --git a/drivers/net/netdevsim/ethtool.c b/drivers/net/netdevsim/ethtool.c index 9350ba48eb81..a465f3220a7c 100644 --- a/drivers/net/netdevsim/ethtool.c +++ b/drivers/net/netdevsim/ethtool.c @@ -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); diff --git a/drivers/net/netdevsim/netdev.c b/drivers/net/netdevsim/netdev.c index 27e5f109f933..09d86a591fac 100644 --- a/drivers/net/netdevsim/netdev.c +++ b/drivers/net/netdevsim/netdev.c @@ -1165,6 +1165,7 @@ struct netdevsim *nsim_create(struct nsim_dev *nsim_dev, return ns; err_free_netdev: + debugfs_remove_recursive(ns->ethtool.ddir); free_netdev(dev); return ERR_PTR(err); } @@ -1214,6 +1215,14 @@ void nsim_destroy(struct netdevsim *ns) ns->page = NULL; } + /* + * Remove the ethtool debugfs directory before free_netdev() releases + * the netdevsim struct to prevent use-after-free in concurrent readers. + * Other per-port debugfs files are already removed above, and the port + * ddir itself is cleaned up by nsim_dev_port_debugfs_exit(). + */ + debugfs_remove_recursive(ns->ethtool.ddir); + free_netdev(dev); } diff --git a/drivers/net/netdevsim/netdevsim.h b/drivers/net/netdevsim/netdevsim.h index 4c9cc96dcec3..c08a01af31e9 100644 --- a/drivers/net/netdevsim/netdevsim.h +++ b/drivers/net/netdevsim/netdevsim.h @@ -95,6 +95,7 @@ struct nsim_ethtool { struct ethtool_coalesce coalesce; struct ethtool_ringparam ring; struct ethtool_fecparam fec; + struct dentry *ddir; }; struct nsim_rq {