From: netdev-bot+sashiko@kernel.org
To: imv4bel@gmail.com
Cc: edumazet@kernel.org, ncardwell@google.com, kuniyu@google.com,
davem@davemloft.net, kuba@kernel.org, pabeni@redhat.com,
horms@kernel.org, martin.lau@linux.dev, john.fastabend@gmail.com,
weiwan@google.com, sd@queasysnail.net, jiayuan.chen@linux.dev,
netdev@vger.kernel.org, stable@vger.kernel.org
Subject: Re: [PATCH net v3 2/2] inet: restore refcount ordering for established lookups
Date: Sun, 25 Oct 2026 05:40:28 +0000 [thread overview]
Message-ID: <179290682873.3134.10437749263853370498@kernel.org> (raw)
In-Reply-To: <20261024053720.1147022-3-imv4bel@gmail.com>
Thank you for your contribution! Sashiko AI review found 5 potential
issue(s) to consider.
Critical: 0 · High: 1 · Medium: 0 (1) · Low: 4
If you believe none of the issues are legitimate, please reply to each
issue of Medium severity or higher and explain why the AI is wrong.
If any of them are legitimate and you plan to respin, please let patchwork
know by including "pw-bot: cr" as a separate line at the end of your reply
(one such reply per series is enough).
- [High] inet_twsk_purge() (net/ipv4/inet_timewait_sock.c) was left
unconverted, so the fix is incomplete.
- [Low] The patch carries 'Cc: stable@vger.kernel.org' and 'Fixes:
fb041bb7c0a9' (v5.5), but the fix depends on…
- [Low] Commit message accuracy.
- [Low] Several converted sites do not follow refcount_set_release()'s
kernel-doc contract: 'This function should be called only after new…
- [Low] In reqsk_timer_handler() the patch moves
timer_setup(&nreq->rsk_timer, ...) ahead of the refcount store, and…
Pre-existing issues:
- [Medium] Same ordering bug in MPTCP token lookups.
--
inet: restore refcount ordering for established lookups
This patch makes the IPv4 and IPv6 established hash lookups use
refcount_inc_not_zero_acquire(). It also converts refcount_set() to
refcount_set_release() in the SYN cookie, TCP Fast Open, request
migration and TIME_WAIT paths. The goal is to bring back ordering that
was lost when fb041bb7c0a9 made refcount_inc_not_zero() relaxed on
success.
> inet: restore refcount ordering for established lookups
>
> Before commit fb041bb7c0a9 ("locking/refcount: Consolidate implementations
> of refcount_t"), default builds implemented refcount_inc_not_zero() using
> atomic_add_unless(), which provided full memory ordering on success. The
> commit removed that ordering on weakly ordered architectures, allowing
> validation in established lookups to be reordered before a successful
> reference acquisition.
>
> Use refcount_inc_not_zero_acquire() in the IPv4 and IPv6 established
> lookups. Use refcount_set_release() when setting refcounts in the SYN
> cookie, TCP Fast Open, request migration, and TIME_WAIT paths. Keep the
> existing TIME_WAIT smp_wmb(), which separately orders the refcount store
> before ehash publication.
[Severity: Low]
Is "restore" accurate for the refcount_set_release() hunks?
fb041bb7c0a9 only changed the reader side. The !REFCOUNT_FULL
refcount_inc_not_zero() went from atomic_add_unless() to a relaxed
cmpxchg loop. refcount_set() was a plain atomic_set() both before and
after that commit.
So the six conversions add writer-side ordering that never existed. They
don't restore it. The six are in tcp_get_cookie_sock(),
tcp_fastopen_create_child(), reqsk_timer_handler(),
inet_csk_complete_hashdance(), inet_csk_listen_stop() and
inet_twsk_hashdance_schedule().
The changes themselves look justified. A stale reader using acquire
ordering has to see the pprev = NULL from sk_node_init() and the new tuple
fields before the new refcount. Otherwise it could match an unhashed
syncookie, TFO or migrated req.
Could the changelog explain this? It could also say how recycled request
sock slab memory makes these unhashed reqs reachable at all.
sk_clone_lock() and sock_init_data() already have an smp_wmb() before
their refcount_set(), so leaving those two alone looks right.
> Fixes: fb041bb7c0a9 ("locking/refcount: Consolidate implementations of refcount_t")
> Cc: stable@vger.kernel.org
[Severity: Low]
refcount_inc_not_zero_acquire() and refcount_set_release() were added by
7f8ceea0c58039 ("refcount: provide ops for cases when object's memory can
be reused"). That commit is in v6.15 and not in v6.14.
The Fixes: tag points to v5.5. Without that prerequisite, none of the
touched files will build in the 5.10, 5.15, 6.1, 6.6 and 6.12 stable
trees.
Should the stable tag carry a prerequisite annotation, for example:
Cc: stable@vger.kernel.org # needs 7f8ceea0c580 ("refcount: provide ops ...")
Or is a fallback planned for older trees?
> diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
> index 01ecd98a2b501..8faef6c38b364 100644
> --- a/net/ipv4/inet_connection_sock.c
> +++ b/net/ipv4/inet_connection_sock.c
> @@ -1060,8 +1060,8 @@ static void reqsk_timer_handler(struct timer_list *t)
> * hold another count to prevent use-after-free and
> * call reqsk_put() just before return.
> */
> - refcount_set(&nreq->rsk_refcnt, 2 + 1);
> timer_setup(&nreq->rsk_timer, reqsk_timer_handler, TIMER_PINNED);
> + refcount_set_release(&nreq->rsk_refcnt, 2 + 1);
[Severity: Low]
This isn't a bug, but timer_setup() now runs before the refcount store,
and the changelog doesn't mention the move.
It follows from the refcount_set_release() kernel-doc, which wants
initialisation done before the release. nreq is still private at this
point. A short note in the commit message would be enough.
> reqsk_queue_migrated(&inet_csk(nsk)->icsk_accept_queue, req);
>
> req = nreq;
[ ... ]
> diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c
> index a1d86026aefb0..5c1bff5a6d4d8 100644
> --- a/net/ipv4/inet_timewait_sock.c
> +++ b/net/ipv4/inet_timewait_sock.c
> @@ -143,7 +143,7 @@ void inet_twsk_hashdance_schedule(struct inet_timewait_sock *tw,
> * Also note that after this point, we lost our implicit reference
> * so we are not allowed to use tw anymore.
> */
> - refcount_set(&tw->tw_refcnt, 3);
> + refcount_set_release(&tw->tw_refcnt, 3);
[Severity: High]
Is the fix complete without also converting inet_twsk_purge() in this
same file?
It walks the same ehash chains locklessly under rcu_read_lock(). It
handles the same SLAB_TYPESAFE_BY_RCU TIME_WAIT and request socks, and it
still uses the relaxed variant:
net/ipv4/inet_timewait_sock.c:inet_twsk_purge() {
...
if (check_net(sock_net(sk)))
continue;
if (unlikely(!refcount_inc_not_zero(&sk->sk_refcnt)))
continue;
if (check_net(sock_net(sk))) {
sock_gen_put(sk);
goto restart;
}
...
inet_csk_reqsk_queue_drop_and_put(req->rsk_listener,
req);
...
}
The release store added here only helps readers that pair it with an
acquire. __refcount_add_not_zero() uses atomic_try_cmpxchg_relaxed(). On
arm64 or POWER, the second check_net() and the later req->rsk_listener
load can therefore be satisfied before the CAS.
Can this sequence happen?
CPU0, in tcp_sk_exit_batch()->tcp_twsk_purge()->inet_twsk_purge() for
dying netns D:
sees socket X in D, and the first check_net() is false
CPU1:
X is freed
the slot is reused for a new TIME_WAIT or request sock in live netns L
the new sock is initialised, gets refcount_set_release(), and is hashed
CPU0:
refcount_inc_not_zero() succeeds on the new object
the reordered second check_net() still reads D
inet_twsk_deschedule_put() or inet_csk_reqsk_queue_drop_and_put() runs
That tears down a TIME_WAIT or pending request sock that belongs to the
live netns L.
req->rsk_listener could also be read stale. It would then be the old
occupant's listener, which may already be released, and
inet_csk_reqsk_queue_drop() would update that listener's accept queue
counters.
An unprivileged user can trigger netns exit through user namespaces. A
remote peer can create TIME_WAIT and request socks in L.
Should inet_twsk_purge() use refcount_inc_not_zero_acquire() too?
[ ... ]
> diff --git a/net/ipv4/tcp_fastopen.c b/net/ipv4/tcp_fastopen.c
> index 471c78be55137..e40477b6b5549 100644
> --- a/net/ipv4/tcp_fastopen.c
> +++ b/net/ipv4/tcp_fastopen.c
> @@ -364,7 +364,7 @@ static struct sock *tcp_fastopen_create_child(struct sock *sk,
> tcp_reset_xmit_timer(child, ICSK_TIME_RETRANS,
> req->timeout, false);
>
> - refcount_set(&req->rsk_refcnt, 2);
> + refcount_set_release(&req->rsk_refcnt, 2);
[Severity: Low]
The kernel-doc for refcount_set_release() says:
* This function should be called only after new object is fully initialized.
* After this call the object should be considered visible to other tasks
Later in tcp_fastopen_create_child(), req is still written after the
release store:
tcp_rsk(req)->rcv_nxt = tp->rcv_nxt;
The other converted sites have the same ordering:
tcp_get_cookie_sock(), inet_csk_complete_hashdance() and
inet_csk_listen_stop() do the release before
inet_csk_reqsk_queue_add(), which writes req->sk and req->dl_next.
reqsk_timer_handler() does the release before req->num_timeout++, the
accecn_fail_mode update and mod_timer() on nreq. nreq is then hashed
by inet_ehash_insert().
For the reqs that are never hashed, hlist_nulls_unhashed_lockless()
rejects stale established lookups, because sk_node_init() runs before the
release. So the practical exposure seems limited to minor fields such as
num_timeout on the migrated nreq.
These stores had no ordering at all before this patch, so nothing
regresses.
Could the release stores move after the last initialising write? If not,
a comment could explain why the later writes are fine.
> diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c
> index aa5fa1dd062f7..1eea584d80df8 100644
> --- a/net/ipv6/inet6_hashtables.c
> +++ b/net/ipv6/inet6_hashtables.c
> @@ -105,7 +105,7 @@ struct sock *__inet6_lookup_established(const struct net *net,
> continue;
> if (!inet6_match(net, sk, saddr, daddr, ports, dif, sdif))
> continue;
> - if (unlikely(!refcount_inc_not_zero(&sk->sk_refcnt)))
> + if (unlikely(!refcount_inc_not_zero_acquire(&sk->sk_refcnt)))
> goto out;
[Severity: Medium]
This is a pre-existing issue and was not introduced by this patch, but
the MPTCP token lookups seem to have the same pattern.
mptcp_token_get_sock() in net/mptcp/token.c re-validates after a relaxed
increment:
if (!refcount_inc_not_zero(&sk->sk_refcnt))
goto not_found;
if (READ_ONCE(msk->token) != token ||
!net_eq(sock_net(sk), net)) {
mptcp_token_iter_next() does the same thing with its net_eq() check.
mptcp_prot sets SLAB_TYPESAFE_BY_RCU for msk objects. For that reason,
mptcp_subflow_reqsk_clone() in net/mptcp/subflow.c already uses
refcount_inc_not_zero_acquire().
On weakly ordered CPUs, can these lookups return a recycled msk from
another connection or netns?
For MP_JOIN, the later HMAC check would fail and cause a spurious reset.
Through the diag iterator, an msk from another netns could be dumped.
MPTCP was merged in v5.6, after fb041bb7c0a9. These sites never had the
fully ordered behaviour, and they are outside what this patch covers.
Would a separate fix for them make sense?
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261024053720.1147022-1-imv4bel%40gmail.com
next prev parent reply other threads:[~2026-10-25 5:40 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-24 5:37 [PATCH net v3 0/2] inet: fix established lookup races Hyunwoo Kim
2026-10-24 5:37 ` [PATCH net v3 1/2] inet: reject unhashed sockets during established lookups Hyunwoo Kim
2026-10-25 5:40 ` netdev-bot+sashiko
2026-10-24 5:37 ` [PATCH net v3 2/2] inet: restore refcount ordering for " Hyunwoo Kim
2026-10-25 5:40 ` netdev-bot+sashiko [this message]
2026-10-25 23:53 ` Hyunwoo Kim
2026-10-24 5:41 ` [PATCH net v3 0/2] inet: fix established lookup races netdev-bot+sinfo
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=179290682873.3134.10437749263853370498@kernel.org \
--to=netdev-bot+sashiko@kernel.org \
--cc=davem@davemloft.net \
--cc=edumazet@kernel.org \
--cc=horms@kernel.org \
--cc=imv4bel@gmail.com \
--cc=jiayuan.chen@linux.dev \
--cc=john.fastabend@gmail.com \
--cc=kuba@kernel.org \
--cc=kuniyu@google.com \
--cc=martin.lau@linux.dev \
--cc=ncardwell@google.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=sd@queasysnail.net \
--cc=stable@vger.kernel.org \
--cc=weiwan@google.com \
/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