summaryrefslogtreecommitdiffstats
path: root/net/mptcp
diff options
context:
space:
mode:
authorPaolo Abeni <pabeni@redhat.com>2020-10-06 08:27:34 +0200
committerJakub Kicinski <kuba@kernel.org>2020-10-08 17:24:04 -0700
commitd9fb8c507d42256034b457ec59347855bec9e569 (patch)
treeea28f4211367233c1b9cc584930d32070b635750 /net/mptcp
parent0eb484ee49c90581af87152df43a119cbe7a2e5f (diff)
downloadlinux-d9fb8c507d42256034b457ec59347855bec9e569.tar.gz
linux-d9fb8c507d42256034b457ec59347855bec9e569.tar.bz2
linux-d9fb8c507d42256034b457ec59347855bec9e569.zip
mptcp: fix infinite loop on recvmsg()/worker() race.
If recvmsg() and the workqueue race to dequeue the data pending on some subflow, the current mapping for such subflow covers several skbs and some of them have not reached yet the received, either the worker or recvmsg() can find a subflow with the data_avail flag set - since the current mapping is valid and in sequence - but no skbs in the receive queue - since the other entity just processed them. The above will lead to an unbounded loop in __mptcp_move_skbs() and a subsequent hang of any task trying to acquiring the msk socket lock. This change addresses the issue stopping the __mptcp_move_skbs() loop as soon as we detect the above race (empty receive queue with data_avail set). Reported-and-tested-by: syzbot+fcf8ca5817d6e92c6567@syzkaller.appspotmail.com Fixes: ab174ad8ef76 ("mptcp: move ooo skbs into msk out of order queue.") Signed-off-by: Paolo Abeni <pabeni@redhat.com> Reviewed-by: Mat Martineau <mathew.j.martineau@linux.intel.com> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Diffstat (limited to 'net/mptcp')
-rw-r--r--net/mptcp/protocol.c9
1 files changed, 8 insertions, 1 deletions
diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index f893985f37d3..9816608da452 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -471,8 +471,15 @@ static bool __mptcp_move_skbs_from_subflow(struct mptcp_sock *msk,
mptcp_subflow_get_map_offset(subflow);
skb = skb_peek(&ssk->sk_receive_queue);
- if (!skb)
+ if (!skb) {
+ /* if no data is found, a racing workqueue/recvmsg
+ * already processed the new data, stop here or we
+ * can enter an infinite loop
+ */
+ if (!moved)
+ done = true;
break;
+ }
if (__mptcp_check_fallback(msk)) {
/* if we are running under the workqueue, TCP could have