* [PATCH net v3 1/4] net: mptcp: take token lookup references with acquire ordering
[not found] <20261114130927.91839-1-2122295973@qq.com>
@ 2026-11-14 13:09 ` Hang Nan
2026-11-14 13:09 ` [PATCH net v3 2/4] net: core: take the reuseport migration reference " Hang Nan
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Hang Nan @ 2026-11-14 13:09 UTC (permalink / raw)
To: netdev
Cc: mptcp, matttbe, martineau, geliang, davem, edumazet, kuba, pabeni,
horms, kuniyu, willemb, linux-kernel, stable, 2122295973
mptcp_token_get_sock() and mptcp_token_iter_next() take a reference on a
socket found on an RCU-protected hash chain and then re-read state to
decide whether that socket is the one they were looking for. The
re-validation is only meaningful if it is ordered after the reference
acquisition.
The sockets come from mptcp_prot.slab, which is SLAB_TYPESAFE_BY_RCU, so
the memory a reader still points at can be freed and reallocated as a new
mptcp socket while the reader is between the chain walk and the
increment. The new owner publishes itself in sock_init_data_uid() with
smp_wmb();
refcount_set(&sk->sk_refcnt, 1);
and initialises the rest of the socket only afterwards. A reader whose
increment does not carry acquire ordering can have the re-read of
msk->token and sock_net(sk) satisfied before the increment, that is
against the old object's contents, while the increment itself succeeds on
the new one. The lookup would then hand back a socket that belongs to a
different connection, or one that is not initialised yet.
refcount_inc_not_zero() has not provided that ordering since
commit fb041bb7c0a9 ("locking/refcount: Consolidate implementations of refcount_t"),
which removed the ordering the previous atomic_add_unless() based
implementation gave; refcount.h names this exact case as the reason the
acquire variants exist.
commit 5b5d8f351dd9 ("net: restore refcount ordering for lockless socket access")
restored the ordering for the IPv4/IPv6 established lookups,
inet_twsk_purge() and bpf_sk_assign(). These two mptcp sites have the
same shape and are converted as well. There is no behaviour change on
strongly ordered CPUs.
Fixes: 2c5ebd001d4f ("mptcp: refactor token container")
Fixes: 96d890daad05 ("mptcp: add msk interations helper")
Cc: stable@vger.kernel.org
Signed-off-by: Hang Nan <2122295973@qq.com>
---
net/mptcp/token.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/net/mptcp/token.c b/net/mptcp/token.c
index e0f2823f92ef..3429b43a9f7c 100644
--- a/net/mptcp/token.c
+++ b/net/mptcp/token.c
@@ -309,7 +309,7 @@ struct mptcp_sock *mptcp_token_get_sock(struct net *net, u32 token)
!net_eq(sock_net(sk), net))
continue;
- if (!refcount_inc_not_zero(&sk->sk_refcnt))
+ if (!refcount_inc_not_zero_acquire(&sk->sk_refcnt))
goto not_found;
if (READ_ONCE(msk->token) != token ||
@@ -370,7 +370,7 @@ struct mptcp_sock *mptcp_token_iter_next(const struct net *net, long *s_slot,
if (num <= *s_num)
continue;
- if (!refcount_inc_not_zero(&sk->sk_refcnt))
+ if (!refcount_inc_not_zero_acquire(&sk->sk_refcnt))
continue;
if (!net_eq(sock_net(sk), net)) {
--
2.47.3
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH net v3 2/4] net: core: take the reuseport migration reference with acquire ordering
[not found] <20261114130927.91839-1-2122295973@qq.com>
2026-11-14 13:09 ` [PATCH net v3 1/4] net: mptcp: take token lookup references with acquire ordering Hang Nan
@ 2026-11-14 13:09 ` Hang Nan
2026-11-15 13:09 ` sashiko-bot
2026-11-14 13:09 ` [PATCH net v3 3/4] net: mptcp: reject token 0 in mptcp_token_get_sock() Hang Nan
2026-11-14 13:09 ` [PATCH net v3 4/4] net: mptcp: verify the token slot in mptcp_token_iter_next() Hang Nan
3 siblings, 1 reply; 5+ messages in thread
From: Hang Nan @ 2026-11-14 13:09 UTC (permalink / raw)
To: netdev
Cc: mptcp, matttbe, martineau, geliang, davem, edumazet, kuba, pabeni,
horms, kuniyu, willemb, linux-kernel, stable, 2122295973
reuseport_migrate_sock() returns a listener with a reference held, and
every caller immediately reads that listener: tcp_v4_rcv() and
tcp_v6_rcv() pass it to tcp_filter() and tcp_check_req(), and the
request-socket paths clone its state. A listener removed from the
reuseport group concurrently with that lookup must not be observed in a
half-torn-down state after the reference was successfully taken.
refcount_inc_not_zero() lost its acquire ordering in commit fb041bb7c0a9
("locking/refcount: Consolidate implementations of refcount_t"), so these
subsequent reads are not ordered against the reference acquisition. Use
refcount_inc_not_zero_acquire(), as was done for the established-socket
lookups, inet_twsk_purge() and bpf_sk_assign() in commit 5b5d8f351dd9
("net: restore refcount ordering for lockless socket access").
No behaviour change on strongly ordered architectures.
Fixes: 1cd62c21572c ("tcp: Add reuseport_migrate_sock() to select a new listener.")
Cc: stable@vger.kernel.org
Signed-off-by: Hang Nan <2122295973@qq.com>
---
net/core/sock_reuseport.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/net/core/sock_reuseport.c b/net/core/sock_reuseport.c
index b9e5648fa4c5..56230aa55a3e 100644
--- a/net/core/sock_reuseport.c
+++ b/net/core/sock_reuseport.c
@@ -667,7 +667,8 @@ struct sock *reuseport_migrate_sock(struct sock *sk,
if (!nsk)
nsk = reuseport_select_sock_by_hash(reuse, hash, socks);
- if (IS_ERR_OR_NULL(nsk) || unlikely(!refcount_inc_not_zero(&nsk->sk_refcnt))) {
+ if (IS_ERR_OR_NULL(nsk) ||
+ unlikely(!refcount_inc_not_zero_acquire(&nsk->sk_refcnt))) {
nsk = NULL;
goto failure;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 5+ messages in thread* Re: [PATCH net v3 2/4] net: core: take the reuseport migration reference with acquire ordering
2026-11-14 13:09 ` [PATCH net v3 2/4] net: core: take the reuseport migration reference " Hang Nan
@ 2026-11-15 13:09 ` sashiko-bot
0 siblings, 0 replies; 5+ messages in thread
From: sashiko-bot @ 2026-11-15 13:09 UTC (permalink / raw)
To: Hang Nan; +Cc: mptcp
Thank you for your contribution! Sashiko AI review found 1 potential
issue to consider:
- [Low] net: unnecessary refcount_inc_not_zero_acquire() in
reuseport_migrate_sock()
--
commit 451ae80ccee42826773bf0a6549978307e27e9aa
Author: Hang Nan <2122295973@qq.com>
net: core: take the reuseport migration reference with acquire ordering
This commit switches reuseport_migrate_sock() from refcount_inc_not_zero()
to refcount_inc_not_zero_acquire() when taking a reference on the selected
listener socket.
> diff --git a/net/core/sock_reuseport.c b/net/core/sock_reuseport.c
> index b9e5648fa4c51..56230aa55a3e2 100644
> --- a/net/core/sock_reuseport.c
> +++ b/net/core/sock_reuseport.c
> @@ -667,7 +667,8 @@ struct sock *reuseport_migrate_sock(struct sock *sk,
> if (!nsk)
> nsk = reuseport_select_sock_by_hash(reuse, hash, socks);
>
> - if (IS_ERR_OR_NULL(nsk) || unlikely(!refcount_inc_not_zero(&nsk->sk_refcnt))) {
> + if (IS_ERR_OR_NULL(nsk) ||
> + unlikely(!refcount_inc_not_zero_acquire(&nsk->sk_refcnt))) {
> nsk = NULL;
> goto failure;
> }
[Severity: Low]
Is refcount_inc_not_zero_acquire() needed here?
Listener teardown in __tcp_close() and tcp_disconnect() sets sk->sk_state
to TCP_CLOSE and runs inet_csk_listen_stop() while sk->sk_refcnt is still
non-zero, before the final sock_put(). An acquire barrier on
nsk->sk_refcnt only prevents reordering subsequent reads to before the
increment (which would observe older, pre-teardown state rather than
half-torn-down state), and does not serialize against concurrent listener
teardown; callers instead recheck sk->sk_state != TCP_LISTEN under
queue->rskq_lock in inet_csk_reqsk_queue_add().
Unlike the SLAB_TYPESAFE_BY_RCU lookups updated in 5b5d8f351dd9 ("net:
restore refcount ordering for lockless socket access"), sockets in a
reuseport group are freed via call_rcu() in sk_destruct() and cannot be
reallocated during the rcu_read_lock() section in reuseport_migrate_sock(),
nor does reuseport_migrate_sock() perform post-refcount validation checks
that need to be ordered after taking the reference.
--
Sashiko AI review · https://sashiko.dev/#/patchset/tencent_CCBF2706A4D1AFF8F48632FE8B56FB67E207@qq.com?part=2
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH net v3 3/4] net: mptcp: reject token 0 in mptcp_token_get_sock()
[not found] <20261114130927.91839-1-2122295973@qq.com>
2026-11-14 13:09 ` [PATCH net v3 1/4] net: mptcp: take token lookup references with acquire ordering Hang Nan
2026-11-14 13:09 ` [PATCH net v3 2/4] net: core: take the reuseport migration reference " Hang Nan
@ 2026-11-14 13:09 ` Hang Nan
2026-11-14 13:09 ` [PATCH net v3 4/4] net: mptcp: verify the token slot in mptcp_token_iter_next() Hang Nan
3 siblings, 0 replies; 5+ messages in thread
From: Hang Nan @ 2026-11-14 13:09 UTC (permalink / raw)
To: netdev
Cc: mptcp, matttbe, martineau, geliang, davem, edumazet, kuba, pabeni,
horms, kuniyu, willemb, linux-kernel, stable, 2122295973
Token 0 is never assigned to a connection: __token_bucket_busy() treats
it as busy. It is, however, the value mptcp_token_destroy() stores into a
socket that is being torn down, and the value a freshly allocated msk
holds until it is hashed.
Both validations in mptcp_token_get_sock() compare the socket's token
with the requested one, so for a request for token 0 they cannot tell a
match apart from a socket whose token has just been cleared. With
SLAB_TYPESAFE_BY_RCU the same is true for a socket whose memory has
already been reused by a new msk that has not been hashed yet.
The token comes from the wire: mptcp_parse_option() copies the MP_JOIN
SYN token without validating it. A lookup for token 0 can therefore
return a dying or half-initialised msk, which subflow_token_join_request()
then hands to mptcp_pm_get_local_id() and, when the subflow uses a
different source port, to mptcp_pm_announced_has_ssk(), which walks
msk->pm.anno_list. That list is only initialised later, from
mptcp_pm_data_init().
Reject token 0 before walking the chain.
Fixes: 2c5ebd001d4f ("mptcp: refactor token container")
Cc: stable@vger.kernel.org
Signed-off-by: Hang Nan <2122295973@qq.com>
---
net/mptcp/token.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/net/mptcp/token.c b/net/mptcp/token.c
index 3429b43a9f7c..8a603fc8dc05 100644
--- a/net/mptcp/token.c
+++ b/net/mptcp/token.c
@@ -299,6 +299,10 @@ struct mptcp_sock *mptcp_token_get_sock(struct net *net, u32 token)
struct mptcp_sock *msk;
struct sock *sk;
+ /* Token 0 is never assigned, but is what a torn down socket holds. */
+ if (!token)
+ return NULL;
+
rcu_read_lock();
bucket = token_bucket(token);
--
2.47.3
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH net v3 4/4] net: mptcp: verify the token slot in mptcp_token_iter_next()
[not found] <20261114130927.91839-1-2122295973@qq.com>
` (2 preceding siblings ...)
2026-11-14 13:09 ` [PATCH net v3 3/4] net: mptcp: reject token 0 in mptcp_token_get_sock() Hang Nan
@ 2026-11-14 13:09 ` Hang Nan
3 siblings, 0 replies; 5+ messages in thread
From: Hang Nan @ 2026-11-14 13:09 UTC (permalink / raw)
To: netdev
Cc: mptcp, matttbe, martineau, geliang, davem, edumazet, kuba, pabeni,
horms, kuniyu, willemb, linux-kernel, stable, 2122295973
mptcp_token_iter_next() takes a reference on a socket found on the chain
of the slot it is walking and then re-checks only net_eq(). A socket
that was freed and whose memory has been reused by a new msk in the same
network namespace passes that check while it is still zeroed, and the
callers - mptcp_diag and the userspace path manager - then use mptcp_pm
state that has not been initialised yet.
The token of a socket on a chain always hashes to the slot being walked,
and token 0 is never assigned, so re-read the token after the acquisition
and drop the socket unless it is non-zero and still maps to this slot.
Fixes: 96d890daad05 ("mptcp: add msk interations helper")
Cc: stable@vger.kernel.org
Signed-off-by: Hang Nan <2122295973@qq.com>
---
net/mptcp/token.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/net/mptcp/token.c b/net/mptcp/token.c
index 8a603fc8dc05..48470d6e751d 100644
--- a/net/mptcp/token.c
+++ b/net/mptcp/token.c
@@ -355,6 +355,7 @@ struct mptcp_sock *mptcp_token_iter_next(const struct net *net, long *s_slot,
struct mptcp_sock *ret = NULL;
struct hlist_nulls_node *pos;
int slot, num = 0;
+ u32 token;
for (slot = *s_slot; slot <= token_mask; *s_num = 0, slot++) {
struct token_bucket *bucket = &token_hash[slot];
@@ -377,7 +378,9 @@ struct mptcp_sock *mptcp_token_iter_next(const struct net *net, long *s_slot,
if (!refcount_inc_not_zero_acquire(&sk->sk_refcnt))
continue;
- if (!net_eq(sock_net(sk), net)) {
+ token = READ_ONCE(mptcp_sk(sk)->token);
+ if (!token || (token & token_mask) != slot ||
+ !net_eq(sock_net(sk), net)) {
sock_put(sk);
continue;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 5+ messages in thread