From: Mahanta Jambigi <mjambigi@linux.ibm.com>
To: netdev-bot+sashiko@kernel.org
Cc: andrew+netdev@lunn.ch, davem@davemloft.net, edumazet@google.com,
kuba@kernel.org, pabeni@redhat.com, alibuda@linux.alibaba.com,
dust.li@linux.alibaba.com, sidraya@linux.ibm.com,
hidayath@linux.ibm.com, pasic@linux.ibm.com, horms@kernel.org,
tonylu@linux.alibaba.com, guwen@linux.alibaba.com,
stable@vger.kernel.org, netdev@vger.kernel.org,
linux-s390@vger.kernel.org, linux-rdma@vger.kernel.org
Subject: Re: [PATCH net v11] net/smc: fix lgr/lnk lifetime vs diag reader race
Date: Mon, 19 Oct 2026 16:37:36 +0530 [thread overview]
Message-ID: <2b6f56ed-60ed-4d27-884d-849e85afbce4@linux.ibm.com> (raw)
In-Reply-To: <179240154272.3135.17238777571997282600@kernel.org>
On 19/10/26 2:49 pm, netdev-bot+sashiko@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential
> issue(s) to consider.
>
> Critical: 1 · High: 0 · Medium: 0 · Low: 0
>
> 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).
>
> - [Critical] The patch makes smc_conn_free() call
> smc_lgr_unregister_conn() unconditionally.
>
> --
>
> net/smc: fix lgr/lnk lifetime vs diag reader race
>
> This patch closes races between the SMC sock_diag dump and teardown of
> conn/lgr/lnk state. It unhashes sockets before smc_conn_free() and
> smcd_buf_detach(), orders sk_state with acquire/release, skips the
> extension attributes for sockets in SMC_INIT/SMC_CLOSED, and uses the
> cached link->ibname. It also makes smc_conn_free() always call
> smc_lgr_unregister_conn().
>
>> diff --git a/net/smc/smc_core.c b/net/smc/smc_core.c
>> index 9974149659c2..6735f185cf48 100644
>> --- a/net/smc/smc_core.c
>> +++ b/net/smc/smc_core.c
>> @@ -1279,10 +1279,9 @@ void smc_conn_free(struct smc_connection *conn)
>> if (current_work() != &conn->abort_work)
>> cancel_work_sync(&conn->abort_work);
>> }
>> - if (!list_empty(&lgr->list)) {
>> + if (!list_empty(&lgr->list))
>> smc_buf_unuse(conn, lgr); /* allow buffer reuse */
>> - smc_lgr_unregister_conn(conn);
>> - }
>> + smc_lgr_unregister_conn(conn);
>>
>> if (!lgr->conns_num)
>> smc_lgr_schedule_free_work(lgr);
>
> [Severity: Critical]
> Now that the unregister is unconditional, can lgr->free_work get re-armed
> on a link group that is already being torn down? If so, the lgr could be
> freed while that timer is still pending.
>
> smc_lgr_cleanup_early() unlinks the lgr but never sets lgr->freeing:
>
> smc_lgr_cleanup_early() {
> ...
> if (!list_empty(&lgr->list))
> list_del_init(&lgr->list);
> spin_unlock_bh(lgr_lock);
> __smc_lgr_terminate(lgr, true);
> }
>
> smc_lgr_schedule_free_work() checks only lgr->freeing, not
> lgr->terminating:
>
> if (!lgr->freeing) {
> mod_delayed_work(system_percpu_wq, &lgr->free_work, ...
>
> __smc_lgr_terminate() cancels free_work once, before a loop that sleeps
> in lock_sock(). After the loop it calls smc_lgr_free(), and nothing on
> that path cancels free_work again:
>
> __smc_lgr_terminate() {
> ...
> cancel_delayed_work(&lgr->free_work);
> lgr->terminating = 1;
> ...
> lock_sock(&smc->sk);
> smc_conn_kill(conn, soft);
> ...
> smc_lgr_cleanup(lgr);
> smc_lgr_free(lgr);
> }
>
> One possible sequence on an SMC-D server:
>
> - Conn X creates a first-contact lgr L. smc_listen_work() releases
> smc_server_lgr_pending for SMC-D right after sending ACCEPT.
>
> - Conn Y joins L. smc_conn_create() has no conns_num limit for SMC-D.
>
> - X's CONFIRM fails:
> smc_listen_decline(X) -> smc_conn_abort() -> smc_conn_free(X), while
> L is still listed. Then smc_lgr_cleanup_early(L) runs list_del_init()
> and __smc_lgr_terminate(L) cancels free_work, sets terminating = 1 and
> blocks in lock_sock(Y). Y's listen worker holds that lock while it
> waits for its own CONFIRM.
>
> - Y's CONFIRM also fails:
> smc_listen_decline(Y) -> smc_conn_abort() -> smc_conn_free(Y). The
> lgr list is now empty, but with this change smc_lgr_unregister_conn(Y)
> still runs. conns_num drops to 0, freeing is 0, so
> smc_lgr_schedule_free_work() arms free_work with
> SMC_LGR_FREE_DELAY_SERV.
>
> - X's worker resumes, the loop ends, and smc_lgr_free(L) ->
> smc_lgr_put() -> __smc_lgr_free() -> kfree(L) runs while free_work is
> still pending.
>
> Would the timer then fire on freed memory? If L were still alive at that
> point, smc_lgr_free_work() would see freeing == 0 and an empty conns_all
> and call smc_lgr_free() a second time.
>
> Before this patch, smc_conn_free(Y) skipped smc_lgr_unregister_conn() when
> the lgr list was empty, so conns_num stayed at 1 and free_work was not
> re-armed.
>
> The peer decides whether and when each CONFIRM fails, and with
> loopback-ism the client can be a local unprivileged user.
>
> Should smc_lgr_cleanup_early() set lgr->freeing like the other unlink
> paths do? Alternatively, smc_lgr_schedule_free_work() could also check
> lgr->terminating.
>
> [ ... ]
>
You are correct. v11 introduced unconditional smc_lgr_unregister_conn()
which correctly fixes the alert_token_local UAF, but left
smc_lgr_schedule_free_work() with only the !lgr->freeing check. On the
smc_lgr_cleanup_early() path, __smc_lgr_terminate() sets terminating=1
and cancels free_work without setting freeing=1, so a concurrent
smc_conn_free() decrementing conns_num to 0 would re-arm free_work. The
subsequent kfree(lgr) inside __smc_lgr_terminate() → smc_lgr_free()
leaves the re-armed work pointing at freed memory.
Fixed in v12 by adding !lgr->terminating to the guard in
smc_lgr_schedule_free_work():
- if (!lgr->freeing) {
+ if (!lgr->freeing && !lgr->terminating) {
This is safe: on the smc_lgr_cleanup_early() path __smc_lgr_terminate()
walks the full conns_all tree, kills every connection via
smc_conn_kill(), and then calls smc_lgr_free() unconditionally — it does
not rely on free_work to complete the teardown. Blocking the re-arm when
terminating=1 just prevents the UAF; the LGR is still freed by
__smc_lgr_terminate() itself.
On all other teardown paths (smc_lgr_terminate_sched,
smc_smcd_terminate, smc_smcd_terminate_all, smc_smcr_terminate_all)
freeing=1 is set before __smc_lgr_terminate() or terminate_work is
scheduled, so !lgr->freeing already blocked smc_lgr_schedule_free_work()
there — the !lgr->terminating addition changes nothing for those paths.
pw-bot: cr
prev parent reply other threads:[~2026-10-19 11:07 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-15 8:13 [PATCH net v11] net/smc: fix lgr/lnk lifetime vs diag reader race Mahanta Jambigi
2026-10-15 8:19 ` netdev-bot+sinfo
2026-10-15 8:21 ` Mahanta Jambigi
2026-10-19 9:19 ` netdev-bot+sashiko
2026-10-19 11:07 ` Mahanta Jambigi [this message]
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=2b6f56ed-60ed-4d27-884d-849e85afbce4@linux.ibm.com \
--to=mjambigi@linux.ibm.com \
--cc=alibuda@linux.alibaba.com \
--cc=andrew+netdev@lunn.ch \
--cc=davem@davemloft.net \
--cc=dust.li@linux.alibaba.com \
--cc=edumazet@google.com \
--cc=guwen@linux.alibaba.com \
--cc=hidayath@linux.ibm.com \
--cc=horms@kernel.org \
--cc=kuba@kernel.org \
--cc=linux-rdma@vger.kernel.org \
--cc=linux-s390@vger.kernel.org \
--cc=netdev-bot+sashiko@kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=pasic@linux.ibm.com \
--cc=sidraya@linux.ibm.com \
--cc=stable@vger.kernel.org \
--cc=tonylu@linux.alibaba.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