Re: [PATCH net v2] net: bridge: mcast: don't truncate the port group walk on teardown
Nikolay Aleksandrov <[email protected]>
| Newsgroups | gmane.linux.network.bridge |
|---|---|
| Message-ID | <86b735ff-6996-4ab4-96b2-6853fcc788a7__40244.6338020795$1787730525$gmane$org@blackwall.org> |
On 26/08/2026 04:41, Jun Yang wrote: > From: Jun Yang <[email protected]> > > __br_multicast_disable_port_ctx() and br_multicast_del_port() walk > port->mglist with hlist_for_each_entry_safe(). However, > br_multicast_find_del_pg() can also delete other entries from the same > list through br_multicast_fwd_src_remove() or __fwd_del_star_excl(). > > If such an entry is the iterator's saved next node, hlist_del_init() > clears its ->next and terminates the walk early. The reproducer triggers > this in both teardown walks, leaving port groups in the bridge mdb with > a dangling ->key.port after del_nbp() frees the port: > > BUG: KASAN: slab-use-after-free in __mdb_fill_info+0x1191/0x1320 > __mdb_fill_info+0x1191/0x1320 > br_mdb_dump+0x594/0xe40 > rtnl_mdb_dump+0x1cf/0x5d0 > > Use hlist_del_init_rcu() to unlink the group while preserving ->next. > br_multicast_del_pg() and the teardown walks run under > br->multicast_lock. The GC worker must acquire the same lock before > detaching the group for destruction, so the node remains alive while > the walk uses the preserved pointer. > > Fixes: b08123684bd5 ("net: bridge: mcast: install S,G entries automatically based on reports") > Cc: [email protected] > Suggested-by: Nikolay Aleksandrov <[email protected]> > Reported-by: TencentOS Corvus AI <[email protected]> > Assisted-by: tencentos-corvus-ai:kimi-k3 > Signed-off-by: Jun Yang <[email protected]> > --- > v2: delete with hlist_del_init_rcu() to preserve ->next for an in-progress > teardown walk, per Nikolay's suggestion, instead of restarting the walks. > Tested on 7.2-rc7 with KASAN: the original use-after-free is no longer > reported. > > v1: https://lore.kernel.org/all/[email protected]/ > > net/bridge/br_multicast.c | 6 +++++- > 1 file changed, 5 insertions(+), 1 deletion(-) > > diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c > index 00aa9b2879d6..8022c7f12169 100644 > --- a/net/bridge/br_multicast.c > +++ b/net/bridge/br_multicast.c > @@ -808,7 +808,11 @@ void br_multicast_del_pg(struct net_bridge_mdb_entry *mp, > struct hlist_node *tmp; > > rcu_assign_pointer(*pp, pg->next); > - hlist_del_init(&pg->mglist); > + /* Keep ->next (held under multicast_lock, freed later by the GC work): > + * a port->mglist teardown walk may have latched this node as its next, > + * and deleting other groups of the same port must not truncate it. > + */ > + hlist_del_init_rcu(&pg->mglist); > br_multicast_eht_clean_sets(pg); > hlist_for_each_entry_safe(ent, tmp, &pg->src_list, node) > br_multicast_del_group_src(ent, false); Acked-by: Nikolay Aleksandrov <[email protected]>