mirror of
https://github.com/torvalds/linux.git
synced 2026-05-31 18:43:33 +02:00
net/mlx5e: Harden uplink netdev access against device unbind
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: 7a9fb35e8c ("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>
This commit is contained in:
parent
94ff1ed303
commit
6b4be64fd9
|
|
@ -1506,12 +1506,21 @@ static const struct mlx5e_profile mlx5e_uplink_rep_profile = {
|
||||||
static int
|
static int
|
||||||
mlx5e_vport_uplink_rep_load(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep)
|
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 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;
|
rpriv->netdev = priv->netdev;
|
||||||
return mlx5e_netdev_change_profile(priv, &mlx5e_uplink_rep_profile,
|
err = mlx5e_netdev_change_profile(priv, &mlx5e_uplink_rep_profile,
|
||||||
rpriv);
|
rpriv);
|
||||||
|
mlx5_uplink_netdev_put(dev, netdev);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -1638,8 +1647,16 @@ mlx5e_vport_rep_unload(struct mlx5_eswitch_rep *rep)
|
||||||
{
|
{
|
||||||
struct mlx5e_rep_priv *rpriv = mlx5e_rep_to_rep_priv(rep);
|
struct mlx5e_rep_priv *rpriv = mlx5e_rep_to_rep_priv(rep);
|
||||||
struct net_device *netdev = rpriv->netdev;
|
struct net_device *netdev = rpriv->netdev;
|
||||||
struct mlx5e_priv *priv = netdev_priv(netdev);
|
struct mlx5e_priv *priv;
|
||||||
void *ppriv = priv->ppriv;
|
void *ppriv;
|
||||||
|
|
||||||
|
if (!netdev) {
|
||||||
|
ppriv = rpriv;
|
||||||
|
goto free_ppriv;
|
||||||
|
}
|
||||||
|
|
||||||
|
priv = netdev_priv(netdev);
|
||||||
|
ppriv = priv->ppriv;
|
||||||
|
|
||||||
if (rep->vport == MLX5_VPORT_UPLINK) {
|
if (rep->vport == MLX5_VPORT_UPLINK) {
|
||||||
mlx5e_vport_uplink_rep_unload(rpriv);
|
mlx5e_vport_uplink_rep_unload(rpriv);
|
||||||
|
|
|
||||||
|
|
@ -1515,6 +1515,7 @@ static u32 mlx5_esw_qos_lag_link_speed_get_locked(struct mlx5_core_dev *mdev)
|
||||||
speed = lksettings.base.speed;
|
speed = lksettings.base.speed;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
mlx5_uplink_netdev_put(mdev, slave);
|
||||||
return speed;
|
return speed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,20 @@ int mlx5_crdump_collect(struct mlx5_core_dev *dev, u32 *cr_data);
|
||||||
|
|
||||||
static inline struct net_device *mlx5_uplink_netdev_get(struct mlx5_core_dev *mdev)
|
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;
|
struct mlx5_sd;
|
||||||
|
|
|
||||||
|
|
@ -663,6 +663,7 @@ struct mlx5e_resources {
|
||||||
bool tisn_valid;
|
bool tisn_valid;
|
||||||
} hw_objs;
|
} hw_objs;
|
||||||
struct net_device *uplink_netdev;
|
struct net_device *uplink_netdev;
|
||||||
|
netdevice_tracker tracker;
|
||||||
struct mutex uplink_netdev_lock;
|
struct mutex uplink_netdev_lock;
|
||||||
struct mlx5_crypto_dek_priv *dek_priv;
|
struct mlx5_crypto_dek_priv *dek_priv;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user