Skip to content

Commit 630fd48

Browse files
vladimirolteankuba-moo
authored andcommitted
net: dsa: flush switchdev workqueue on bridge join error path
There is a race between switchdev_bridge_port_offload() and the dsa_port_switchdev_sync_attrs() call right below it. When switchdev_bridge_port_offload() finishes, FDB entries have been replayed by the bridge, but are scheduled for deferred execution later. However dsa_port_switchdev_sync_attrs -> dsa_port_can_apply_vlan_filtering() may impose restrictions on the vlan_filtering attribute and refuse offloading. When this happens, the delayed FDB entries will dereference dp->bridge, which is a NULL pointer because we have stopped the process of offloading this bridge. Unable to handle kernel NULL pointer dereference at virtual address 0000000000000000 Workqueue: dsa_ordered dsa_slave_switchdev_event_work pc : dsa_port_bridge_host_fdb_del+0x64/0x100 lr : dsa_slave_switchdev_event_work+0x130/0x1bc Call trace: dsa_port_bridge_host_fdb_del+0x64/0x100 dsa_slave_switchdev_event_work+0x130/0x1bc process_one_work+0x294/0x670 worker_thread+0x80/0x460 ---[ end trace 0000000000000000 ]--- Error: dsa_core: Must first remove VLAN uppers having VIDs also present in bridge. Fix the bug by doing what we do on the normal bridge leave path as well, which is to wait until the deferred FDB entries complete executing, then exit. The placement of dsa_flush_workqueue() after switchdev_bridge_port_unoffload() guarantees that both the FDB additions and deletions on rollback are waited for. Fixes: d7d0d42 ("net: dsa: flush switchdev workqueue when leaving the bridge") Signed-off-by: Vladimir Oltean <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent d75b4c7 commit 630fd48

File tree

1 file changed

+1
-0
lines changed

1 file changed

+1
-0
lines changed

net/dsa/port.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,7 @@ int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br,
451451
switchdev_bridge_port_unoffload(brport_dev, dp,
452452
&dsa_slave_switchdev_notifier,
453453
&dsa_slave_switchdev_blocking_notifier);
454+
dsa_flush_workqueue();
454455
out_rollback_unbridge:
455456
dsa_broadcast(DSA_NOTIFIER_BRIDGE_LEAVE, &info);
456457
out_rollback:

0 commit comments

Comments
 (0)