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

Aleksandr Nogikh <[email protected]>
Newsgroups dev.linux.lists.syzbot
Message-ID <CANp29Y6gq+X76VDzG9vePaX4+R1i=aFCRR6JLK6F3LTvP0L9EQ@mail.gmail.com>
#syz upstream

On Wed, Jun 24, 2026 at 3:04 PM 'syzbot' via
syzkaller-upstream-moderation
<[email protected]> wrote:
>
> 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: [email protected]
> Closes: https://syzkaller.appspot.com/bug?extid=6c25f4750230faf70be9
> Link: https://syzkaller.appspot.com/ai_job?id=f0f1a72a-a527-478e-a31c-7b83cdfee8d1
> To: "Andrew Lunn" <[email protected]>
> To: "David S. Miller" <[email protected]>
> To: "Eric Dumazet" <[email protected]>
> To: "Jakub Kicinski" <[email protected]>
> To: <[email protected]>
> To: "Paolo Abeni" <[email protected]>
> Cc: <[email protected]>
>
> ---
> 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/[email protected]/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;
> 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 [email protected].
>
> --
> You received this message because you are subscribed to the Google Groups "syzkaller-upstream-moderation" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
> To view this discussion visit https://groups.google.com/d/msgid/syzkaller-upstream-moderation/eda8ccdd-476a-4387-95bf-aeedb3545c69%40mail.kernel.org.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.