Skip to content

Commit 0b4f33d

Browse files
Florian Westphaldavem330
authored andcommitted
mptcp: fix tcp fallback crash
Christoph Paasch reports following crash: general protection fault [..] CPU: 0 PID: 2874 Comm: syz-executor072 Not tainted 5.6.0-rc5 #62 RIP: 0010:__pv_queued_spin_lock_slowpath kernel/locking/qspinlock.c:471 [..] queued_spin_lock_slowpath arch/x86/include/asm/qspinlock.h:50 [inline] do_raw_spin_lock include/linux/spinlock.h:181 [inline] spin_lock_bh include/linux/spinlock.h:343 [inline] __mptcp_flush_join_list+0x44/0xb0 net/mptcp/protocol.c:278 mptcp_shutdown+0xb3/0x230 net/mptcp/protocol.c:1882 [..] Problem is that mptcp_shutdown() socket isn't an mptcp socket, its a plain tcp_sk. Thus, trying to access mptcp_sk specific members accesses garbage. Root cause is that accept() returns a fallback (tcp) socket, not an mptcp one. There is code in getpeername to detect this and override the sockets stream_ops. But this will only run when accept() caller provided a sockaddr struct. "accept(fd, NULL, 0)" will therefore result in mptcp stream ops, but with sock->sk pointing at a tcp_sk. Update the existing fallback handling to detect this as well. Moreover, mptcp_shutdown did not have fallback handling, and mptcp_poll did it too late so add that there as well. Reported-by: Christoph Paasch <cpaasch@apple.com> Tested-by: Christoph Paasch <cpaasch@apple.com> Reviewed-by: Mat Martineau <mathew.j.martineau@linux.intel.com> Signed-off-by: Matthieu Baerts <matthieu.baerts@tessares.net> Signed-off-by: Florian Westphal <fw@strlen.de> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent d16fa75 commit 0b4f33d

1 file changed

Lines changed: 46 additions & 4 deletions

File tree

net/mptcp/protocol.c

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,43 @@ static bool __mptcp_needs_tcp_fallback(const struct mptcp_sock *msk)
5757
return msk->first && !sk_is_mptcp(msk->first);
5858
}
5959

60+
static struct socket *mptcp_is_tcpsk(struct sock *sk)
61+
{
62+
struct socket *sock = sk->sk_socket;
63+
64+
if (sock->sk != sk)
65+
return NULL;
66+
67+
if (unlikely(sk->sk_prot == &tcp_prot)) {
68+
/* we are being invoked after mptcp_accept() has
69+
* accepted a non-mp-capable flow: sk is a tcp_sk,
70+
* not an mptcp one.
71+
*
72+
* Hand the socket over to tcp so all further socket ops
73+
* bypass mptcp.
74+
*/
75+
sock->ops = &inet_stream_ops;
76+
return sock;
77+
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
78+
} else if (unlikely(sk->sk_prot == &tcpv6_prot)) {
79+
sock->ops = &inet6_stream_ops;
80+
return sock;
81+
#endif
82+
}
83+
84+
return NULL;
85+
}
86+
6087
static struct socket *__mptcp_tcp_fallback(struct mptcp_sock *msk)
6188
{
89+
struct socket *sock;
90+
6291
sock_owned_by_me((const struct sock *)msk);
6392

93+
sock = mptcp_is_tcpsk((struct sock *)msk);
94+
if (unlikely(sock))
95+
return sock;
96+
6497
if (likely(!__mptcp_needs_tcp_fallback(msk)))
6598
return NULL;
6699

@@ -84,6 +117,10 @@ static struct socket *__mptcp_socket_create(struct mptcp_sock *msk, int state)
84117
struct socket *ssock;
85118
int err;
86119

120+
ssock = __mptcp_tcp_fallback(msk);
121+
if (unlikely(ssock))
122+
return ssock;
123+
87124
ssock = __mptcp_nmpc_socket(msk);
88125
if (ssock)
89126
goto set_state;
@@ -1752,7 +1789,9 @@ static __poll_t mptcp_poll(struct file *file, struct socket *sock,
17521789

17531790
msk = mptcp_sk(sk);
17541791
lock_sock(sk);
1755-
ssock = __mptcp_nmpc_socket(msk);
1792+
ssock = __mptcp_tcp_fallback(msk);
1793+
if (!ssock)
1794+
ssock = __mptcp_nmpc_socket(msk);
17561795
if (ssock) {
17571796
mask = ssock->ops->poll(file, ssock, wait);
17581797
release_sock(sk);
@@ -1762,9 +1801,6 @@ static __poll_t mptcp_poll(struct file *file, struct socket *sock,
17621801
release_sock(sk);
17631802
sock_poll_wait(file, sock, wait);
17641803
lock_sock(sk);
1765-
ssock = __mptcp_tcp_fallback(msk);
1766-
if (unlikely(ssock))
1767-
return ssock->ops->poll(file, ssock, NULL);
17681804

17691805
if (test_bit(MPTCP_DATA_READY, &msk->flags))
17701806
mask = EPOLLIN | EPOLLRDNORM;
@@ -1783,11 +1819,17 @@ static int mptcp_shutdown(struct socket *sock, int how)
17831819
{
17841820
struct mptcp_sock *msk = mptcp_sk(sock->sk);
17851821
struct mptcp_subflow_context *subflow;
1822+
struct socket *ssock;
17861823
int ret = 0;
17871824

17881825
pr_debug("sk=%p, how=%d", msk, how);
17891826

17901827
lock_sock(sock->sk);
1828+
ssock = __mptcp_tcp_fallback(msk);
1829+
if (ssock) {
1830+
release_sock(sock->sk);
1831+
return inet_shutdown(ssock, how);
1832+
}
17911833

17921834
if (how == SHUT_WR || how == SHUT_RDWR)
17931835
inet_sk_state_store(sock->sk, TCP_FIN_WAIT1);

0 commit comments

Comments
 (0)