mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 14:11:52 +00:00
net: bridge: mcast: wait for previous gc cycles when removing port
syzbot hit a use-after-free[1] which is caused because the bridge doesn't
make sure that all previous garbage has been collected when removing a
port. What happens is:
CPU 1 CPU 2
start gc cycle remove port
acquire gc lock first
wait for lock
call br_multicasg_gc() directly
acquire lock now but free port
the port can be freed
while grp timers still
running
Make sure all previous gc cycles have finished by using flush_work before
freeing the port.
[1]
BUG: KASAN: slab-use-after-free in br_multicast_port_group_expired+0x4c0/0x550 net/bridge/br_multicast.c:861
Read of size 8 at addr ffff888071d6d000 by task syz.5.1232/9699
CPU: 1 PID: 9699 Comm: syz.5.1232 Not tainted 6.10.0-rc5-syzkaller-00021-g24ca36a562d6 #0
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 06/07/2024
Call Trace:
<IRQ>
__dump_stack lib/dump_stack.c:88 [inline]
dump_stack_lvl+0x116/0x1f0 lib/dump_stack.c:114
print_address_description mm/kasan/report.c:377 [inline]
print_report+0xc3/0x620 mm/kasan/report.c:488
kasan_report+0xd9/0x110 mm/kasan/report.c:601
br_multicast_port_group_expired+0x4c0/0x550 net/bridge/br_multicast.c:861
call_timer_fn+0x1a3/0x610 kernel/time/timer.c:1792
expire_timers kernel/time/timer.c:1843 [inline]
__run_timers+0x74b/0xaf0 kernel/time/timer.c:2417
__run_timer_base kernel/time/timer.c:2428 [inline]
__run_timer_base kernel/time/timer.c:2421 [inline]
run_timer_base+0x111/0x190 kernel/time/timer.c:2437
Reported-by: syzbot+263426984509be19c9a0@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=263426984509be19c9a0
Fixes: e12cec65b5
("net: bridge: mcast: destroy all entries via gc")
Signed-off-by: Nikolay Aleksandrov <razor@blackwall.org>
Link: https://patch.msgid.link/20240802080730.3206303-1-razor@blackwall.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
7ab107544b
commit
92c4ee2520
@ -2045,16 +2045,14 @@ void br_multicast_del_port(struct net_bridge_port *port)
|
|||||||
{
|
{
|
||||||
struct net_bridge *br = port->br;
|
struct net_bridge *br = port->br;
|
||||||
struct net_bridge_port_group *pg;
|
struct net_bridge_port_group *pg;
|
||||||
HLIST_HEAD(deleted_head);
|
|
||||||
struct hlist_node *n;
|
struct hlist_node *n;
|
||||||
|
|
||||||
/* Take care of the remaining groups, only perm ones should be left */
|
/* Take care of the remaining groups, only perm ones should be left */
|
||||||
spin_lock_bh(&br->multicast_lock);
|
spin_lock_bh(&br->multicast_lock);
|
||||||
hlist_for_each_entry_safe(pg, n, &port->mglist, mglist)
|
hlist_for_each_entry_safe(pg, n, &port->mglist, mglist)
|
||||||
br_multicast_find_del_pg(br, pg);
|
br_multicast_find_del_pg(br, pg);
|
||||||
hlist_move_list(&br->mcast_gc_list, &deleted_head);
|
|
||||||
spin_unlock_bh(&br->multicast_lock);
|
spin_unlock_bh(&br->multicast_lock);
|
||||||
br_multicast_gc(&deleted_head);
|
flush_work(&br->mcast_gc_work);
|
||||||
br_multicast_port_ctx_deinit(&port->multicast_ctx);
|
br_multicast_port_ctx_deinit(&port->multicast_ctx);
|
||||||
free_percpu(port->mcast_stats);
|
free_percpu(port->mcast_stats);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user