mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-13 10:38:44 -04:00
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: David S. Miller <davem@davemloft.net>
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -624,16 +624,19 @@ void mptcp_info2sockaddr(const struct mptcp_addr_info *info,
|
||||
struct sockaddr_storage *addr,
|
||||
unsigned short family);
|
||||
|
||||
static inline bool __tcp_can_send(const struct sock *ssk)
|
||||
{
|
||||
/* 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)
|
||||
{
|
||||
struct sock *ssk = mptcp_subflow_tcp_sock(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
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user