[Bridge] [syzbot] possible deadlock in br_ioctl_call

Hillf Danton hdanton at sina.com
Sun Aug 1 13:14:06 UTC 2021


On Sun, 01 Aug 2021 03:34:24 -0700
> syzbot found the following issue on:
> 
> HEAD commit:    3bdc70669eb2 Merge branch 'devlink-register'
> git tree:       net-next
> console output: https://syzkaller.appspot.com/x/log.txt?x=11ee370a300000
> kernel config:  https://syzkaller.appspot.com/x/.config?x=914a8107c0ffdc14
> dashboard link: https://syzkaller.appspot.com/bug?extid=34fe5894623c4ab1b379
> compiler:       gcc (Debian 10.2.1-6) 10.2.1 20210110, GNU ld (GNU Binutils for Debian) 2.35.1
> syz repro:      https://syzkaller.appspot.com/x/repro.syz?x=114398c6300000
> C reproducer:   https://syzkaller.appspot.com/x/repro.c?x=10d6d61a300000
> 
> IMPORTANT: if you fix the issue, please add the following tag to the commit:
> Reported-by: syzbot+34fe5894623c4ab1b379 at syzkaller.appspotmail.com
> 
> netdevsim netdevsim0 netdevsim1: set [1, 0] type 2 family 0 port 6081 - 0
> netdevsim netdevsim0 netdevsim2: set [1, 0] type 2 family 0 port 6081 - 0
> netdevsim netdevsim0 netdevsim3: set [1, 0] type 2 family 0 port 6081 - 0
> ======================================================
> WARNING: possible circular locking dependency detected
> 5.14.0-rc2-syzkaller #0 Not tainted
> ------------------------------------------------------
> syz-executor772/8460 is trying to acquire lock:
> ffffffff8d0a9608 (br_ioctl_mutex){+.+.}-{3:3}, at: br_ioctl_call+0x3b/0xa0 net/socket.c:1089
> 
> but task is already holding lock:
> ffffffff8d0cb568 (rtnl_mutex){+.+.}-{3:3}, at: dev_ioctl+0x1a7/0xee0 net/core/dev_ioctl.c:579
> 
> which lock already depends on the new lock.
> 
> 
> the existing dependency chain (in reverse order) is:
> 
> -> #1 (rtnl_mutex){+.+.}-{3:3}:
>        __mutex_lock_common kernel/locking/mutex.c:959 [inline]
>        __mutex_lock+0x12a/0x10a0 kernel/locking/mutex.c:1104
>        register_netdev+0x11/0x50 net/core/dev.c:10474
>        br_add_bridge+0x97/0xf0 net/bridge/br_if.c:459
>        br_ioctl_stub+0x750/0x7f0 net/bridge/br_ioctl.c:390
>        br_ioctl_call+0x5e/0xa0 net/socket.c:1091
>        sock_ioctl+0x30c/0x640 net/socket.c:1185
>        vfs_ioctl fs/ioctl.c:51 [inline]
>        __do_sys_ioctl fs/ioctl.c:1069 [inline]
>        __se_sys_ioctl fs/ioctl.c:1055 [inline]
>        __x64_sys_ioctl+0x193/0x200 fs/ioctl.c:1055
>        do_syscall_x64 arch/x86/entry/common.c:50 [inline]
>        do_syscall_64+0x35/0xb0 arch/x86/entry/common.c:80
>        entry_SYSCALL_64_after_hwframe+0x44/0xae
> 
> -> #0 (br_ioctl_mutex){+.+.}-{3:3}:
>        check_prev_add kernel/locking/lockdep.c:3051 [inline]
>        check_prevs_add kernel/locking/lockdep.c:3174 [inline]
>        validate_chain kernel/locking/lockdep.c:3789 [inline]
>        __lock_acquire+0x2a07/0x54a0 kernel/locking/lockdep.c:5015
>        lock_acquire kernel/locking/lockdep.c:5625 [inline]
>        lock_acquire+0x1ab/0x510 kernel/locking/lockdep.c:5590
>        __mutex_lock_common kernel/locking/mutex.c:959 [inline]
>        __mutex_lock+0x12a/0x10a0 kernel/locking/mutex.c:1104
>        br_ioctl_call+0x3b/0xa0 net/socket.c:1089
>        dev_ifsioc+0xc1f/0xf60 net/core/dev_ioctl.c:382
>        dev_ioctl+0x1b9/0xee0 net/core/dev_ioctl.c:580
>        sock_do_ioctl+0x18b/0x210 net/socket.c:1128
>        sock_ioctl+0x2f1/0x640 net/socket.c:1231
>        vfs_ioctl fs/ioctl.c:51 [inline]
>        __do_sys_ioctl fs/ioctl.c:1069 [inline]
>        __se_sys_ioctl fs/ioctl.c:1055 [inline]
>        __x64_sys_ioctl+0x193/0x200 fs/ioctl.c:1055
>        do_syscall_x64 arch/x86/entry/common.c:50 [inline]
>        do_syscall_64+0x35/0xb0 arch/x86/entry/common.c:80
>        entry_SYSCALL_64_after_hwframe+0x44/0xae
> 
> other info that might help us debug this:
> 
>  Possible unsafe locking scenario:
> 
>        CPU0                    CPU1
>        ----                    ----
>   lock(rtnl_mutex);
>                                lock(br_ioctl_mutex);
>                                lock(rtnl_mutex);
>   lock(br_ioctl_mutex);
> 
>  *** DEADLOCK ***

Fix it by doing bridge ioctl outside rtnl lock after checking netdev present
and bumping up its reference. Recheck netdev state (or take rtnl lock) after
acquiring br_ioctl_mutex with a stable netdev.

Now only for thoughts.

+++ x/net/core/dev_ioctl.c
@@ -379,7 +379,12 @@ static int dev_ifsioc(struct net *net, s
 	case SIOCBRDELIF:
 		if (!netif_device_present(dev))
 			return -ENODEV;
-		return br_ioctl_call(net, netdev_priv(dev), cmd, ifr, NULL);
+		dev_hold(dev);
+		rtnl_unlock();
+		err = br_ioctl_call(net, netdev_priv(dev), cmd, ifr, NULL);
+		dev_put(dev);
+		rtnl_lock();
+		return err;
 
 	case SIOCSHWTSTAMP:
 		err = net_hwtstamp_validate(ifr);


More information about the Bridge mailing list