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>
This commit is contained in:
@@ -25,7 +25,7 @@ static inline int should_deliver(const struct net_bridge_port *p,
|
||||
|
||||
vg = nbp_vlan_group_rcu(p);
|
||||
return ((p->flags & BR_HAIRPIN_MODE) || skb->dev != p->dev) &&
|
||||
(br_mst_is_enabled(p->br) || p->state == BR_STATE_FORWARDING) &&
|
||||
(br_mst_is_enabled(p) || p->state == BR_STATE_FORWARDING) &&
|
||||
br_allowed_egress(vg, skb) && nbp_switchdev_allowed_egress(p, skb) &&
|
||||
!br_skb_isolated(p, skb);
|
||||
}
|
||||
|
||||
@@ -386,6 +386,7 @@ void br_dev_delete(struct net_device *dev, struct list_head *head)
|
||||
del_nbp(p);
|
||||
}
|
||||
|
||||
br_mst_uninit(br);
|
||||
br_recalculate_neigh_suppress_enabled(br);
|
||||
|
||||
br_fdb_delete_by_port(br, NULL, 0, 1);
|
||||
|
||||
@@ -94,7 +94,7 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
|
||||
|
||||
br = p->br;
|
||||
|
||||
if (br_mst_is_enabled(br)) {
|
||||
if (br_mst_is_enabled(p)) {
|
||||
state = BR_STATE_FORWARDING;
|
||||
} else {
|
||||
if (p->state == BR_STATE_DISABLED) {
|
||||
@@ -429,7 +429,7 @@ static rx_handler_result_t br_handle_frame(struct sk_buff **pskb)
|
||||
return RX_HANDLER_PASS;
|
||||
|
||||
forward:
|
||||
if (br_mst_is_enabled(p->br))
|
||||
if (br_mst_is_enabled(p))
|
||||
goto defer_stp_filtering;
|
||||
|
||||
switch (p->state) {
|
||||
|
||||
+8
-2
@@ -22,6 +22,12 @@ bool br_mst_enabled(const struct net_device *dev)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(br_mst_enabled);
|
||||
|
||||
void br_mst_uninit(struct net_bridge *br)
|
||||
{
|
||||
if (br_opt_get(br, BROPT_MST_ENABLED))
|
||||
static_branch_dec(&br_mst_used);
|
||||
}
|
||||
|
||||
int br_mst_get_info(const struct net_device *dev, u16 msti, unsigned long *vids)
|
||||
{
|
||||
const struct net_bridge_vlan_group *vg;
|
||||
@@ -225,9 +231,9 @@ int br_mst_set_enabled(struct net_bridge *br, bool on,
|
||||
return err;
|
||||
|
||||
if (on)
|
||||
static_branch_enable(&br_mst_used);
|
||||
static_branch_inc(&br_mst_used);
|
||||
else
|
||||
static_branch_disable(&br_mst_used);
|
||||
static_branch_dec(&br_mst_used);
|
||||
|
||||
br_opt_toggle(br, BROPT_MST_ENABLED, on);
|
||||
return 0;
|
||||
|
||||
+10
-3
@@ -1935,10 +1935,12 @@ static inline bool br_vlan_state_allowed(u8 state, bool learn_allow)
|
||||
/* br_mst.c */
|
||||
#ifdef CONFIG_BRIDGE_VLAN_FILTERING
|
||||
DECLARE_STATIC_KEY_FALSE(br_mst_used);
|
||||
static inline bool br_mst_is_enabled(struct net_bridge *br)
|
||||
static inline bool br_mst_is_enabled(const struct net_bridge_port *p)
|
||||
{
|
||||
/* check the port's vlan group to avoid racing with port deletion */
|
||||
return static_branch_unlikely(&br_mst_used) &&
|
||||
br_opt_get(br, BROPT_MST_ENABLED);
|
||||
br_opt_get(p->br, BROPT_MST_ENABLED) &&
|
||||
rcu_access_pointer(p->vlgrp);
|
||||
}
|
||||
|
||||
int br_mst_set_state(struct net_bridge_port *p, u16 msti, u8 state,
|
||||
@@ -1952,8 +1954,9 @@ int br_mst_fill_info(struct sk_buff *skb,
|
||||
const struct net_bridge_vlan_group *vg);
|
||||
int br_mst_process(struct net_bridge_port *p, const struct nlattr *mst_attr,
|
||||
struct netlink_ext_ack *extack);
|
||||
void br_mst_uninit(struct net_bridge *br);
|
||||
#else
|
||||
static inline bool br_mst_is_enabled(struct net_bridge *br)
|
||||
static inline bool br_mst_is_enabled(const struct net_bridge_port *p)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -1987,6 +1990,10 @@ static inline int br_mst_process(struct net_bridge_port *p,
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline void br_mst_uninit(struct net_bridge *br)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
struct nf_br_ops {
|
||||
|
||||
Reference in New Issue
Block a user