Skip to content

Commit 5969856

Browse files
Paolo Abenidavem330
authored andcommitted
mptcp: fix races between shutdown and recvmsg
The msk sk_shutdown flag is set by a workqueue, possibly introducing some delay in user-space notification. If the last subflow carries some data with the fin packet, the user space can wake-up before RCV_SHUTDOWN is set. If it executes unblocking recvmsg(), it may return with an error instead of eof. Address the issue explicitly checking for eof in recvmsg(), when no data is found. Fixes: 59832e2 ("mptcp: subflow: check parent mptcp socket on subflow state change") Signed-off-by: Paolo Abeni <[email protected]> Reviewed-by: Matthieu Baerts <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 50cb876 commit 5969856

File tree

1 file changed

+24
-21
lines changed

1 file changed

+24
-21
lines changed

net/mptcp/protocol.c

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,27 @@ void mptcp_subflow_eof(struct sock *sk)
374374
sock_hold(sk);
375375
}
376376

377+
static void mptcp_check_for_eof(struct mptcp_sock *msk)
378+
{
379+
struct mptcp_subflow_context *subflow;
380+
struct sock *sk = (struct sock *)msk;
381+
int receivers = 0;
382+
383+
mptcp_for_each_subflow(msk, subflow)
384+
receivers += !subflow->rx_eof;
385+
386+
if (!receivers && !(sk->sk_shutdown & RCV_SHUTDOWN)) {
387+
/* hopefully temporary hack: propagate shutdown status
388+
* to msk, when all subflows agree on it
389+
*/
390+
sk->sk_shutdown |= RCV_SHUTDOWN;
391+
392+
smp_mb__before_atomic(); /* SHUTDOWN must be visible first */
393+
set_bit(MPTCP_DATA_READY, &msk->flags);
394+
sk->sk_data_ready(sk);
395+
}
396+
}
397+
377398
static void mptcp_stop_timer(struct sock *sk)
378399
{
379400
struct inet_connection_sock *icsk = inet_csk(sk);
@@ -1011,6 +1032,9 @@ static int mptcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
10111032
break;
10121033
}
10131034

1035+
if (test_and_clear_bit(MPTCP_WORK_EOF, &msk->flags))
1036+
mptcp_check_for_eof(msk);
1037+
10141038
if (sk->sk_shutdown & RCV_SHUTDOWN)
10151039
break;
10161040

@@ -1148,27 +1172,6 @@ static unsigned int mptcp_sync_mss(struct sock *sk, u32 pmtu)
11481172
return 0;
11491173
}
11501174

1151-
static void mptcp_check_for_eof(struct mptcp_sock *msk)
1152-
{
1153-
struct mptcp_subflow_context *subflow;
1154-
struct sock *sk = (struct sock *)msk;
1155-
int receivers = 0;
1156-
1157-
mptcp_for_each_subflow(msk, subflow)
1158-
receivers += !subflow->rx_eof;
1159-
1160-
if (!receivers && !(sk->sk_shutdown & RCV_SHUTDOWN)) {
1161-
/* hopefully temporary hack: propagate shutdown status
1162-
* to msk, when all subflows agree on it
1163-
*/
1164-
sk->sk_shutdown |= RCV_SHUTDOWN;
1165-
1166-
smp_mb__before_atomic(); /* SHUTDOWN must be visible first */
1167-
set_bit(MPTCP_DATA_READY, &msk->flags);
1168-
sk->sk_data_ready(sk);
1169-
}
1170-
}
1171-
11721175
static void mptcp_worker(struct work_struct *work)
11731176
{
11741177
struct mptcp_sock *msk = container_of(work, struct mptcp_sock, work);

0 commit comments

Comments
 (0)