MPTCP Linux Development
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Geliang Tang" <geliang@kernel.org>, mptcp@lists.linux.dev
Subject: Re: [PATCH mptcp-next v2 1/4] mptcp: give MPTCP sockets a distinct lockdep class
Date: Mon, 26 Oct 2026 11:27:02 +0000	[thread overview]
Message-ID: <sashiko-outbox-185097@kernel.org> (raw)
In-Reply-To: <a17b9360df88d22c8ed579f532c41456fc46006e.1793010744.git.tanggeliang@kylinos.cn>

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] mptcp: race on sk_lock reinit and unlocked clone with SLAB_TYPESAFE_BY_RCU
--

commit 1535a4c9bef6857111a0222f084ae0666d8e7461
Author: Geliang Tang <geliang@kernel.org>

mptcp: give MPTCP sockets a distinct lockdep class

This commit introduces mptcp_reclassify_socket() to assign distinct lockdep
classes to MPTCP sockets based on address family and kernel vs user socket
type. It calls this helper from mptcp_init_sock() and from
mptcp_sk_clone_init() after switching from sk_clone_lock() to unlocked
sk_clone().

> diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
> index 02a4f479d9d8c..d4f42dfc227e2 100644
> --- a/net/mptcp/protocol.c
> +++ b/net/mptcp/protocol.c
> @@ -3267,11 +3267,43 @@ static void mptcp_ca_reset(struct sock *sk)
>  	icsk->icsk_ca_ops = NULL;
>  }
>  
> +/* The subflow socket lock is acquired in a nested to the msk one
> + * in several places, even by the TCP stack: lockdep complains when
> + * both are kernel sockets. Instead of propagating the _nested modifiers
> + * in several places, re-init the lock class for the msk socket to an
> + * mptcp specific one. Separate lock classes are used for kernel and
> + * user sockets to prevent lockdep from conflating their usage patterns.
> + */
> +static struct lock_class_key mptcp_slock_keys[2][2];
> +static struct lock_class_key mptcp_keys[2][2];
> +
> +static void mptcp_reclassify_socket(struct sock *sk)
> +{
> +	bool is_ipv6 = sk->sk_family == AF_INET6;
> +	const char *slock_name, *lock_name;
> +	bool is_kern = !!sk->sk_kern_sock;
> +
> +	if (is_kern) {
> +		slock_name = is_ipv6 ? "kmlock-AF_INET6" : "kmlock-AF_INET";
> +		lock_name = is_ipv6 ? "kmsk_lock-AF_INET6" :
> +				      "kmsk_lock-AF_INET";
> +	} else {
> +		slock_name = is_ipv6 ? "mlock-AF_INET6" : "mlock-AF_INET";
> +		lock_name = is_ipv6 ? "msk_lock-AF_INET6" : "msk_lock-AF_INET";
> +	}
> +
> +	sock_lock_init_class_and_name(sk, slock_name,
> +				      &mptcp_slock_keys[is_kern][is_ipv6],
> +				      lock_name, &mptcp_keys[is_kern][is_ipv6]);
> +}
> +
>  static int mptcp_init_sock(struct sock *sk)
>  {
>  	struct net *net = sock_net(sk);
>  	int ret;
>  
> +	mptcp_reclassify_socket(sk);
> +
>  	__mptcp_init_sock(sk);
>  
>  	if (!mptcp_is_enabled(net))
> @@ -3772,13 +3804,16 @@ struct sock *mptcp_sk_clone_init(const struct sock *sk,
>  				 struct request_sock *req)
>  {
>  	struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req);
> -	struct sock *nsk = sk_clone_lock(sk, GFP_ATOMIC);
> +	struct sock *nsk = sk_clone(sk, GFP_ATOMIC, false);
>  	struct mptcp_subflow_context *subflow;
>  	struct mptcp_sock *msk;
>  
>  	if (!nsk)
>  		return NULL;
>  
> +	mptcp_reclassify_socket(nsk);
> +
> +	bh_lock_sock(nsk);

[Severity: High]
Can calling mptcp_reclassify_socket() and unlocked sk_clone() race with
lockless RCU readers on SLAB_TYPESAFE_BY_RCU MPTCP sockets?

Both mptcp_prot and mptcp_v6_prot use SLAB_TYPESAFE_BY_RCU, and accepted
MPTCP sockets clear SOCK_RCU_FREE in mptcp_sk_clone_init(), so a closed
mptcp_sock can be immediately recycled from the slab cache while a
concurrent RCU reader in mptcp_token_iter_next() or mptcp_token_get_sock()
is walking bucket->msk_chain:

net/mptcp/token.c:mptcp_token_iter_next() {
	...
	rcu_read_lock();
	sk_nulls_for_each_rcu(sk, pos, &bucket->msk_chain) {
		++num;
		if (!net_eq(sock_net(sk), net))
			continue;

		if (num <= *s_num)
			continue;

		if (!refcount_inc_not_zero(&sk->sk_refcnt))
			continue;
	...
}

Once refcount_inc_not_zero(&sk->sk_refcnt) succeeds on the recycled socket,
callers of mptcp_token_iter_next() (such as mptcp_diag_dump(),
mptcp_nl_remove_subflow_and_signal_addr(), mptcp_nl_remove_id_zero_address(),
mptcp_nl_flush_addrs_list(), and mptcp_nl_set_flags()) immediately call
lock_sock(sk) or lock_sock_fast(sk).

In mptcp_sk_clone_init(), sk_clone_lock() previously initialized newsk's
lock and acquired bh_lock_sock(newsk) before setting newsk->sk_refcnt to 2:

net/core/sock.c:sk_clone() {
	...
	sock_lock_init(newsk);

	if (lock)
		bh_lock_sock(newsk);
	...
	smp_wmb();
	refcount_set(&newsk->sk_refcnt, 2);
}

Holding bh_lock_sock(newsk) before sk_refcnt became non-zero serialized any
concurrent lock_sock() or lock_sock_fast() reader until __mptcp_init_sock()
completed and bh_unlock_sock(nsk) was called.

With sk_clone(sk, GFP_ATOMIC, false), nsk->sk_refcnt becomes 2 while nsk is
unlocked. Can a concurrent RCU reader grab a reference on nsk and call
lock_sock(nsk) or lock_sock_fast(nsk):

1. Concurrently with mptcp_reclassify_socket(nsk) (and similarly in
   mptcp_init_sock() after sock_init_data() has set sk->sk_refcnt to 1),
   where sock_lock_init_class_and_name() zeroes sk_lock.owned and
   re-initializes sk_lock.wq, sk_lock.slock, and the lockdep maps while
   another CPU is acquiring or holding sk_lock?

2. In mptcp_sk_clone_init(), after mptcp_reclassify_socket(nsk) finishes
   and before bh_lock_sock(nsk) is called? If the reader acquires
   lock_sock(nsk) first, it sets nsk->sk_lock.owned = 1 and drops
   nsk->sk_lock.slock, which does not prevent bh_lock_sock(nsk) from
   proceeding into __mptcp_init_sock(nsk) concurrently, and the reader can
   iterate msk->conn_list while it still contains the raw copy of the
   listening socket's list head from sock_copy()?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/cover.1793010744.git.tanggeliang@kylinos.cn?part=1

  reply	other threads:[~2026-10-26 11:27 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-26 10:35 [PATCH mptcp-next v2 0/4] Add MPTCP support for NBD Geliang Tang
2026-10-26 10:35 ` [PATCH mptcp-next v2 1/4] mptcp: give MPTCP sockets a distinct lockdep class Geliang Tang
2026-10-26 11:27   ` sashiko-bot [this message]
2026-10-26 10:35 ` [PATCH mptcp-next v2 2/4] sock: add set_memalloc protocol callback Geliang Tang
2026-10-26 11:46   ` sashiko-bot
2026-10-26 10:35 ` [PATCH mptcp-next v2 3/4] nbd: allow MPTCP sockets Geliang Tang
2026-10-26 12:14   ` sashiko-bot
2026-10-26 10:35 ` [PATCH mptcp-next v2 4/4] selftests: mptcp: add mptcp nbd tests Geliang Tang
2026-10-26 12:32   ` sashiko-bot
2026-10-26 12:04 ` [PATCH mptcp-next v2 0/4] Add MPTCP support for NBD MPTCP CI
  -- strict thread matches above, loose matches on Subject: below --
2026-10-27 23:46 [PATCH mptcp-next v2 1/4] mptcp: give MPTCP sockets a distinct lockdep class netdev-bot+sashiko

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=sashiko-outbox-185097@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=geliang@kernel.org \
    --cc=mptcp@lists.linux.dev \
    --cc=sashiko-reviews@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox