mirror of
https://github.com/torvalds/linux.git
synced 2026-09-11 20:13:02 +02:00
net: bridge: mcast: properly convert mglist to rcu
Sashiko reported a bug [1] that br_multicast_del_port_group unlists the
port group not using proper rcu helper that preserves the next pointer and
after that immediately frees the port group without waiting for rcu grace
period. The only rcu walker of mglist is br_multicast_list_adjacent() and
it turns out that function has always been buggy because mglist was never
properly converted to RCU. Fix it by converting it to rcu and moving its
initialization after eth_addr's. Initializing p->next can use
RCU_INIT_POINTER because we have a barrier from the hlist_add_head_rcu call
later, besides we're initializing an unpublished structure anyway.
[1] https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260826014200.362304-1-littleddfu%40gmail.com
Fixes: 07f8ac4a1e ("bridge: add export of multicast database adjacent to net_dev")
Signed-off-by: Nikolay Aleksandrov <razor@blackwall.org>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Link: https://patch.msgid.link/20260903093851.1494297-1-razor@blackwall.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
742b94967d
commit
4b772869a1
|
|
@ -1441,16 +1441,17 @@ struct net_bridge_port_group *br_multicast_new_port_group(
|
|||
goto free_out;
|
||||
}
|
||||
|
||||
rcu_assign_pointer(p->next, next);
|
||||
timer_setup(&p->timer, br_multicast_port_group_expired, 0);
|
||||
timer_setup(&p->rexmit_timer, br_multicast_port_group_rexmit, 0);
|
||||
hlist_add_head(&p->mglist, &port->mglist);
|
||||
|
||||
if (src)
|
||||
memcpy(p->eth_addr, src, ETH_ALEN);
|
||||
else
|
||||
eth_broadcast_addr(p->eth_addr);
|
||||
|
||||
RCU_INIT_POINTER(p->next, next);
|
||||
hlist_add_head_rcu(&p->mglist, &port->mglist);
|
||||
|
||||
return p;
|
||||
|
||||
free_out:
|
||||
|
|
@ -1465,11 +1466,11 @@ void br_multicast_del_port_group(struct net_bridge_port_group *p)
|
|||
struct net_bridge_port *port = p->key.port;
|
||||
__u16 vid = p->key.addr.vid;
|
||||
|
||||
hlist_del_init(&p->mglist);
|
||||
hlist_del_init_rcu(&p->mglist);
|
||||
if (!br_multicast_is_star_g(&p->key.addr))
|
||||
rhashtable_remove_fast(&port->br->sg_port_tbl, &p->rhnode,
|
||||
br_sg_port_rht_params);
|
||||
kfree(p);
|
||||
kfree_rcu(p, rcu);
|
||||
br_multicast_port_ngroups_dec(port, vid);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user