Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'net-bridge-fix-two-mst-bugs'

Nikolay Aleksandrov says:

====================
net: bridge: fix two MST bugs

Patch 01 fixes a race condition that exists between expired fdb deletion
and port deletion when MST is enabled. Learning can happen after the
port's state has been changed to disabled which could lead to that
port's memory being used after it's been freed. The issue was reported
by syzbot, more information in patch 01. Patch 02 fixes an issue with
MST's static key which Ido spotted, we can have multiple bridges with MST
and a single bridge can erroneously disable it for all.
====================

Link: https://patch.msgid.link/20251105111919.1499702-1-razor@blackwall.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+22 -8
+1 -1
net/bridge/br_forward.c
··· 25 25 26 26 vg = nbp_vlan_group_rcu(p); 27 27 return ((p->flags & BR_HAIRPIN_MODE) || skb->dev != p->dev) && 28 - (br_mst_is_enabled(p->br) || p->state == BR_STATE_FORWARDING) && 28 + (br_mst_is_enabled(p) || p->state == BR_STATE_FORWARDING) && 29 29 br_allowed_egress(vg, skb) && nbp_switchdev_allowed_egress(p, skb) && 30 30 !br_skb_isolated(p, skb); 31 31 }
+1
net/bridge/br_if.c
··· 386 386 del_nbp(p); 387 387 } 388 388 389 + br_mst_uninit(br); 389 390 br_recalculate_neigh_suppress_enabled(br); 390 391 391 392 br_fdb_delete_by_port(br, NULL, 0, 1);
+2 -2
net/bridge/br_input.c
··· 94 94 95 95 br = p->br; 96 96 97 - if (br_mst_is_enabled(br)) { 97 + if (br_mst_is_enabled(p)) { 98 98 state = BR_STATE_FORWARDING; 99 99 } else { 100 100 if (p->state == BR_STATE_DISABLED) { ··· 429 429 return RX_HANDLER_PASS; 430 430 431 431 forward: 432 - if (br_mst_is_enabled(p->br)) 432 + if (br_mst_is_enabled(p)) 433 433 goto defer_stp_filtering; 434 434 435 435 switch (p->state) {
+8 -2
net/bridge/br_mst.c
··· 22 22 } 23 23 EXPORT_SYMBOL_GPL(br_mst_enabled); 24 24 25 + void br_mst_uninit(struct net_bridge *br) 26 + { 27 + if (br_opt_get(br, BROPT_MST_ENABLED)) 28 + static_branch_dec(&br_mst_used); 29 + } 30 + 25 31 int br_mst_get_info(const struct net_device *dev, u16 msti, unsigned long *vids) 26 32 { 27 33 const struct net_bridge_vlan_group *vg; ··· 231 225 return err; 232 226 233 227 if (on) 234 - static_branch_enable(&br_mst_used); 228 + static_branch_inc(&br_mst_used); 235 229 else 236 - static_branch_disable(&br_mst_used); 230 + static_branch_dec(&br_mst_used); 237 231 238 232 br_opt_toggle(br, BROPT_MST_ENABLED, on); 239 233 return 0;
+10 -3
net/bridge/br_private.h
··· 1935 1935 /* br_mst.c */ 1936 1936 #ifdef CONFIG_BRIDGE_VLAN_FILTERING 1937 1937 DECLARE_STATIC_KEY_FALSE(br_mst_used); 1938 - static inline bool br_mst_is_enabled(struct net_bridge *br) 1938 + static inline bool br_mst_is_enabled(const struct net_bridge_port *p) 1939 1939 { 1940 + /* check the port's vlan group to avoid racing with port deletion */ 1940 1941 return static_branch_unlikely(&br_mst_used) && 1941 - br_opt_get(br, BROPT_MST_ENABLED); 1942 + br_opt_get(p->br, BROPT_MST_ENABLED) && 1943 + rcu_access_pointer(p->vlgrp); 1942 1944 } 1943 1945 1944 1946 int br_mst_set_state(struct net_bridge_port *p, u16 msti, u8 state, ··· 1954 1952 const struct net_bridge_vlan_group *vg); 1955 1953 int br_mst_process(struct net_bridge_port *p, const struct nlattr *mst_attr, 1956 1954 struct netlink_ext_ack *extack); 1955 + void br_mst_uninit(struct net_bridge *br); 1957 1956 #else 1958 - static inline bool br_mst_is_enabled(struct net_bridge *br) 1957 + static inline bool br_mst_is_enabled(const struct net_bridge_port *p) 1959 1958 { 1960 1959 return false; 1961 1960 } ··· 1989 1986 struct netlink_ext_ack *extack) 1990 1987 { 1991 1988 return -EOPNOTSUPP; 1989 + } 1990 + 1991 + static inline void br_mst_uninit(struct net_bridge *br) 1992 + { 1992 1993 } 1993 1994 #endif 1994 1995