ACK/Cmnt: [SRU][J][PATCH 1/1] mptcp: move subflow cleanup in mptcp_destroy_common()
Andrei Gherzan
andrei.gherzan at canonical.com
Tue Sep 15 18:41:34 UTC 2026
On 26/09/10 06:35AM, Cengiz Can via kernel-team wrote:
> From: Paolo Abeni <pabeni at redhat.com>
>
> If the mptcp socket creation fails due to a CGROUP_INET_SOCK_CREATE
> eBPF program, the MPTCP protocol ends-up leaking all the subflows:
> the related cleanup happens in __mptcp_destroy_sock() that is not
> invoked in such code path.
>
> Address the issue moving the subflow sockets cleanup in the
> mptcp_destroy_common() helper, which is invoked in every msk cleanup
> path.
>
> Additionally get rid of the intermediate list_splice_init step, which
> is an unneeded relic from the past.
>
> The issue is present since before the reported root cause commit, but
> any attempt to backport the fix before that hash will require a complete
> rewrite.
>
> Fixes: e16163b6e2 ("mptcp: refactor shutdown and close")
> Reported-by: Nguyen Dinh Phi <phind.uet at gmail.com>
> Reviewed-by: Mat Martineau <mathew.j.martineau at linux.intel.com>
> Co-developed-by: Nguyen Dinh Phi <phind.uet at gmail.com>
> Signed-off-by: Nguyen Dinh Phi <phind.uet at gmail.com>
> Signed-off-by: Paolo Abeni <pabeni at redhat.com>
> Signed-off-by: Mat Martineau <mathew.j.martineau at linux.intel.com>
> Signed-off-by: David S. Miller <davem at davemloft.net>
> (backported from commit c0bf3c6aa444a5ef44acc57ef6cfa53fd4fc1c9b)
> [bot_kybele: This tree's __mptcp_close_ssk is 3-arg (no
> flags/MPTCP_CF_FASTCLOSE) so mptcp_destroy_common keeps the added flags param
> but calls the 3-arg form; __mptcp_destroy_sock keeps its join_list->conn_list
> splice (subflows now closed by mptcp_destroy_common via sk_prot->destroy) and
> the sk_stop_timer idiom instead of mptcp_stop_timer; mptcp_disconnect here uses
> tcp_disconnect() per subflow and never calls mptcp_destroy_common, so its
> upstream hunk was not applicable and HEAD was kept.]
> CVE-2022-50071
> Assisted-by: kybele:claude-opus-4.8
> Signed-off-by: Cengiz Can <cengiz.can at canonical.com>
> ---
> net/mptcp/protocol.c | 27 +++++++++++++++------------
> net/mptcp/protocol.h | 2 +-
> net/mptcp/subflow.c | 3 ++-
> 3 files changed, 18 insertions(+), 14 deletions(-)
>
> diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
> index 26d32af7a43f..25ff5be71f57 100644
> --- a/net/mptcp/protocol.c
> +++ b/net/mptcp/protocol.c
> @@ -2806,31 +2806,25 @@ 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\n", msk);
>
> might_sleep();
>
> - /* be sure to always acquire the join list lock, to sync vs
> - * mptcp_finish_join().
> + /* join list will be eventually flushed (with rst) at sock lock
> + * release time; be sure to always acquire the join list lock, to
> + * sync vs mptcp_finish_join(). The actual subflow cleanup is now
> + * performed by mptcp_destroy_common() via sk->sk_prot->destroy().
> */
> spin_lock_bh(&msk->join_list_lock);
> list_splice_tail_init(&msk->join_list, &msk->conn_list);
> spin_unlock_bh(&msk->join_list_lock);
> - list_splice_init(&msk->conn_list, &conn_list);
>
> sk_stop_timer(sk, &msk->sk.icsk_retransmit_timer);
> sk_stop_timer(sk, &sk->sk_timer);
> msk->pm.status = 0;
>
> - list_for_each_entry_safe(subflow, tmp, &conn_list, node) {
> - struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
> - __mptcp_close_ssk(sk, ssk, subflow);
> - }
> -
> sk->sk_prot->destroy(sk);
>
> WARN_ON_ONCE(msk->wmem_reserved);
> @@ -3122,12 +3116,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)
I can't see where `flags` is used in the function. On the other hand, cleaning
this up would be an "unforced" change.
Acked-by: Andrei Gherzan <andrei.gherzan at canonical.com>
> {
> + 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);
> +
> /* move to sk_receive_queue, sk_stream_kill_queues will purge it */
> skb_queue_splice_tail_init(&msk->receive_queue, &sk->sk_receive_queue);
>
> @@ -3140,7 +3139,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);
> }
>
> diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
> index 5492c67ecc9a..30d8760f9060 100644
> --- a/net/mptcp/protocol.h
> +++ b/net/mptcp/protocol.h
> @@ -710,7 +710,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
>
> diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c
> index 6dc26d9d283a..0a2336603550 100644
> --- a/net/mptcp/subflow.c
> +++ b/net/mptcp/subflow.c
> @@ -616,7 +616,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);
> }
--
Andrei Gherzan
gpg: rsa4096/D4D94F67AD0E9640
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <https://lists.ubuntu.com/archives/kernel-team/attachments/20260915/05540769/attachment-0001.sig>
More information about the kernel-team
mailing list