diff options
author | Ido Schimmel <idosch@mellanox.com> | 2018-10-17 04:05:45 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-10-18 01:25:45 -0400 |
commit | 9b3bc7db759e64c33471025721817467f8c3ecd4 (patch) | |
tree | 3dab97b9c58de87c8587db412b4b43802b81ed06 | |
parent | c863850ce22e1b0bb365d49cadf51f4765153ae4 (diff) |
mlxsw: core: Fix use-after-free when flashing firmware during init
When the switch driver (e.g., mlxsw_spectrum) determines it needs to
flash a new firmware version it resets the ASIC after the flashing
process. The bus driver (e.g., mlxsw_pci) then registers itself again
with mlxsw_core which means (among other things) that the device
registers itself again with the hwmon subsystem again.
Since the device was registered with the hwmon subsystem using
devm_hwmon_device_register_with_groups(), then the old hwmon device
(registered before the flashing) was never unregistered and was
referencing stale data, resulting in a use-after free.
Fix by removing reliance on device managed APIs in mlxsw_hwmon_init().
Fixes: c86d62cc410c ("mlxsw: spectrum: Reset FW after flash")
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Reported-by: Alexander Petrovskiy <alexpe@mellanox.com>
Tested-by: Alexander Petrovskiy <alexpe@mellanox.com>
Reviewed-by: Petr Machata <petrm@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/core.c | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/core.h | 4 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c | 17 |
3 files changed, 17 insertions, 6 deletions
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c index 81533d7f395c..937d0ace699a 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core.c +++ b/drivers/net/ethernet/mellanox/mlxsw/core.c | |||
@@ -1055,6 +1055,7 @@ int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info, | |||
1055 | err_driver_init: | 1055 | err_driver_init: |
1056 | mlxsw_thermal_fini(mlxsw_core->thermal); | 1056 | mlxsw_thermal_fini(mlxsw_core->thermal); |
1057 | err_thermal_init: | 1057 | err_thermal_init: |
1058 | mlxsw_hwmon_fini(mlxsw_core->hwmon); | ||
1058 | err_hwmon_init: | 1059 | err_hwmon_init: |
1059 | if (!reload) | 1060 | if (!reload) |
1060 | devlink_unregister(devlink); | 1061 | devlink_unregister(devlink); |
@@ -1088,6 +1089,7 @@ void mlxsw_core_bus_device_unregister(struct mlxsw_core *mlxsw_core, | |||
1088 | if (mlxsw_core->driver->fini) | 1089 | if (mlxsw_core->driver->fini) |
1089 | mlxsw_core->driver->fini(mlxsw_core); | 1090 | mlxsw_core->driver->fini(mlxsw_core); |
1090 | mlxsw_thermal_fini(mlxsw_core->thermal); | 1091 | mlxsw_thermal_fini(mlxsw_core->thermal); |
1092 | mlxsw_hwmon_fini(mlxsw_core->hwmon); | ||
1091 | if (!reload) | 1093 | if (!reload) |
1092 | devlink_unregister(devlink); | 1094 | devlink_unregister(devlink); |
1093 | mlxsw_emad_fini(mlxsw_core); | 1095 | mlxsw_emad_fini(mlxsw_core); |
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h index 655ddd204ab2..c35be477856f 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core.h +++ b/drivers/net/ethernet/mellanox/mlxsw/core.h | |||
@@ -359,6 +359,10 @@ static inline int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core, | |||
359 | return 0; | 359 | return 0; |
360 | } | 360 | } |
361 | 361 | ||
362 | static inline void mlxsw_hwmon_fini(struct mlxsw_hwmon *mlxsw_hwmon) | ||
363 | { | ||
364 | } | ||
365 | |||
362 | #endif | 366 | #endif |
363 | 367 | ||
364 | struct mlxsw_thermal; | 368 | struct mlxsw_thermal; |
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c index f6cf2896d337..e04e8162aa14 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +++ b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c | |||
@@ -303,8 +303,7 @@ int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core, | |||
303 | struct device *hwmon_dev; | 303 | struct device *hwmon_dev; |
304 | int err; | 304 | int err; |
305 | 305 | ||
306 | mlxsw_hwmon = devm_kzalloc(mlxsw_bus_info->dev, sizeof(*mlxsw_hwmon), | 306 | mlxsw_hwmon = kzalloc(sizeof(*mlxsw_hwmon), GFP_KERNEL); |
307 | GFP_KERNEL); | ||
308 | if (!mlxsw_hwmon) | 307 | if (!mlxsw_hwmon) |
309 | return -ENOMEM; | 308 | return -ENOMEM; |
310 | mlxsw_hwmon->core = mlxsw_core; | 309 | mlxsw_hwmon->core = mlxsw_core; |
@@ -321,10 +320,9 @@ int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core, | |||
321 | mlxsw_hwmon->groups[0] = &mlxsw_hwmon->group; | 320 | mlxsw_hwmon->groups[0] = &mlxsw_hwmon->group; |
322 | mlxsw_hwmon->group.attrs = mlxsw_hwmon->attrs; | 321 | mlxsw_hwmon->group.attrs = mlxsw_hwmon->attrs; |
323 | 322 | ||
324 | hwmon_dev = devm_hwmon_device_register_with_groups(mlxsw_bus_info->dev, | 323 | hwmon_dev = hwmon_device_register_with_groups(mlxsw_bus_info->dev, |
325 | "mlxsw", | 324 | "mlxsw", mlxsw_hwmon, |
326 | mlxsw_hwmon, | 325 | mlxsw_hwmon->groups); |
327 | mlxsw_hwmon->groups); | ||
328 | if (IS_ERR(hwmon_dev)) { | 326 | if (IS_ERR(hwmon_dev)) { |
329 | err = PTR_ERR(hwmon_dev); | 327 | err = PTR_ERR(hwmon_dev); |
330 | goto err_hwmon_register; | 328 | goto err_hwmon_register; |
@@ -337,5 +335,12 @@ int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core, | |||
337 | err_hwmon_register: | 335 | err_hwmon_register: |
338 | err_fans_init: | 336 | err_fans_init: |
339 | err_temp_init: | 337 | err_temp_init: |
338 | kfree(mlxsw_hwmon); | ||
340 | return err; | 339 | return err; |
341 | } | 340 | } |
341 | |||
342 | void mlxsw_hwmon_fini(struct mlxsw_hwmon *mlxsw_hwmon) | ||
343 | { | ||
344 | hwmon_device_unregister(mlxsw_hwmon->hwmon_dev); | ||
345 | kfree(mlxsw_hwmon); | ||
346 | } | ||