Closed mjmartineau closed 2 years ago
KASAN: null-ptr-deref in range [0x0000000000000018-0x000000000000001f] RIP: 0010:__lock_acquire+0xdc5/0x5160 kernel/locking/lockdep.c:4885
Note that offset 0x18 correspond to socket_wq.wait.lock.key offset inside struct socket_wq This is likely caused by msk->sk_wq being NULL. Likely the first subflow was orphaned before reaching here.
Code: c2 04 41 bf 01 00 00 00 0f 86 cb 01 00 00 89 05 01 ba c2 04 e9 c0 01 00 00 48 b8 00 00 00 00 00 fc ff df 4c 89 ea 48 c1 ea 03 <80> 3c 02 00 0f 85 ea 27 00 00 49 81 7d 00 00 44 c0 85 0f 84 04 f3 RSP: 0018:ffff88802c86f7e0 EFLAGS: 00010006 RAX: dffffc0000000000 RBX: 1ffff1100590df2d RCX: 0000000000000000 RDX: 0000000000000003 RSI: 0000000000000000 RDI: 0000000000000018 RBP: ffff8880373ec180 R08: 0000000000000001 R09: 0000000000000001 R10: ffff88811b03084b R11: ffffed1023606109 R12: 0000000000000000 R13: 0000000000000018 R14: 0000000000000000 R15: 0000000000000000 FS: 00007fcdc7dd7700(0000) GS:ffff88811b000000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007fcdc7d73db8 CR3: 0000000113a3e001 CR4: 0000000000770ef0 PKRU: 55555554 Call Trace: lock_acquire kernel/locking/lockdep.c:5625 [inline] lock_acquire+0x1a2/0x490 kernel/locking/lockdep.c:5590 __raw_spin_lock_irqsave include/linux/spinlock_api_smp.h:110 [inline] _raw_spin_lock_irqsave+0x39/0x50 kernel/locking/spinlock.c:162 finish_wait+0xc0/0x280 kernel/sched/wait.c:400 inet_csk_wait_for_connect net/ipv4/inet_connection_sock.c:464 [inline] inet_csk_accept+0xa69/0xd20 net/ipv4/inet_connection_sock.c:497
The above acquires the listening TCP socket lock and check its status (TCP_LISTEN), but not for the sk being orphaned. Plain TCP socket can't reach there as orphans, but mptcp subflow possibly can, even if don't see how ?!?
mptcp_accept+0xe5/0x500 net/mptcp/protocol.c:2871 inet_accept+0xeb/0x790 net/ipv4/af_inet.c:742 mptcp_stream_accept+0x2e9/0x10c0 net/mptcp/protocol.c:3319
Here we check for the msk status, but we have to release the msk socket lock bevore invoking proto-level accept(). Adding more checks here will be useless.
it looks like we have a possible race triggering the above:
(on CPU 0)
listen(msk)
accept(msk)
|-> mptcp_stream_accept(msk)
|-> <listen status check successful>
(preempted or on CPU 1)
close(msk)
|-> <msk->sk_state = TCP_CLOSE, ssk is orphaned, ssk state is unchanged>
(preempted or on CPU 0)
|-> mptcp_accept()
|-> inet_csk_accept()
|-> <ssk status check is successful even if ssk is orphaned: oops>
Note: the above can happen even with no preemption enabled, I think, but is even much more unlikely.
it looks like we have a possible race triggering the above:
(on CPU 0) listen(msk) accept(msk) |-> mptcp_stream_accept(msk) |-> <listen status check successful> (preempted or on CPU 1) close(msk) |-> <msk->sk_state = TCP_CLOSE, ssk is orphaned, ssk state is unchanged>
Dumb me, the above can't happen: close(msk) will call into sock_release() -> ... -> mptcp_close() only after the struct socket/ inode refcnt goes to 0. In the above scenario, only after accept() completes.
Still looking for the real root cause
Syzkaller had new reproducer, nothing wrong found by looking at the code, syzkaller didn't hit this issue again: we can close this ticket for now and re-open it if something new is reported.
Syzkaller (with CONFIG_PREEMPT in the target kernel) found the following. One occurrence, no reproducer, tag
export/20211028T172544
https://github.com/multipath-tcp/mptcp_net-next/commit/267276196f68c6347becd881381195009e31e634Config: syz.config.gz Full syzkaller log: syz.log.gz