Skip to content

Commit d1f3db4

Browse files
Jianbo Liugregkh
authored andcommitted
net/mlx5e: Harden uplink netdev access against device unbind
[ Upstream commit 6b4be64 ] 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: 7a9fb35 ("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>
1 parent bec5048 commit d1f3db4

File tree

4 files changed

+38
-6
lines changed

4 files changed

+38
-6
lines changed

drivers/net/ethernet/mellanox/mlx5/core/en_rep.c

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1497,12 +1497,21 @@ static const struct mlx5e_profile mlx5e_uplink_rep_profile = {
14971497
static int
14981498
mlx5e_vport_uplink_rep_load(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep)
14991499
{
1500-
struct mlx5e_priv *priv = netdev_priv(mlx5_uplink_netdev_get(dev));
15011500
struct mlx5e_rep_priv *rpriv = mlx5e_rep_to_rep_priv(rep);
1501+
struct net_device *netdev;
1502+
struct mlx5e_priv *priv;
1503+
int err;
1504+
1505+
netdev = mlx5_uplink_netdev_get(dev);
1506+
if (!netdev)
1507+
return 0;
15021508

1509+
priv = netdev_priv(netdev);
15031510
rpriv->netdev = priv->netdev;
1504-
return mlx5e_netdev_change_profile(priv, &mlx5e_uplink_rep_profile,
1505-
rpriv);
1511+
err = mlx5e_netdev_change_profile(priv, &mlx5e_uplink_rep_profile,
1512+
rpriv);
1513+
mlx5_uplink_netdev_put(dev, netdev);
1514+
return err;
15061515
}
15071516

15081517
static void
@@ -1629,8 +1638,16 @@ mlx5e_vport_rep_unload(struct mlx5_eswitch_rep *rep)
16291638
{
16301639
struct mlx5e_rep_priv *rpriv = mlx5e_rep_to_rep_priv(rep);
16311640
struct net_device *netdev = rpriv->netdev;
1632-
struct mlx5e_priv *priv = netdev_priv(netdev);
1633-
void *ppriv = priv->ppriv;
1641+
struct mlx5e_priv *priv;
1642+
void *ppriv;
1643+
1644+
if (!netdev) {
1645+
ppriv = rpriv;
1646+
goto free_ppriv;
1647+
}
1648+
1649+
priv = netdev_priv(netdev);
1650+
ppriv = priv->ppriv;
16341651

16351652
if (rep->vport == MLX5_VPORT_UPLINK) {
16361653
mlx5e_vport_uplink_rep_unload(rpriv);

drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -733,6 +733,7 @@ static u32 mlx5_esw_qos_lag_link_speed_get_locked(struct mlx5_core_dev *mdev)
733733
speed = lksettings.base.speed;
734734

735735
out:
736+
mlx5_uplink_netdev_put(mdev, slave);
736737
return speed;
737738
}
738739

drivers/net/ethernet/mellanox/mlx5/core/lib/mlx5.h

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,20 @@ static inline struct net *mlx5_core_net(struct mlx5_core_dev *dev)
5252

5353
static inline struct net_device *mlx5_uplink_netdev_get(struct mlx5_core_dev *mdev)
5454
{
55-
return mdev->mlx5e_res.uplink_netdev;
55+
struct mlx5e_resources *mlx5e_res = &mdev->mlx5e_res;
56+
struct net_device *netdev;
57+
58+
mutex_lock(&mlx5e_res->uplink_netdev_lock);
59+
netdev = mlx5e_res->uplink_netdev;
60+
netdev_hold(netdev, &mlx5e_res->tracker, GFP_KERNEL);
61+
mutex_unlock(&mlx5e_res->uplink_netdev_lock);
62+
return netdev;
63+
}
64+
65+
static inline void mlx5_uplink_netdev_put(struct mlx5_core_dev *mdev,
66+
struct net_device *netdev)
67+
{
68+
netdev_put(netdev, &mdev->mlx5e_res.tracker);
5669
}
5770

5871
struct mlx5_sd;

include/linux/mlx5/driver.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -689,6 +689,7 @@ struct mlx5e_resources {
689689
bool tisn_valid;
690690
} hw_objs;
691691
struct net_device *uplink_netdev;
692+
netdevice_tracker tracker;
692693
struct mutex uplink_netdev_lock;
693694
struct mlx5_crypto_dek_priv *dek_priv;
694695
};

0 commit comments

Comments
 (0)