[SRU][J][PATCH 1/1] net: dsa: Avoid cross-chip syncing of VLAN filtering
Cengiz Can
cengiz.can at canonical.com
Tue Sep 8 21:56:33 UTC 2026
From: Tobias Waldekranz <tobias at waldekranz.com>
Changes to VLAN filtering are not applicable to cross-chip
notifications.
On a system like this:
.-----. .-----. .-----.
| sw1 +---+ sw2 +---+ sw3 |
'-1-2-' '-1-2-' '-1-2-'
Before this change, upon sw1p1 leaving a bridge, a call to
dsa_port_vlan_filtering would also be made to sw2p1 and sw3p1.
In this scenario:
.---------. .-----. .-----.
| sw1 +---+ sw2 +---+ sw3 |
'-1-2-3-4-' '-1-2-' '-1-2-'
When sw1p4 would leave a bridge, dsa_port_vlan_filtering would be
called for sw2 and sw3 with a non-existing port - leading to array
out-of-bounds accesses and crashes on mv88e6xxx.
Fixes: d371b7c92d19 ("net: dsa: Unset vlan_filtering when ports leave the bridge")
Signed-off-by: Tobias Waldekranz <tobias at waldekranz.com>
Reviewed-by: Vladimir Oltean <olteanv at gmail.com>
Signed-off-by: David S. Miller <davem at davemloft.net>
(backported from commit 108dc8741c203e9d6ce4e973367f1bac20c7192b)
[bot_kybele: This tree inlines the VLAN-filtering sync logic in
dsa_switch_bridge_leave instead of the dsa_switch_sync_vlan_filtering() helper
the upstream patch guards; wrapped that inlined block in the same local-switch
condition (dst->index==info->tree_index && ds->index==info->sw_index) and
discarded git-am's fuzzy-matched newer-tree function copy.]
CVE-2022-49234
Assisted-by: kybele:claude-opus-4.8
Signed-off-by: Cengiz Can <cengiz.can at canonical.com>
---
net/dsa/switch.c | 73 ++++++++++++++++++++++++++----------------------
1 file changed, 40 insertions(+), 33 deletions(-)
diff --git a/net/dsa/switch.c b/net/dsa/switch.c
index fb69f2f14234..89c08658f8f5 100644
--- a/net/dsa/switch.c
+++ b/net/dsa/switch.c
@@ -132,44 +132,51 @@ static int dsa_switch_bridge_leave(struct dsa_switch *ds,
info->sw_index, info->port,
info->br);
- if (ds->needs_standalone_vlan_filtering && !br_vlan_enabled(info->br)) {
- change_vlan_filtering = true;
- vlan_filtering = true;
- } else if (!ds->needs_standalone_vlan_filtering &&
- br_vlan_enabled(info->br)) {
- change_vlan_filtering = true;
- vlan_filtering = false;
- }
-
- /* If the bridge was vlan_filtering, the bridge core doesn't trigger an
- * event for changing vlan_filtering setting upon slave ports leaving
- * it. That is a good thing, because that lets us handle it and also
- * handle the case where the switch's vlan_filtering setting is global
- * (not per port). When that happens, the correct moment to trigger the
- * vlan_filtering callback is only when the last port leaves the last
- * VLAN-aware bridge.
+ /* Changes to VLAN filtering are not applicable to cross-chip
+ * notifications.
*/
- if (change_vlan_filtering && ds->vlan_filtering_is_global) {
- for (port = 0; port < ds->num_ports; port++) {
- struct net_device *bridge_dev;
-
- bridge_dev = dsa_to_port(ds, port)->bridge_dev;
+ if (dst->index == info->tree_index && ds->index == info->sw_index) {
+ if (ds->needs_standalone_vlan_filtering &&
+ !br_vlan_enabled(info->br)) {
+ change_vlan_filtering = true;
+ vlan_filtering = true;
+ } else if (!ds->needs_standalone_vlan_filtering &&
+ br_vlan_enabled(info->br)) {
+ change_vlan_filtering = true;
+ vlan_filtering = false;
+ }
- if (bridge_dev && br_vlan_enabled(bridge_dev)) {
- change_vlan_filtering = false;
- break;
+ /* If the bridge was vlan_filtering, the bridge core doesn't
+ * trigger an event for changing vlan_filtering setting upon
+ * slave ports leaving it. That is a good thing, because that
+ * lets us handle it and also handle the case where the switch's
+ * vlan_filtering setting is global (not per port). When that
+ * happens, the correct moment to trigger the vlan_filtering
+ * callback is only when the last port leaves the last VLAN-aware
+ * bridge.
+ */
+ if (change_vlan_filtering && ds->vlan_filtering_is_global) {
+ for (port = 0; port < ds->num_ports; port++) {
+ struct net_device *bridge_dev;
+
+ bridge_dev = dsa_to_port(ds, port)->bridge_dev;
+
+ if (bridge_dev && br_vlan_enabled(bridge_dev)) {
+ change_vlan_filtering = false;
+ break;
+ }
}
}
- }
- if (change_vlan_filtering) {
- err = dsa_port_vlan_filtering(dsa_to_port(ds, info->port),
- vlan_filtering, &extack);
- if (extack._msg)
- dev_err(ds->dev, "port %d: %s\n", info->port,
- extack._msg);
- if (err && err != -EOPNOTSUPP)
- return err;
+ if (change_vlan_filtering) {
+ err = dsa_port_vlan_filtering(dsa_to_port(ds, info->port),
+ vlan_filtering, &extack);
+ if (extack._msg)
+ dev_err(ds->dev, "port %d: %s\n", info->port,
+ extack._msg);
+ if (err && err != -EOPNOTSUPP)
+ return err;
+ }
}
return dsa_tag_8021q_bridge_leave(ds, info);
--
2.53.0
More information about the kernel-team
mailing list