Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mptcp: fix double-unlock in mptcp_poll

mptcp_connect/28740 is trying to release lock (sk_lock-AF_INET) at:
[<ffffffff82c15869>] mptcp_poll+0xb9/0x550
but there are no more locks to release!
Call Trace:
lock_release+0x50f/0x750
release_sock+0x171/0x1b0
mptcp_poll+0xb9/0x550
sock_poll+0x157/0x470
? get_net_ns+0xb0/0xb0
do_sys_poll+0x63c/0xdd0

Problem is that __mptcp_tcp_fallback() releases the mptcp socket lock,
but after recent change it doesn't do this in all of its return paths.

To fix this, remove the unlock from __mptcp_tcp_fallback() and
always do the unlock in the caller.

Also add a small comment as to why we have this
__mptcp_needs_tcp_fallback().

Fixes: 0b4f33def7bbde ("mptcp: fix tcp fallback crash")
Reported-by: syzbot+e56606435b7bfeea8cf5@syzkaller.appspotmail.com
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Florian Westphal and committed by
David S. Miller
e154659b 3fe260e0

+13 -12
+13 -12
net/mptcp/protocol.c
··· 97 97 if (likely(!__mptcp_needs_tcp_fallback(msk))) 98 98 return NULL; 99 99 100 - if (msk->subflow) { 101 - release_sock((struct sock *)msk); 102 - return msk->subflow; 103 - } 104 - 105 - return NULL; 100 + return msk->subflow; 106 101 } 107 102 108 103 static bool __mptcp_can_create_subflow(const struct mptcp_sock *msk) ··· 729 734 goto out; 730 735 } 731 736 737 + fallback: 732 738 ssock = __mptcp_tcp_fallback(msk); 733 739 if (unlikely(ssock)) { 734 - fallback: 740 + release_sock(sk); 735 741 pr_debug("fallback passthrough"); 736 742 ret = sock_sendmsg(ssock, msg); 737 743 return ret >= 0 ? ret + copied : (copied ? copied : ret); ··· 765 769 if (ret < 0) 766 770 break; 767 771 if (ret == 0 && unlikely(__mptcp_needs_tcp_fallback(msk))) { 772 + /* Can happen for passive sockets: 773 + * 3WHS negotiated MPTCP, but first packet after is 774 + * plain TCP (e.g. due to middlebox filtering unknown 775 + * options). 776 + * 777 + * Fall back to TCP. 778 + */ 768 779 release_sock(ssk); 769 - ssock = __mptcp_tcp_fallback(msk); 770 780 goto fallback; 771 781 } 772 782 ··· 885 883 ssock = __mptcp_tcp_fallback(msk); 886 884 if (unlikely(ssock)) { 887 885 fallback: 886 + release_sock(sk); 888 887 pr_debug("fallback-read subflow=%p", 889 888 mptcp_subflow_ctx(ssock->sk)); 890 889 copied = sock_recvmsg(ssock, msg, flags); ··· 1470 1467 */ 1471 1468 lock_sock(sk); 1472 1469 ssock = __mptcp_tcp_fallback(msk); 1470 + release_sock(sk); 1473 1471 if (ssock) 1474 1472 return tcp_setsockopt(ssock->sk, level, optname, optval, 1475 1473 optlen); 1476 - 1477 - release_sock(sk); 1478 1474 1479 1475 return -EOPNOTSUPP; 1480 1476 } ··· 1494 1492 */ 1495 1493 lock_sock(sk); 1496 1494 ssock = __mptcp_tcp_fallback(msk); 1495 + release_sock(sk); 1497 1496 if (ssock) 1498 1497 return tcp_getsockopt(ssock->sk, level, optname, optval, 1499 1498 option); 1500 - 1501 - release_sock(sk); 1502 1499 1503 1500 return -EOPNOTSUPP; 1504 1501 }