aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIdo Schimmel <idosch@mellanox.com>2018-12-06 12:44:53 -0500
committerDavid S. Miller <davem@davemloft.net>2018-12-06 16:31:09 -0500
commit993107fea5eefdfdfde1ca38d3f01f0bebf76e77 (patch)
treece4e0cec2dc35dc184900f8c6bbf378c71cdbd89
parentda93d2913fdf43d5cde3c5a53ac9cc29684d5c7c (diff)
mlxsw: spectrum_switchdev: Fix VLAN device deletion via ioctl
When deleting a VLAN device using an ioctl the netdev is unregistered before the VLAN filter is updated via ndo_vlan_rx_kill_vid(). It can lead to a use-after-free in mlxsw in case the VLAN device is deleted while being enslaved to a bridge. The reason for the above is that when mlxsw receives the CHANGEUPPER event, it wrongly assumes that the VLAN device is no longer its upper and thus destroys the internal representation of the bridge port despite the reference count being non-zero. Fix this by checking if the VLAN device is our upper using its real device. In net-next I'm going to remove this trick and instead make mlxsw completely agnostic to the order of the events. Fixes: c57529e1d5d8 ("mlxsw: spectrum: Replace vPorts with Port-VLAN") Signed-off-by: Ido Schimmel <idosch@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/spectrum_switchdev.c10
1 files changed, 8 insertions, 2 deletions
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
index 7f2091c2648e..50080c60a279 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
@@ -296,7 +296,13 @@ static bool
296mlxsw_sp_bridge_port_should_destroy(const struct mlxsw_sp_bridge_port * 296mlxsw_sp_bridge_port_should_destroy(const struct mlxsw_sp_bridge_port *
297 bridge_port) 297 bridge_port)
298{ 298{
299 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(bridge_port->dev); 299 struct net_device *dev = bridge_port->dev;
300 struct mlxsw_sp *mlxsw_sp;
301
302 if (is_vlan_dev(dev))
303 mlxsw_sp = mlxsw_sp_lower_get(vlan_dev_real_dev(dev));
304 else
305 mlxsw_sp = mlxsw_sp_lower_get(dev);
300 306
301 /* In case ports were pulled from out of a bridged LAG, then 307 /* In case ports were pulled from out of a bridged LAG, then
302 * it's possible the reference count isn't zero, yet the bridge 308 * it's possible the reference count isn't zero, yet the bridge
@@ -2109,7 +2115,7 @@ mlxsw_sp_bridge_8021d_port_leave(struct mlxsw_sp_bridge_device *bridge_device,
2109 2115
2110 vid = is_vlan_dev(dev) ? vlan_dev_vlan_id(dev) : 1; 2116 vid = is_vlan_dev(dev) ? vlan_dev_vlan_id(dev) : 1;
2111 mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid); 2117 mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid);
2112 if (WARN_ON(!mlxsw_sp_port_vlan)) 2118 if (!mlxsw_sp_port_vlan)
2113 return; 2119 return;
2114 2120
2115 mlxsw_sp_port_vlan_bridge_leave(mlxsw_sp_port_vlan); 2121 mlxsw_sp_port_vlan_bridge_leave(mlxsw_sp_port_vlan);