Commit 9f05f9ad authored by David S. Miller's avatar David S. Miller

Merge branch 'mptcp-fixes'

Mat Martineau says:

====================
mptcp: Fixes for mptcp cleanup/close and a selftest

Patch 1 fixes an issue with leaking subflow sockets if there's a failure
in a CGROUP_INET_SOCK_CREATE eBPF program.

Patch 2 fixes a syzkaller-detected race at MPTCP socket close.

Patch 3 is a fix for one mode of the mptcp_connect.sh selftest.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 4ae97cae df9e03ae
...@@ -1240,6 +1240,9 @@ static int mptcp_sendmsg_frag(struct sock *sk, struct sock *ssk, ...@@ -1240,6 +1240,9 @@ static int mptcp_sendmsg_frag(struct sock *sk, struct sock *ssk,
info->limit > dfrag->data_len)) info->limit > dfrag->data_len))
return 0; return 0;
if (unlikely(!__tcp_can_send(ssk)))
return -EAGAIN;
/* compute send limit */ /* compute send limit */
info->mss_now = tcp_send_mss(ssk, &info->size_goal, info->flags); info->mss_now = tcp_send_mss(ssk, &info->size_goal, info->flags);
copy = info->size_goal; copy = info->size_goal;
...@@ -1413,7 +1416,8 @@ static struct sock *mptcp_subflow_get_send(struct mptcp_sock *msk) ...@@ -1413,7 +1416,8 @@ static struct sock *mptcp_subflow_get_send(struct mptcp_sock *msk)
if (__mptcp_check_fallback(msk)) { if (__mptcp_check_fallback(msk)) {
if (!msk->first) if (!msk->first)
return NULL; return NULL;
return sk_stream_memory_free(msk->first) ? msk->first : NULL; return __tcp_can_send(msk->first) &&
sk_stream_memory_free(msk->first) ? msk->first : NULL;
} }
/* re-use last subflow, if the burst allow that */ /* re-use last subflow, if the burst allow that */
...@@ -1564,6 +1568,8 @@ void __mptcp_push_pending(struct sock *sk, unsigned int flags) ...@@ -1564,6 +1568,8 @@ void __mptcp_push_pending(struct sock *sk, unsigned int flags)
ret = mptcp_sendmsg_frag(sk, ssk, dfrag, &info); ret = mptcp_sendmsg_frag(sk, ssk, dfrag, &info);
if (ret <= 0) { if (ret <= 0) {
if (ret == -EAGAIN)
continue;
mptcp_push_release(ssk, &info); mptcp_push_release(ssk, &info);
goto out; goto out;
} }
...@@ -2769,30 +2775,16 @@ static void __mptcp_wr_shutdown(struct sock *sk) ...@@ -2769,30 +2775,16 @@ static void __mptcp_wr_shutdown(struct sock *sk)
static void __mptcp_destroy_sock(struct sock *sk) static void __mptcp_destroy_sock(struct sock *sk)
{ {
struct mptcp_subflow_context *subflow, *tmp;
struct mptcp_sock *msk = mptcp_sk(sk); struct mptcp_sock *msk = mptcp_sk(sk);
LIST_HEAD(conn_list);
pr_debug("msk=%p", msk); pr_debug("msk=%p", msk);
might_sleep(); might_sleep();
/* join list will be eventually flushed (with rst) at sock lock release time*/
list_splice_init(&msk->conn_list, &conn_list);
mptcp_stop_timer(sk); mptcp_stop_timer(sk);
sk_stop_timer(sk, &sk->sk_timer); sk_stop_timer(sk, &sk->sk_timer);
msk->pm.status = 0; msk->pm.status = 0;
/* clears msk->subflow, allowing the following loop to close
* even the initial subflow
*/
mptcp_dispose_initial_subflow(msk);
list_for_each_entry_safe(subflow, tmp, &conn_list, node) {
struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
__mptcp_close_ssk(sk, ssk, subflow, 0);
}
sk->sk_prot->destroy(sk); sk->sk_prot->destroy(sk);
WARN_ON_ONCE(msk->rmem_fwd_alloc); WARN_ON_ONCE(msk->rmem_fwd_alloc);
...@@ -2884,24 +2876,20 @@ static void mptcp_copy_inaddrs(struct sock *msk, const struct sock *ssk) ...@@ -2884,24 +2876,20 @@ static void mptcp_copy_inaddrs(struct sock *msk, const struct sock *ssk)
static int mptcp_disconnect(struct sock *sk, int flags) static int mptcp_disconnect(struct sock *sk, int flags)
{ {
struct mptcp_subflow_context *subflow, *tmp;
struct mptcp_sock *msk = mptcp_sk(sk); struct mptcp_sock *msk = mptcp_sk(sk);
inet_sk_state_store(sk, TCP_CLOSE); inet_sk_state_store(sk, TCP_CLOSE);
list_for_each_entry_safe(subflow, tmp, &msk->conn_list, node) {
struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
__mptcp_close_ssk(sk, ssk, subflow, MPTCP_CF_FASTCLOSE);
}
mptcp_stop_timer(sk); mptcp_stop_timer(sk);
sk_stop_timer(sk, &sk->sk_timer); sk_stop_timer(sk, &sk->sk_timer);
if (mptcp_sk(sk)->token) if (mptcp_sk(sk)->token)
mptcp_event(MPTCP_EVENT_CLOSED, mptcp_sk(sk), NULL, GFP_KERNEL); mptcp_event(MPTCP_EVENT_CLOSED, mptcp_sk(sk), NULL, GFP_KERNEL);
mptcp_destroy_common(msk); /* msk->subflow is still intact, the following will not free the first
* subflow
*/
mptcp_destroy_common(msk, MPTCP_CF_FASTCLOSE);
msk->last_snd = NULL; msk->last_snd = NULL;
WRITE_ONCE(msk->flags, 0); WRITE_ONCE(msk->flags, 0);
msk->cb_flags = 0; msk->cb_flags = 0;
...@@ -3051,12 +3039,17 @@ static struct sock *mptcp_accept(struct sock *sk, int flags, int *err, ...@@ -3051,12 +3039,17 @@ static struct sock *mptcp_accept(struct sock *sk, int flags, int *err,
return newsk; return newsk;
} }
void mptcp_destroy_common(struct mptcp_sock *msk) void mptcp_destroy_common(struct mptcp_sock *msk, unsigned int flags)
{ {
struct mptcp_subflow_context *subflow, *tmp;
struct sock *sk = (struct sock *)msk; struct sock *sk = (struct sock *)msk;
__mptcp_clear_xmit(sk); __mptcp_clear_xmit(sk);
/* join list will be eventually flushed (with rst) at sock lock release time */
list_for_each_entry_safe(subflow, tmp, &msk->conn_list, node)
__mptcp_close_ssk(sk, mptcp_subflow_tcp_sock(subflow), subflow, flags);
/* move to sk_receive_queue, sk_stream_kill_queues will purge it */ /* move to sk_receive_queue, sk_stream_kill_queues will purge it */
mptcp_data_lock(sk); mptcp_data_lock(sk);
skb_queue_splice_tail_init(&msk->receive_queue, &sk->sk_receive_queue); skb_queue_splice_tail_init(&msk->receive_queue, &sk->sk_receive_queue);
...@@ -3078,7 +3071,11 @@ static void mptcp_destroy(struct sock *sk) ...@@ -3078,7 +3071,11 @@ static void mptcp_destroy(struct sock *sk)
{ {
struct mptcp_sock *msk = mptcp_sk(sk); struct mptcp_sock *msk = mptcp_sk(sk);
mptcp_destroy_common(msk); /* clears msk->subflow, allowing the following to close
* even the initial subflow
*/
mptcp_dispose_initial_subflow(msk);
mptcp_destroy_common(msk, 0);
sk_sockets_allocated_dec(sk); sk_sockets_allocated_dec(sk);
} }
......
...@@ -624,16 +624,19 @@ void mptcp_info2sockaddr(const struct mptcp_addr_info *info, ...@@ -624,16 +624,19 @@ void mptcp_info2sockaddr(const struct mptcp_addr_info *info,
struct sockaddr_storage *addr, struct sockaddr_storage *addr,
unsigned short family); unsigned short family);
static inline bool __mptcp_subflow_active(struct mptcp_subflow_context *subflow) static inline bool __tcp_can_send(const struct sock *ssk)
{ {
struct sock *ssk = mptcp_subflow_tcp_sock(subflow); /* only send if our side has not closed yet */
return ((1 << inet_sk_state_load(ssk)) & (TCPF_ESTABLISHED | TCPF_CLOSE_WAIT));
}
static inline bool __mptcp_subflow_active(struct mptcp_subflow_context *subflow)
{
/* can't send if JOIN hasn't completed yet (i.e. is usable for mptcp) */ /* can't send if JOIN hasn't completed yet (i.e. is usable for mptcp) */
if (subflow->request_join && !subflow->fully_established) if (subflow->request_join && !subflow->fully_established)
return false; return false;
/* only send if our side has not closed yet */ return __tcp_can_send(mptcp_subflow_tcp_sock(subflow));
return ((1 << ssk->sk_state) & (TCPF_ESTABLISHED | TCPF_CLOSE_WAIT));
} }
void mptcp_subflow_set_active(struct mptcp_subflow_context *subflow); void mptcp_subflow_set_active(struct mptcp_subflow_context *subflow);
...@@ -717,7 +720,7 @@ static inline void mptcp_write_space(struct sock *sk) ...@@ -717,7 +720,7 @@ static inline void mptcp_write_space(struct sock *sk)
} }
} }
void mptcp_destroy_common(struct mptcp_sock *msk); void mptcp_destroy_common(struct mptcp_sock *msk, unsigned int flags);
#define MPTCP_TOKEN_MAX_RETRIES 4 #define MPTCP_TOKEN_MAX_RETRIES 4
......
...@@ -621,7 +621,8 @@ static void mptcp_sock_destruct(struct sock *sk) ...@@ -621,7 +621,8 @@ static void mptcp_sock_destruct(struct sock *sk)
sock_orphan(sk); sock_orphan(sk);
} }
mptcp_destroy_common(mptcp_sk(sk)); /* We don't need to clear msk->subflow, as it's still NULL at this point */
mptcp_destroy_common(mptcp_sk(sk), 0);
inet_sock_destruct(sk); inet_sock_destruct(sk);
} }
......
...@@ -553,6 +553,18 @@ static void set_nonblock(int fd, bool nonblock) ...@@ -553,6 +553,18 @@ static void set_nonblock(int fd, bool nonblock)
fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
} }
static void shut_wr(int fd)
{
/* Close our write side, ev. give some time
* for address notification and/or checking
* the current status
*/
if (cfg_wait)
usleep(cfg_wait);
shutdown(fd, SHUT_WR);
}
static int copyfd_io_poll(int infd, int peerfd, int outfd, bool *in_closed_after_out) static int copyfd_io_poll(int infd, int peerfd, int outfd, bool *in_closed_after_out)
{ {
struct pollfd fds = { struct pollfd fds = {
...@@ -630,14 +642,7 @@ static int copyfd_io_poll(int infd, int peerfd, int outfd, bool *in_closed_after ...@@ -630,14 +642,7 @@ static int copyfd_io_poll(int infd, int peerfd, int outfd, bool *in_closed_after
/* ... and peer also closed already */ /* ... and peer also closed already */
break; break;
/* ... but we still receive. shut_wr(peerfd);
* Close our write side, ev. give some time
* for address notification and/or checking
* the current status
*/
if (cfg_wait)
usleep(cfg_wait);
shutdown(peerfd, SHUT_WR);
} else { } else {
if (errno == EINTR) if (errno == EINTR)
continue; continue;
...@@ -767,7 +772,7 @@ static int copyfd_io_mmap(int infd, int peerfd, int outfd, ...@@ -767,7 +772,7 @@ static int copyfd_io_mmap(int infd, int peerfd, int outfd,
if (err) if (err)
return err; return err;
shutdown(peerfd, SHUT_WR); shut_wr(peerfd);
err = do_recvfile(peerfd, outfd); err = do_recvfile(peerfd, outfd);
*in_closed_after_out = true; *in_closed_after_out = true;
...@@ -791,6 +796,9 @@ static int copyfd_io_sendfile(int infd, int peerfd, int outfd, ...@@ -791,6 +796,9 @@ static int copyfd_io_sendfile(int infd, int peerfd, int outfd,
err = do_sendfile(infd, peerfd, size); err = do_sendfile(infd, peerfd, size);
if (err) if (err)
return err; return err;
shut_wr(peerfd);
err = do_recvfile(peerfd, outfd); err = do_recvfile(peerfd, outfd);
*in_closed_after_out = true; *in_closed_after_out = true;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment