From: Mahanta Jambigi <mjambigi@linux.ibm.com>
To: sashiko-reviews@lists.linux.dev,
"D. Wythe" <alibuda@linux.alibaba.com>,
Dust Li <dust.li@linux.alibaba.com>,
Sidraya Jayagond <sidraya@linux.ibm.com>
Cc: Heiko Carstens <hca@linux.ibm.com>,
Alexander Gordeev <agordeev@linux.ibm.com>,
Vasily Gorbik <gor@linux.ibm.com>,
linux-s390@vger.kernel.org,
Hidayath Khan <hidayath@linux.ibm.com>,
Alexandra Winter <wintera@linux.ibm.com>,
Aswin Karuvally <aswin@linux.ibm.com>,
Nagamani PV <nagamani@linux.ibm.com>,
Tony Lu <tonylu@linux.alibaba.com>,
Wen Gu <guwen@linux.alibaba.com>,
netdev@vger.kernel.org
Subject: Re: [PATCH net v3] net/smc: fix clcsock and lgr/lnk races in smc_diag dump path
Date: Thu, 13 Aug 2026 13:03:17 +0530 [thread overview]
Message-ID: <b27c85b8-2adb-4a2d-b2f1-573b31cc3f3d@linux.ibm.com> (raw)
In-Reply-To: <20260808081643.35CA11F000E9@smtp.kernel.org>
On 08/08/26 1:46 pm, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
>
> New issues:
> - [High] Dropping the hash lock per-socket and unconditionally restarting the list walk from the head using a logical index introduces O(N^2) list traversal complexity and causes active sockets to be skipped in the diag dump.
>
> Pre-existing issues:
> - [Critical] The patch attempts to fix a Use-After-Free race on `smc->clcsock` by adding `clcsock_release_lock` in `smc_diag_msg_common_fill()`, but misses a concurrent teardown path in `smc_accept_dequeue()` that frees the socket without acquiring the mutex.
> --
>
> --- Patch [1]: [PATCH net v3] net/smc: fix clcsock and lgr/lnk races in smc_diag dump path ---
> commit a16d6de2c1851166c340508a037e5292d66a0907
> Author: Mahanta Jambigi <mjambigi@linux.ibm.com>
>
> net/smc: fix clcsock and lgr/lnk races in smc_diag dump path
>
> This commit attempts to fix two races in the SMC diag dump path by holding
> clcsock_release_lock in smc_diag_msg_common_fill() and lock_sock() in
> __smc_diag_dump(). It also modifies the dump iteration to pin sockets, drop
> the hash lock, and restart the traversal from the head of the list.
>
>> diff --git a/net/smc/smc_diag.c b/net/smc/smc_diag.c
>> index bf0beaa23bdb6..72d77360e504f 100644
>> --- a/net/smc/smc_diag.c
>> +++ b/net/smc/smc_diag.c
>> @@ -39,22 +39,34 @@ static void smc_diag_msg_common_fill(struct smc_diag_msg *r, struct sock *sk)
>> memset(r, 0, sizeof(*r));
>> r->diag_family = sk->sk_family;
>> sock_diag_save_cookie(sk, r->id.idiag_cookie);
>> - if (!smc->clcsock)
>> - return;
>> - r->id.idiag_sport = htons(smc->clcsock->sk->sk_num);
>> - r->id.idiag_dst[0] = smc->clcsock->sk->sk_daddr;
>> + /*
>> + * smc_clcsock_release() sets smc->clcsock = NULL under
>> + * clcsock_release_lock before freeing the socket. Hold the same
>> + * mutex here to make the NULL check and all field reads atomic
>> + * with that writer. mutex_lock() is safe: this function is called
>> + * only after the hash spinlock has been dropped by
>> + * smc_diag_dump_proto().
>> + */
>> + mutex_lock(&smc->clcsock_release_lock);
>> + if (smc->clcsock) {
>> + r->id.idiag_sport = htons(smc->clcsock->sk->sk_num);
>
> [Severity: Critical]
> This is a pre-existing issue, but does this mutex fully protect against
> concurrent teardowns?
>
> Looking at smc_accept_dequeue() in net/smc/af_smc.c, if an unaccepted socket
> is closed (SMC_CLOSED), it unhashes it and frees isk->clcsock without holding
> clcsock_release_lock or the child's socket lock:
I'll address this issue separately as this is a pre-existing one.
>
> net/smc/af_smc.c:smc_accept_dequeue() {
> ...
> if (new_sk->sk_state == SMC_CLOSED) {
> new_sk->sk_prot->unhash(new_sk);
> if (isk->clcsock) {
> sock_release(isk->clcsock);
> isk->clcsock = NULL;
> }
> ...
> }
>
> If the netlink diag dump thread concurrently iterates the hash table, grabs
> the socket reference, and calls smc_diag_msg_common_fill(), could it acquire
> the mutex, see a non-NULL clcsock, and dereference it while it is being freed
> by smc_accept_dequeue()?
>
> [ ... ]
>
>> @@ -204,25 +228,43 @@ static int smc_diag_dump_proto(struct proto *prot, struct sk_buff *skb,
>> int rc = 0, num = 0;
>> struct sock *sk;
>>
>> - read_lock(&prot->h.smc_hash->lock);
>> head = &prot->h.smc_hash->ht;
>> +restart:
>> + num = 0;
>> + read_lock(&prot->h.smc_hash->lock);
>> if (hlist_empty(head))
>> goto out;
>> -
>> sk_for_each(sk, head) {
>> if (!net_eq(sock_net(sk), net))
>> continue;
>> if (num < snum)
>> goto next;
>> + /*
>> + * Pin sk before dropping the lock. refcount_inc_not_zero()
>> + * skips sockets already past their last reference.
>> + * smc_unhash_sk() nulls sk->sk_node.next via sk_del_node_init()
>> + * so resuming an interrupted sk_for_each() would terminate
>> + * early if a socket is unhashed while the lock is dropped.
>> + * Restart from head after each unlock, using snum to skip
>> + * already-dumped entries.
>> + */
>> + if (!refcount_inc_not_zero(&sk->sk_refcnt))
>> + goto next;
>> + read_unlock(&prot->h.smc_hash->lock);
>> +
>> rc = __smc_diag_dump(sk, skb, cb, nlmsg_data(cb->nlh), bc);
>> + sock_put(sk);
>> +
>> if (rc < 0)
>> - goto out;
>> + goto out_nolock;
>> + snum = num + 1;
>> + goto restart;
>
> [Severity: High]
> Does restarting the list walk from the head using a logical index (snum)
> introduce an O(N^2) list traversal complexity?
>
> If any previously seen sockets are concurrently unhashed while the lock is
> dropped, could stepping over (num < snum) elements skip active sockets that
> shifted to earlier positions in the list?
I got couple of reviews from Sashiko AI & I have addressed them here.
Q1: O(N²) complexity?
Yes, this is O(N²) in the worst case — on each restart we skip
already-dumped entries from the head. This is an accepted trade-off: the
same pattern is used in inet_diag and unix_diag. The lock cannot be held
across __smc_diag_dump() since it now takes sleeping locks (mutex_lock,
lock_sock), so drop-and-restart is unavoidable. The skip itself is cheap
(counter comparison only), and the SMC hash is small in practice.
Q2: Can sockets shift to earlier positions and get skipped?
No. SMC uses an hlist where new sockets are always inserted at the head
via hlist_add_head(). Removal does not reorder remaining nodes. So a
socket that existed before an unlock cannot move to an earlier position
— its ordinal index across restarts is stable. A socket inserted during
the unlock will appear at position 0 on the next restart and will be
skipped by num < snum, but that is correct and consistent behaviour —
netlink dumps are not guaranteed to be atomic snapshots.
Sashiko AI review ·
https://sashiko.dev/#/patchset/20260807081606.3200128-1-mjambigi@linux.ibm.com?part=1
next prev parent reply other threads:[~2026-08-13 7:33 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-07 8:16 [PATCH net v3] net/smc: fix clcsock and lgr/lnk races in smc_diag dump path Mahanta Jambigi
2026-08-07 9:12 ` Mahanta Jambigi
2026-08-07 15:02 ` [syzbot ci] " syzbot ci
2026-08-13 7:25 ` Mahanta Jambigi
2026-08-08 8:16 ` [PATCH net v3] " sashiko-bot
2026-08-13 7:33 ` Mahanta Jambigi [this message]
2026-08-17 12:43 ` Mahanta Jambigi
2026-08-24 7:15 ` Mahanta Jambigi
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=b27c85b8-2adb-4a2d-b2f1-573b31cc3f3d@linux.ibm.com \
--to=mjambigi@linux.ibm.com \
--cc=agordeev@linux.ibm.com \
--cc=alibuda@linux.alibaba.com \
--cc=aswin@linux.ibm.com \
--cc=dust.li@linux.alibaba.com \
--cc=gor@linux.ibm.com \
--cc=guwen@linux.alibaba.com \
--cc=hca@linux.ibm.com \
--cc=hidayath@linux.ibm.com \
--cc=linux-s390@vger.kernel.org \
--cc=nagamani@linux.ibm.com \
--cc=netdev@vger.kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
--cc=sidraya@linux.ibm.com \
--cc=tonylu@linux.alibaba.com \
--cc=wintera@linux.ibm.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