]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
net/mlx5e: Harden uplink netdev access against device unbind
authorJianbo Liu <jianbol@nvidia.com>
Mon, 15 Sep 2025 12:24:32 +0000 (15:24 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 25 Sep 2025 09:13:44 +0000 (11:13 +0200)
[ Upstream commit 6b4be64fd9fec16418f365c2d8e47a7566e9eba5 ]

The function mlx5_uplink_netdev_get() gets the uplink netdevice
pointer from mdev->mlx5e_res.uplink_netdev. However, the netdevice can
be removed and its pointer cleared when unbound from the mlx5_core.eth
driver. This results in a NULL pointer, causing a kernel panic.

 BUG: unable to handle page fault for address: 0000000000001300
 at RIP: 0010:mlx5e_vport_rep_load+0x22a/0x270 [mlx5_core]
 Call Trace:
  <TASK>
  mlx5_esw_offloads_rep_load+0x68/0xe0 [mlx5_core]
  esw_offloads_enable+0x593/0x910 [mlx5_core]
  mlx5_eswitch_enable_locked+0x341/0x420 [mlx5_core]
  mlx5_devlink_eswitch_mode_set+0x17e/0x3a0 [mlx5_core]
  devlink_nl_eswitch_set_doit+0x60/0xd0
  genl_family_rcv_msg_doit+0xe0/0x130
  genl_rcv_msg+0x183/0x290
  netlink_rcv_skb+0x4b/0xf0
  genl_rcv+0x24/0x40
  netlink_unicast+0x255/0x380
  netlink_sendmsg+0x1f3/0x420
  __sock_sendmsg+0x38/0x60
  __sys_sendto+0x119/0x180
  do_syscall_64+0x53/0x1d0
  entry_SYSCALL_64_after_hwframe+0x4b/0x53

Ensure the pointer is valid before use by checking it for NULL. If it
is valid, immediately call netdev_hold() to take a reference, and
preventing the netdevice from being freed while it is in use.

Fixes: 7a9fb35e8c3a ("net/mlx5e: Do not reload ethernet ports when changing eswitch mode")
Signed-off-by: Jianbo Liu <jianbol@nvidia.com>
Reviewed-by: Cosmin Ratiu <cratiu@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Reviewed-by: Dragos Tatulea <dtatulea@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
Link: https://patch.msgid.link/1757939074-617281-2-git-send-email-tariqt@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c
drivers/net/ethernet/mellanox/mlx5/core/lib/mlx5.h
include/linux/mlx5/driver.h

index 18ec392d17404c85ad9fe552b38827f70732066e..b561358474c4ff2bd3729a982ce4f47df241f548 100644 (file)
@@ -1497,12 +1497,21 @@ static const struct mlx5e_profile mlx5e_uplink_rep_profile = {
 static int
 mlx5e_vport_uplink_rep_load(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep)
 {
-       struct mlx5e_priv *priv = netdev_priv(mlx5_uplink_netdev_get(dev));
        struct mlx5e_rep_priv *rpriv = mlx5e_rep_to_rep_priv(rep);
+       struct net_device *netdev;
+       struct mlx5e_priv *priv;
+       int err;
+
+       netdev = mlx5_uplink_netdev_get(dev);
+       if (!netdev)
+               return 0;
 
+       priv = netdev_priv(netdev);
        rpriv->netdev = priv->netdev;
-       return mlx5e_netdev_change_profile(priv, &mlx5e_uplink_rep_profile,
-                                          rpriv);
+       err = mlx5e_netdev_change_profile(priv, &mlx5e_uplink_rep_profile,
+                                         rpriv);
+       mlx5_uplink_netdev_put(dev, netdev);
+       return err;
 }
 
 static void
@@ -1629,8 +1638,16 @@ mlx5e_vport_rep_unload(struct mlx5_eswitch_rep *rep)
 {
        struct mlx5e_rep_priv *rpriv = mlx5e_rep_to_rep_priv(rep);
        struct net_device *netdev = rpriv->netdev;
-       struct mlx5e_priv *priv = netdev_priv(netdev);
-       void *ppriv = priv->ppriv;
+       struct mlx5e_priv *priv;
+       void *ppriv;
+
+       if (!netdev) {
+               ppriv = rpriv;
+               goto free_ppriv;
+       }
+
+       priv = netdev_priv(netdev);
+       ppriv = priv->ppriv;
 
        if (rep->vport == MLX5_VPORT_UPLINK) {
                mlx5e_vport_uplink_rep_unload(rpriv);
index 02a3563f51ad2697af9485b0e4947e750bb5d08f..d8c304427e2ab893c947151d87f5fd90d085ec8e 100644 (file)
@@ -733,6 +733,7 @@ static u32 mlx5_esw_qos_lag_link_speed_get_locked(struct mlx5_core_dev *mdev)
                speed = lksettings.base.speed;
 
 out:
+       mlx5_uplink_netdev_put(mdev, slave);
        return speed;
 }
 
index 37d5f445598c7bff34f1a09b8d3c2ac8749d923b..a7486e6d0d5eff4f47e537706a48c336916da497 100644 (file)
@@ -52,7 +52,20 @@ static inline struct net *mlx5_core_net(struct mlx5_core_dev *dev)
 
 static inline struct net_device *mlx5_uplink_netdev_get(struct mlx5_core_dev *mdev)
 {
-       return mdev->mlx5e_res.uplink_netdev;
+       struct mlx5e_resources *mlx5e_res = &mdev->mlx5e_res;
+       struct net_device *netdev;
+
+       mutex_lock(&mlx5e_res->uplink_netdev_lock);
+       netdev = mlx5e_res->uplink_netdev;
+       netdev_hold(netdev, &mlx5e_res->tracker, GFP_KERNEL);
+       mutex_unlock(&mlx5e_res->uplink_netdev_lock);
+       return netdev;
+}
+
+static inline void mlx5_uplink_netdev_put(struct mlx5_core_dev *mdev,
+                                         struct net_device *netdev)
+{
+       netdev_put(netdev, &mdev->mlx5e_res.tracker);
 }
 
 struct mlx5_sd;
index da9749739abde98d70e8c405e78901ea8b18988b..9a8eb644f6707d1c0179484c0d742a570eb72ae3 100644 (file)
@@ -689,6 +689,7 @@ struct mlx5e_resources {
                bool                       tisn_valid;
        } hw_objs;
        struct net_device *uplink_netdev;
+       netdevice_tracker tracker;
        struct mutex uplink_netdev_lock;
        struct mlx5_crypto_dek_priv *dek_priv;
 };