]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
netdevsim: remove ethtool debugfs files before freeing netdev
authorYousef Alhouseen <alhouseenyousef@gmail.com>
Sun, 28 Jun 2026 00:28:04 +0000 (02:28 +0200)
committerJakub Kicinski <kuba@kernel.org>
Tue, 30 Jun 2026 01:47:23 +0000 (18:47 -0700)
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: ff1f7c17fb20 ("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>
drivers/net/netdevsim/ethtool.c
drivers/net/netdevsim/netdev.c
drivers/net/netdevsim/netdevsim.h

index 9350ba48eb815632d315c673c424cd7fe884dd58..025ea79879f3a93cb9a75c1a20464d81c4ca5cef 100644 (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);
+}
index 27e5f109f933d22e1b34cfc745b2d1f4c21524a6..4e9d7e10b527e5e4127331c141e4197afe0efa07 100644 (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,
index 4c9cc96dcec375fe11b5e2edfc8653b7ac0206aa..64f77f93d937cd643b3abb1cf11b1b9570c2c2d8 100644 (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,