* [PATCH net] net/smc: avoid recursive sk_callback_lock in listen data_ready
@ 2026-06-17 15:28 Runyu Xiao
2026-06-18 6:24 ` Mahanta Jambigi
0 siblings, 1 reply; 3+ messages in thread
From: Runyu Xiao @ 2026-06-17 15:28 UTC (permalink / raw)
To: D. Wythe, Dust Li, Sidraya Jayagond, Wenjia Zhang,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni
Cc: Mahanta Jambigi, Tony Lu, Wen Gu, Simon Horman, Karsten Graul,
linux-rdma, linux-s390, netdev, linux-kernel, jianhao.xu,
runyu.xiao, stable
smc_listen() installs smc_clcsock_data_ready() as the underlying TCP
listen socket's sk_data_ready callback. smc_clcsock_data_ready() then
immediately takes sk_callback_lock before looking up the SMC listener and
queuing smc_tcp_listen_work().
That is unsafe once the TCP listen socket is leaving TCP_LISTEN. The TCP
close/flush path can run the installed sk_data_ready callback with
sk_callback_lock already held, so entering smc_clcsock_data_ready() again
tries to take the same rwlock recursively in the same thread. The nvmet
TCP listener had to make the same state check before taking
sk_callback_lock for this reason.
This issue was found by our static analysis tool and then manually
reviewed against the current tree.
The grounded PoC kept the SMC listen callback installation path:
smc_listen()
smc_clcsock_replace_cb()
sk_data_ready = smc_clcsock_data_ready()
It then modeled the close/flush carrier that invokes the installed
sk_data_ready callback while sk_callback_lock is already held. Lockdep
reported the same-thread recursive acquisition:
WARNING: possible recursive locking detected
smc_clcsock_data_ready+0xa/0x4d [vuln_msv]
smc_close_flush_work+0x1f/0x30 [vuln_msv]
*** DEADLOCK ***
Return before taking sk_callback_lock when the underlying TCP socket is no
longer in TCP_LISTEN. In that state there is no listen accept work to
queue for SMC, and avoiding the callback lock mirrors the fix used by the
TCP nvmet listener.
Fixes: 0558226cebee ("net/smc: Fix slab-out-of-bounds issue in fallback")
Cc: stable@vger.kernel.org
Signed-off-by: Runyu Xiao <runyu.xiao@seu.edu.cn>
---
net/smc/af_smc.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c
index 6421c2e1c84d..1af4e3c333ff 100644
--- a/net/smc/af_smc.c
+++ b/net/smc/af_smc.c
@@ -2631,6 +2631,9 @@ static void smc_clcsock_data_ready(struct sock *listen_clcsock)
{
struct smc_sock *lsmc;
+ if (READ_ONCE(listen_clcsock->sk_state) != TCP_LISTEN)
+ return;
+
read_lock_bh(&listen_clcsock->sk_callback_lock);
lsmc = smc_clcsock_user_data(listen_clcsock);
if (!lsmc)
--
2.34.1
^ permalink raw reply related [flat|nested] 3+ messages in thread* Re: [PATCH net] net/smc: avoid recursive sk_callback_lock in listen data_ready
2026-06-17 15:28 [PATCH net] net/smc: avoid recursive sk_callback_lock in listen data_ready Runyu Xiao
@ 2026-06-18 6:24 ` Mahanta Jambigi
2026-06-18 14:16 ` Runyu Xiao
0 siblings, 1 reply; 3+ messages in thread
From: Mahanta Jambigi @ 2026-06-18 6:24 UTC (permalink / raw)
To: Runyu Xiao, D. Wythe, Dust Li, Sidraya Jayagond, Wenjia Zhang,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni
Cc: Tony Lu, Wen Gu, Simon Horman, Karsten Graul, linux-rdma,
linux-s390, netdev, linux-kernel, jianhao.xu, stable
On 17/06/26 8:58 pm, Runyu Xiao wrote:
> smc_listen() installs smc_clcsock_data_ready() as the underlying TCP
> listen socket's sk_data_ready callback. smc_clcsock_data_ready() then
> immediately takes sk_callback_lock before looking up the SMC listener and
> queuing smc_tcp_listen_work().
>
> That is unsafe once the TCP listen socket is leaving TCP_LISTEN. The TCP
> close/flush path can run the installed sk_data_ready callback with
> sk_callback_lock already held, so entering smc_clcsock_data_ready() again
> tries to take the same rwlock recursively in the same thread. The nvmet
Could you provide me the exact call stack showing recursive lock? Also
help me with the nvmet commit details.
> TCP listener had to make the same state check before taking
> sk_callback_lock for this reason.
>
> This issue was found by our static analysis tool and then manually
> reviewed against the current tree.
>
> The grounded PoC kept the SMC listen callback installation path:
>
> smc_listen()
> smc_clcsock_replace_cb()
> sk_data_ready = smc_clcsock_data_ready()
>
> It then modeled the close/flush carrier that invokes the installed
> sk_data_ready callback while sk_callback_lock is already held. Lockdep
> reported the same-thread recursive acquisition:
>
> WARNING: possible recursive locking detected
> smc_clcsock_data_ready+0xa/0x4d [vuln_msv]
> smc_close_flush_work+0x1f/0x30 [vuln_msv]
> *** DEADLOCK ***
>
> Return before taking sk_callback_lock when the underlying TCP socket is no
> longer in TCP_LISTEN. In that state there is no listen accept work to
> queue for SMC, and avoiding the callback lock mirrors the fix used by the
> TCP nvmet listener.
>
> Fixes: 0558226cebee ("net/smc: Fix slab-out-of-bounds issue in fallback")
> Cc: stable@vger.kernel.org
> Signed-off-by: Runyu Xiao <runyu.xiao@seu.edu.cn>
> ---
> net/smc/af_smc.c | 3 +++
> 1 file changed, 3 insertions(+)
>
> diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c
> index 6421c2e1c84d..1af4e3c333ff 100644
> --- a/net/smc/af_smc.c
> +++ b/net/smc/af_smc.c
> @@ -2631,6 +2631,9 @@ static void smc_clcsock_data_ready(struct sock *listen_clcsock)
> {
> struct smc_sock *lsmc;
>
> + if (READ_ONCE(listen_clcsock->sk_state) != TCP_LISTEN)
Is *TCP_LISTEN* check sufficient? What about *TCP_SYN_RECV* or
*TCP_ESTABLISHED*?
> + return;
> +
> read_lock_bh(&listen_clcsock->sk_callback_lock);
> lsmc = smc_clcsock_user_data(listen_clcsock);
> if (!lsmc)
^ permalink raw reply [flat|nested] 3+ messages in thread* Re: [PATCH net] net/smc: avoid recursive sk_callback_lock in listen data_ready
2026-06-18 6:24 ` Mahanta Jambigi
@ 2026-06-18 14:16 ` Runyu Xiao
0 siblings, 0 replies; 3+ messages in thread
From: Runyu Xiao @ 2026-06-18 14:16 UTC (permalink / raw)
To: Mahanta Jambigi, D. Wythe, Dust Li, Sidraya Jayagond,
Wenjia Zhang, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni
Cc: Tony Lu, Wen Gu, Simon Horman, Karsten Graul, linux-rdma,
linux-s390, netdev, linux-kernel, jianhao.xu, runyu.xiao
Hi,
Thanks for taking a look.
The exact Lockdep stack I have is from the grounded reproducer, not from
a production SMC setup. The reproducer keeps the same callback shape:
the close/flush side holds sk_callback_lock and invokes the installed
sk_data_ready callback, which re-enters smc_clcsock_data_ready() and tries
to take sk_callback_lock again.
The relevant Lockdep report is:
WARNING: possible recursive locking detected
kworker/u4:3/39 is trying to acquire lock:
(sk_callback_lock) at smc_clcsock_data_ready+0xa/0x4d
but task is already holding lock:
(sk_callback_lock) at smc_close_flush_work+0xc/0x30
Possible unsafe locking scenario:
CPU0
----
lock(sk_callback_lock);
lock(sk_callback_lock);
*** DEADLOCK ***
Workqueue: smc_close_wq smc_close_flush_work
Call Trace:
dump_stack_lvl
__lock_acquire
lock_acquire
_raw_read_lock_bh
smc_clcsock_data_ready+0xa/0x4d
smc_close_flush_work+0x1f/0x30
process_one_work
worker_thread
kthread
ret_from_fork
The nvmet change I referred to is:
2fa8961d3a6a ("nvmet-tcp: fixup hang in nvmet_tcp_listen_data_ready()")
The stable/backport patch I originally used as the reference is:
1c90f930e7b4 ("nvmet-tcp: fixup hang in nvmet_tcp_listen_data_ready()")
Its commit message says that when the socket is closed while in
TCP_LISTEN, the flush callback can call nvmet_tcp_listen_data_ready()
with sk_callback_lock already held, so nvmet moved the TCP_LISTEN check
before taking sk_callback_lock.
For the TCP_LISTEN check: my reasoning was that smc_clcsock_data_ready()
is installed by smc_listen() on the underlying TCP listen socket and only
queues smc_tcp_listen_work() for the SMC listen/accept path. Once that
underlying socket is no longer in TCP_LISTEN, there should be no SMC
listen accept work to queue from this callback. TCP_SYN_RECV and
TCP_ESTABLISHED are not listen-socket states for this callback path, so I
did not intend the callback to queue listen work for those states.
That said, if SMC expects smc_clcsock_data_ready() to handle a non-LISTEN
state during fallback or another transition, then the proposed check is
too strict and I should rework the fix.
Thanks,
Runyu
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-06-18 14:21 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-17 15:28 [PATCH net] net/smc: avoid recursive sk_callback_lock in listen data_ready Runyu Xiao
2026-06-18 6:24 ` Mahanta Jambigi
2026-06-18 14:16 ` Runyu Xiao
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.