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 <idosch@mellanox.com>
Fixes: 2d8dc5bbf4 ("devlink: Add support for reload")
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Jiri Pirko
2019-11-09 11:29:46 +01:00
committed by David S. Miller
parent 0058b0a506
commit 5a508a254b
5 changed files with 52 additions and 3 deletions

View File

@@ -2699,7 +2699,7 @@ static int devlink_nl_cmd_reload(struct sk_buff *skb, struct genl_info *info)
struct devlink *devlink = info->user_ptr[0];
int err;
if (!devlink_reload_supported(devlink))
if (!devlink_reload_supported(devlink) || !devlink->reload_enabled)
return -EOPNOTSUPP;
err = devlink_resources_validate(devlink, NULL, info);
@@ -6196,12 +6196,49 @@ EXPORT_SYMBOL_GPL(devlink_register);
void devlink_unregister(struct devlink *devlink)
{
mutex_lock(&devlink_mutex);
WARN_ON(devlink_reload_supported(devlink) &&
devlink->reload_enabled);
devlink_notify(devlink, DEVLINK_CMD_DEL);
list_del(&devlink->list);
mutex_unlock(&devlink_mutex);
}
EXPORT_SYMBOL_GPL(devlink_unregister);
/**
* devlink_reload_enable - Enable reload of devlink instance
*
* @devlink: devlink
*
* Should be called at end of device initialization
* process when reload operation is supported.
*/
void devlink_reload_enable(struct devlink *devlink)
{
mutex_lock(&devlink_mutex);
devlink->reload_enabled = true;
mutex_unlock(&devlink_mutex);
}
EXPORT_SYMBOL_GPL(devlink_reload_enable);
/**
* devlink_reload_disable - Disable reload of devlink instance
*
* @devlink: devlink
*
* Should be called at the beginning of device cleanup
* process when reload operation is supported.
*/
void devlink_reload_disable(struct devlink *devlink)
{
mutex_lock(&devlink_mutex);
/* Mutex is taken which ensures that no reload operation is in
* progress while setting up forbidded flag.
*/
devlink->reload_enabled = false;
mutex_unlock(&devlink_mutex);
}
EXPORT_SYMBOL_GPL(devlink_reload_disable);
/**
* devlink_free - Free devlink instance resources
*