Skip to content

Commit 5a508a2

Browse files
jpirkodavem330
authored andcommitted
devlink: disallow reload operation during device cleanup
There is a race between driver code that does setup/cleanup of device and devlink reload operation that in some drivers works with the same code. Use after free could we easily obtained by running: while true; do echo "0000:00:10.0" >/sys/bus/pci/drivers/mlxsw_spectrum2/bind devlink dev reload pci/0000:00:10.0 & echo "0000:00:10.0" >/sys/bus/pci/drivers/mlxsw_spectrum2/unbind done Fix this by enabling reload only after setup of device is complete and disabling it at the beginning of the cleanup process. Reported-by: Ido Schimmel <[email protected]> Fixes: 2d8dc5b ("devlink: Add support for reload") Signed-off-by: Jiri Pirko <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 0058b0a commit 5a508a2

File tree

5 files changed

+52
-3
lines changed

5 files changed

+52
-3
lines changed

drivers/net/ethernet/mellanox/mlx4/main.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4010,6 +4010,7 @@ static int mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
40104010
goto err_params_unregister;
40114011

40124012
devlink_params_publish(devlink);
4013+
devlink_reload_enable(devlink);
40134014
pci_save_state(pdev);
40144015
return 0;
40154016

@@ -4121,6 +4122,8 @@ static void mlx4_remove_one(struct pci_dev *pdev)
41214122
struct devlink *devlink = priv_to_devlink(priv);
41224123
int active_vfs = 0;
41234124

4125+
devlink_reload_disable(devlink);
4126+
41244127
if (mlx4_is_slave(dev))
41254128
persist->interface_state |= MLX4_INTERFACE_STATE_NOWAIT;
41264129

drivers/net/ethernet/mellanox/mlxsw/core.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1186,8 +1186,10 @@ __mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info,
11861186
if (err)
11871187
goto err_thermal_init;
11881188

1189-
if (mlxsw_driver->params_register)
1189+
if (mlxsw_driver->params_register) {
11901190
devlink_params_publish(devlink);
1191+
devlink_reload_enable(devlink);
1192+
}
11911193

11921194
return 0;
11931195

@@ -1249,6 +1251,8 @@ void mlxsw_core_bus_device_unregister(struct mlxsw_core *mlxsw_core,
12491251
{
12501252
struct devlink *devlink = priv_to_devlink(mlxsw_core);
12511253

1254+
if (!reload)
1255+
devlink_reload_disable(devlink);
12521256
if (devlink_is_reload_failed(devlink)) {
12531257
if (!reload)
12541258
/* Only the parts that were not de-initialized in the

drivers/net/netdevsim/dev.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -708,6 +708,7 @@ nsim_dev_create(struct nsim_bus_dev *nsim_bus_dev, unsigned int port_count)
708708
goto err_debugfs_exit;
709709

710710
devlink_params_publish(devlink);
711+
devlink_reload_enable(devlink);
711712
return nsim_dev;
712713

713714
err_debugfs_exit:
@@ -732,6 +733,7 @@ static void nsim_dev_destroy(struct nsim_dev *nsim_dev)
732733
{
733734
struct devlink *devlink = priv_to_devlink(nsim_dev);
734735

736+
devlink_reload_disable(devlink);
735737
nsim_bpf_dev_exit(nsim_dev);
736738
nsim_dev_debugfs_exit(nsim_dev);
737739
nsim_dev_traps_exit(devlink);

include/net/devlink.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ struct devlink {
3838
struct device *dev;
3939
possible_net_t _net;
4040
struct mutex lock;
41-
bool reload_failed;
41+
u8 reload_failed:1,
42+
reload_enabled:1;
4243
char priv[0] __aligned(NETDEV_ALIGN);
4344
};
4445

@@ -774,6 +775,8 @@ struct ib_device;
774775
struct devlink *devlink_alloc(const struct devlink_ops *ops, size_t priv_size);
775776
int devlink_register(struct devlink *devlink, struct device *dev);
776777
void devlink_unregister(struct devlink *devlink);
778+
void devlink_reload_enable(struct devlink *devlink);
779+
void devlink_reload_disable(struct devlink *devlink);
777780
void devlink_free(struct devlink *devlink);
778781
int devlink_port_register(struct devlink *devlink,
779782
struct devlink_port *devlink_port,

net/core/devlink.c

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2699,7 +2699,7 @@ static int devlink_nl_cmd_reload(struct sk_buff *skb, struct genl_info *info)
26992699
struct devlink *devlink = info->user_ptr[0];
27002700
int err;
27012701

2702-
if (!devlink_reload_supported(devlink))
2702+
if (!devlink_reload_supported(devlink) || !devlink->reload_enabled)
27032703
return -EOPNOTSUPP;
27042704

27052705
err = devlink_resources_validate(devlink, NULL, info);
@@ -6196,12 +6196,49 @@ EXPORT_SYMBOL_GPL(devlink_register);
61966196
void devlink_unregister(struct devlink *devlink)
61976197
{
61986198
mutex_lock(&devlink_mutex);
6199+
WARN_ON(devlink_reload_supported(devlink) &&
6200+
devlink->reload_enabled);
61996201
devlink_notify(devlink, DEVLINK_CMD_DEL);
62006202
list_del(&devlink->list);
62016203
mutex_unlock(&devlink_mutex);
62026204
}
62036205
EXPORT_SYMBOL_GPL(devlink_unregister);
62046206

6207+
/**
6208+
* devlink_reload_enable - Enable reload of devlink instance
6209+
*
6210+
* @devlink: devlink
6211+
*
6212+
* Should be called at end of device initialization
6213+
* process when reload operation is supported.
6214+
*/
6215+
void devlink_reload_enable(struct devlink *devlink)
6216+
{
6217+
mutex_lock(&devlink_mutex);
6218+
devlink->reload_enabled = true;
6219+
mutex_unlock(&devlink_mutex);
6220+
}
6221+
EXPORT_SYMBOL_GPL(devlink_reload_enable);
6222+
6223+
/**
6224+
* devlink_reload_disable - Disable reload of devlink instance
6225+
*
6226+
* @devlink: devlink
6227+
*
6228+
* Should be called at the beginning of device cleanup
6229+
* process when reload operation is supported.
6230+
*/
6231+
void devlink_reload_disable(struct devlink *devlink)
6232+
{
6233+
mutex_lock(&devlink_mutex);
6234+
/* Mutex is taken which ensures that no reload operation is in
6235+
* progress while setting up forbidded flag.
6236+
*/
6237+
devlink->reload_enabled = false;
6238+
mutex_unlock(&devlink_mutex);
6239+
}
6240+
EXPORT_SYMBOL_GPL(devlink_reload_disable);
6241+
62056242
/**
62066243
* devlink_free - Free devlink instance resources
62076244
*

0 commit comments

Comments
 (0)