Commit 993107fe authored by Ido Schimmel's avatar Ido Schimmel Committed by David S. Miller

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: c57529e1 ("mlxsw: spectrum: Replace vPorts with Port-VLAN")
Signed-off-by: default avatarIdo Schimmel <idosch@mellanox.com>
Reviewed-by: default avatarPetr Machata <petrm@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent da93d291
...@@ -296,7 +296,13 @@ static bool ...@@ -296,7 +296,13 @@ static bool
mlxsw_sp_bridge_port_should_destroy(const struct mlxsw_sp_bridge_port * mlxsw_sp_bridge_port_should_destroy(const struct mlxsw_sp_bridge_port *
bridge_port) bridge_port)
{ {
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(bridge_port->dev); struct net_device *dev = bridge_port->dev;
struct mlxsw_sp *mlxsw_sp;
if (is_vlan_dev(dev))
mlxsw_sp = mlxsw_sp_lower_get(vlan_dev_real_dev(dev));
else
mlxsw_sp = mlxsw_sp_lower_get(dev);
/* In case ports were pulled from out of a bridged LAG, then /* In case ports were pulled from out of a bridged LAG, then
* it's possible the reference count isn't zero, yet the bridge * 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,7 +2115,7 @@ mlxsw_sp_bridge_8021d_port_leave(struct mlxsw_sp_bridge_device *bridge_device,
vid = is_vlan_dev(dev) ? vlan_dev_vlan_id(dev) : 1; vid = is_vlan_dev(dev) ? vlan_dev_vlan_id(dev) : 1;
mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid); mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid);
if (WARN_ON(!mlxsw_sp_port_vlan)) if (!mlxsw_sp_port_vlan)
return; return;
mlxsw_sp_port_vlan_bridge_leave(mlxsw_sp_port_vlan); mlxsw_sp_port_vlan_bridge_leave(mlxsw_sp_port_vlan);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment