| From 9f1a98813b4b686482e5ef3c9d998581cace0ba6 Mon Sep 17 00:00:00 2001 |
| From: Paolo Abeni <pabeni@redhat.com> |
| Date: Sat, 16 Sep 2023 12:52:47 +0200 |
| Subject: mptcp: process pending subflow error on close |
| |
| From: Paolo Abeni <pabeni@redhat.com> |
| |
| commit 9f1a98813b4b686482e5ef3c9d998581cace0ba6 upstream. |
| |
| On incoming TCP reset, subflow closing could happen before error |
| propagation. That in turn could cause the socket error being ignored, |
| and a missing socket state transition, as reported by Daire-Byrne. |
| |
| Address the issues explicitly checking for subflow socket error at |
| close time. To avoid code duplication, factor-out of __mptcp_error_report() |
| a new helper implementing the relevant bits. |
| |
| Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/429 |
| Fixes: 15cc10453398 ("mptcp: deliver ssk errors to msk") |
| Cc: stable@vger.kernel.org |
| Signed-off-by: Paolo Abeni <pabeni@redhat.com> |
| Reviewed-by: Mat Martineau <martineau@kernel.org> |
| Signed-off-by: Matthieu Baerts <matthieu.baerts@tessares.net> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| net/mptcp/protocol.c | 63 +++++++++++++++++++++++++++------------------------ |
| 1 file changed, 34 insertions(+), 29 deletions(-) |
| |
| --- a/net/mptcp/protocol.c |
| +++ b/net/mptcp/protocol.c |
| @@ -772,40 +772,44 @@ static bool __mptcp_ofo_queue(struct mpt |
| return moved; |
| } |
| |
| -void __mptcp_error_report(struct sock *sk) |
| +static bool __mptcp_subflow_error_report(struct sock *sk, struct sock *ssk) |
| { |
| - struct mptcp_subflow_context *subflow; |
| - struct mptcp_sock *msk = mptcp_sk(sk); |
| + int err = sock_error(ssk); |
| + int ssk_state; |
| |
| - mptcp_for_each_subflow(msk, subflow) { |
| - struct sock *ssk = mptcp_subflow_tcp_sock(subflow); |
| - int err = sock_error(ssk); |
| - int ssk_state; |
| + if (!err) |
| + return false; |
| |
| - if (!err) |
| - continue; |
| + /* only propagate errors on fallen-back sockets or |
| + * on MPC connect |
| + */ |
| + if (sk->sk_state != TCP_SYN_SENT && !__mptcp_check_fallback(mptcp_sk(sk))) |
| + return false; |
| |
| - /* only propagate errors on fallen-back sockets or |
| - * on MPC connect |
| - */ |
| - if (sk->sk_state != TCP_SYN_SENT && !__mptcp_check_fallback(msk)) |
| - continue; |
| + /* We need to propagate only transition to CLOSE state. |
| + * Orphaned socket will see such state change via |
| + * subflow_sched_work_if_closed() and that path will properly |
| + * destroy the msk as needed. |
| + */ |
| + ssk_state = inet_sk_state_load(ssk); |
| + if (ssk_state == TCP_CLOSE && !sock_flag(sk, SOCK_DEAD)) |
| + inet_sk_state_store(sk, ssk_state); |
| + WRITE_ONCE(sk->sk_err, -err); |
| + |
| + /* This barrier is coupled with smp_rmb() in mptcp_poll() */ |
| + smp_wmb(); |
| + sk_error_report(sk); |
| + return true; |
| +} |
| |
| - /* We need to propagate only transition to CLOSE state. |
| - * Orphaned socket will see such state change via |
| - * subflow_sched_work_if_closed() and that path will properly |
| - * destroy the msk as needed. |
| - */ |
| - ssk_state = inet_sk_state_load(ssk); |
| - if (ssk_state == TCP_CLOSE && !sock_flag(sk, SOCK_DEAD)) |
| - inet_sk_state_store(sk, ssk_state); |
| - WRITE_ONCE(sk->sk_err, -err); |
| - |
| - /* This barrier is coupled with smp_rmb() in mptcp_poll() */ |
| - smp_wmb(); |
| - sk_error_report(sk); |
| - break; |
| - } |
| +void __mptcp_error_report(struct sock *sk) |
| +{ |
| + struct mptcp_subflow_context *subflow; |
| + struct mptcp_sock *msk = mptcp_sk(sk); |
| + |
| + mptcp_for_each_subflow(msk, subflow) |
| + if (__mptcp_subflow_error_report(sk, mptcp_subflow_tcp_sock(subflow))) |
| + break; |
| } |
| |
| /* In most cases we will be able to lock the mptcp socket. If its already |
| @@ -2417,6 +2421,7 @@ static void __mptcp_close_ssk(struct soc |
| } |
| |
| out_release: |
| + __mptcp_subflow_error_report(sk, ssk); |
| release_sock(ssk); |
| |
| sock_put(ssk); |