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

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
Loading
Loading
Loading
Loading
+22 −25
Original line number Diff line number Diff line
@@ -1240,6 +1240,9 @@ static int mptcp_sendmsg_frag(struct sock *sk, struct sock *ssk,
			 info->limit > dfrag->data_len))
		return 0;

	if (unlikely(!__tcp_can_send(ssk)))
		return -EAGAIN;

	/* compute send limit */
	info->mss_now = tcp_send_mss(ssk, &info->size_goal, info->flags);
	copy = info->size_goal;
@@ -1413,7 +1416,8 @@ static struct sock *mptcp_subflow_get_send(struct mptcp_sock *msk)
	if (__mptcp_check_fallback(msk)) {
		if (!msk->first)
			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 */
@@ -1564,6 +1568,8 @@ void __mptcp_push_pending(struct sock *sk, unsigned int flags)

			ret = mptcp_sendmsg_frag(sk, ssk, dfrag, &info);
			if (ret <= 0) {
				if (ret == -EAGAIN)
					continue;
				mptcp_push_release(ssk, &info);
				goto out;
			}
@@ -2769,30 +2775,16 @@ static void __mptcp_wr_shutdown(struct sock *sk)

static void __mptcp_destroy_sock(struct sock *sk)
{
	struct mptcp_subflow_context *subflow, *tmp;
	struct mptcp_sock *msk = mptcp_sk(sk);
	LIST_HEAD(conn_list);

	pr_debug("msk=%p", msk);

	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);
	sk_stop_timer(sk, &sk->sk_timer);
	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);

	WARN_ON_ONCE(msk->rmem_fwd_alloc);
@@ -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)
{
	struct mptcp_subflow_context *subflow, *tmp;
	struct mptcp_sock *msk = mptcp_sk(sk);

	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);
	sk_stop_timer(sk, &sk->sk_timer);

	if (mptcp_sk(sk)->token)
		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;
	WRITE_ONCE(msk->flags, 0);
	msk->cb_flags = 0;
@@ -3051,12 +3039,17 @@ static struct sock *mptcp_accept(struct sock *sk, int flags, int *err,
	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;

	__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 */
	mptcp_data_lock(sk);
	skb_queue_splice_tail_init(&msk->receive_queue, &sk->sk_receive_queue);
@@ -3078,7 +3071,11 @@ static void mptcp_destroy(struct sock *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);
}

+8 −5
Original line number Diff line number Diff line
@@ -624,16 +624,19 @@ void mptcp_info2sockaddr(const struct mptcp_addr_info *info,
			 struct sockaddr_storage *addr,
			 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) */
	if (subflow->request_join && !subflow->fully_established)
		return false;

	/* only send if our side has not closed yet */
	return ((1 << ssk->sk_state) & (TCPF_ESTABLISHED | TCPF_CLOSE_WAIT));
	return __tcp_can_send(mptcp_subflow_tcp_sock(subflow));
}

void mptcp_subflow_set_active(struct mptcp_subflow_context *subflow);
@@ -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

+2 −1
Original line number Diff line number Diff line
@@ -621,7 +621,8 @@ static void mptcp_sock_destruct(struct sock *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);
}

+17 −9
Original line number Diff line number Diff line
@@ -553,6 +553,18 @@ static void set_nonblock(int fd, bool 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)
{
	struct pollfd fds = {
@@ -630,14 +642,7 @@ static int copyfd_io_poll(int infd, int peerfd, int outfd, bool *in_closed_after
					/* ... and peer also closed already */
					break;

				/* ... but we still receive.
				 * 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);
				shut_wr(peerfd);
			} else {
				if (errno == EINTR)
					continue;
@@ -767,7 +772,7 @@ static int copyfd_io_mmap(int infd, int peerfd, int outfd,
		if (err)
			return err;

		shutdown(peerfd, SHUT_WR);
		shut_wr(peerfd);

		err = do_recvfile(peerfd, outfd);
		*in_closed_after_out = true;
@@ -791,6 +796,9 @@ static int copyfd_io_sendfile(int infd, int peerfd, int outfd,
		err = do_sendfile(infd, peerfd, size);
		if (err)
			return err;

		shut_wr(peerfd);

		err = do_recvfile(peerfd, outfd);
		*in_closed_after_out = true;
	}