Commit de06f573 authored by Florian Westphal's avatar Florian Westphal Committed by David S. Miller

mptcp: re-check dsn before reading from subflow

mptcp_subflow_data_available() is commonly called via
ssk->sk_data_ready(), in this case the mptcp socket lock
cannot be acquired.

Therefore, while we can safely discard subflow data that
was already received up to msk->ack_seq, we cannot be sure
that 'subflow->data_avail' will still be valid at the time
userspace wants to read the data -- a previous read on a
different subflow might have carried this data already.

In that (unlikely) event, msk->ack_seq will have been updated
and will be ahead of the subflow dsn.

We can check for this condition and skip/resync to the expected
sequence number.
Signed-off-by: default avatarFlorian Westphal <fw@strlen.de>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 59832e24
...@@ -158,6 +158,27 @@ static void __mptcp_move_skb(struct mptcp_sock *msk, struct sock *ssk, ...@@ -158,6 +158,27 @@ static void __mptcp_move_skb(struct mptcp_sock *msk, struct sock *ssk,
MPTCP_SKB_CB(skb)->offset = offset; MPTCP_SKB_CB(skb)->offset = offset;
} }
/* both sockets must be locked */
static bool mptcp_subflow_dsn_valid(const struct mptcp_sock *msk,
struct sock *ssk)
{
struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk);
u64 dsn = mptcp_subflow_get_mapped_dsn(subflow);
/* revalidate data sequence number.
*
* mptcp_subflow_data_available() is usually called
* without msk lock. Its unlikely (but possible)
* that msk->ack_seq has been advanced since the last
* call found in-sequence data.
*/
if (likely(dsn == msk->ack_seq))
return true;
subflow->data_avail = 0;
return mptcp_subflow_data_available(ssk);
}
static bool __mptcp_move_skbs_from_subflow(struct mptcp_sock *msk, static bool __mptcp_move_skbs_from_subflow(struct mptcp_sock *msk,
struct sock *ssk, struct sock *ssk,
unsigned int *bytes) unsigned int *bytes)
...@@ -169,6 +190,11 @@ static bool __mptcp_move_skbs_from_subflow(struct mptcp_sock *msk, ...@@ -169,6 +190,11 @@ static bool __mptcp_move_skbs_from_subflow(struct mptcp_sock *msk,
struct tcp_sock *tp; struct tcp_sock *tp;
bool done = false; bool done = false;
if (!mptcp_subflow_dsn_valid(msk, ssk)) {
*bytes = 0;
return false;
}
if (!(sk->sk_userlocks & SOCK_RCVBUF_LOCK)) { if (!(sk->sk_userlocks & SOCK_RCVBUF_LOCK)) {
int rcvbuf = max(ssk->sk_rcvbuf, sk->sk_rcvbuf); int rcvbuf = max(ssk->sk_rcvbuf, sk->sk_rcvbuf);
......
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