* [PATCH 1/2] smb: client: hold server ref while queueing reconnect work
@ 2026-11-03 9:15 Joseph Qi
2026-11-03 9:15 ` [PATCH 2/2] smb: client: skip NULL channel in __cifs_put_smb_ses() Joseph Qi
2026-11-07 17:28 ` [PATCH 1/2] smb: client: hold server ref while queueing reconnect work Paulo Alcantara
0 siblings, 2 replies; 4+ messages in thread
From: Joseph Qi @ 2026-11-03 9:15 UTC (permalink / raw)
To: Paulo Alcantara, Namjae Jeon; +Cc: linux-cifs, linux-kernel
When query_server_interfaces() returns -EOPNOTSUPP on a secondary
channel, smb2_reconnect() calls smb3_update_ses_channels() which for a
channel runs cifs_chan_skip_or_disable(). That clears the channel's
slot in the session and calls cifs_put_tcp_session(), which can drop
the last reference of the channel and tear it down.
smb2_reconnect() then falls through to skip_add_channels and queues
reconnect work on that server, using a server that may already be
freed. The send path obtained the channel from cifs_pick_channel(),
which does not take a reference, so the session's channel reference is
the only one.
Take our own reference on the channel before calling
smb3_update_ses_channels() and drop it after the reconnect work has
been queued, so the channel cannot be freed while it is still used.
Fixes: f591062bdbf4 ("cifs: handle servers that still advertise multichannel after disabling")
Cc: stable@vger.kernel.org
Signed-off-by: Joseph Qi <joseph.qi@linux.alibaba.com>
---
fs/smb/client/smb2pdu.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
index f85595136ef8a..8e53e9e02df6c 100644
--- a/fs/smb/client/smb2pdu.c
+++ b/fs/smb/client/smb2pdu.c
@@ -253,6 +253,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
struct cifs_ses *ses;
int xid;
int rc = 0;
+ bool hold_server_ref = false;
/*
* SMB2s NegProt, SessSetup, Logoff do not have tcon yet so
@@ -470,6 +471,20 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
* treat this as server not supporting multichannel
*/
+ /*
+ * If server is a secondary channel,
+ * cifs_chan_skip_or_disable() called below may
+ * drop its last reference, so hold our own
+ * reference until the reconnect work below has
+ * been queued.
+ */
+ spin_lock(&cifs_tcp_ses_lock);
+ if (server->srv_count) {
+ server->srv_count++;
+ hold_server_ref = true;
+ }
+ spin_unlock(&cifs_tcp_ses_lock);
+
rc = smb3_update_ses_channels(ses, server,
from_reconnect,
true /* disable_mchan */);
@@ -498,6 +513,8 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
if (smb2_command != SMB2_INTERNAL_CMD)
cifs_queue_server_reconn(server);
+ if (hold_server_ref)
+ cifs_put_tcp_session(server, from_reconnect);
atomic_inc(&tconInfoReconnectCount);
out:
--
2.39.3
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH 2/2] smb: client: skip NULL channel in __cifs_put_smb_ses()
2026-11-03 9:15 [PATCH 1/2] smb: client: hold server ref while queueing reconnect work Joseph Qi
@ 2026-11-03 9:15 ` Joseph Qi
2026-11-07 17:32 ` Paulo Alcantara
2026-11-07 17:28 ` [PATCH 1/2] smb: client: hold server ref while queueing reconnect work Paulo Alcantara
1 sibling, 1 reply; 4+ messages in thread
From: Joseph Qi @ 2026-11-03 9:15 UTC (permalink / raw)
To: Paulo Alcantara, Namjae Jeon; +Cc: linux-cifs, linux-kernel
cifs_chan_skip_or_disable() clears a secondary channel's slot in the
session (ses->chans[chan_index].server = NULL) without lowering
chan_count when the server stops supporting multichannel. When the
session is later released, __cifs_put_smb_ses() walks every slot up to
chan_count and calls cifs_put_tcp_session() on it, which dereferences
the server pointer immediately, so a slot left NULL by the skip path
makes the release crash with a NULL pointer dereference.
Clearing a slot without lowering chan_count is older than
cifs_chan_skip_or_disable(): cifs_chan_update_iface() could already
do the same since b54034a73baf9 ("cifs: during reconnect, update
interface if necessary"), and the release loop has been unguarded
since then. 12d1e301bdfd1 ("cifs: do not let cifs_chan_update_iface
deallocate channels") later removed that trigger, but the crash is
reachable through it on older kernels.
cifs_decrease_secondary_channels() already guards the same put with
if (server). Add the same guard to the release loop so a skipped
channel slot is left alone.
Fixes: b54034a73baf9 ("cifs: during reconnect, update interface if necessary")
Cc: stable@vger.kernel.org
Signed-off-by: Joseph Qi <joseph.qi@linux.alibaba.com>
---
fs/smb/client/connect.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c
index e68fffb2ab2ea..6497b0d54fea7 100644
--- a/fs/smb/client/connect.c
+++ b/fs/smb/client/connect.c
@@ -2200,7 +2200,8 @@ void __cifs_put_smb_ses(struct cifs_ses *ses)
kref_put(&ses->chans[i].iface->refcount, release_iface);
ses->chans[i].iface = NULL;
}
- cifs_put_tcp_session(ses->chans[i].server, 0);
+ if (ses->chans[i].server)
+ cifs_put_tcp_session(ses->chans[i].server, 0);
ses->chans[i].server = NULL;
}
--
2.39.3
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH 1/2] smb: client: hold server ref while queueing reconnect work
2026-11-03 9:15 [PATCH 1/2] smb: client: hold server ref while queueing reconnect work Joseph Qi
2026-11-03 9:15 ` [PATCH 2/2] smb: client: skip NULL channel in __cifs_put_smb_ses() Joseph Qi
@ 2026-11-07 17:28 ` Paulo Alcantara
1 sibling, 0 replies; 4+ messages in thread
From: Paulo Alcantara @ 2026-11-07 17:28 UTC (permalink / raw)
To: Joseph Qi, Namjae Jeon; +Cc: linux-cifs, linux-kernel
Joseph Qi <joseph.qi@linux.alibaba.com> writes:
> When query_server_interfaces() returns -EOPNOTSUPP on a secondary
> channel, smb2_reconnect() calls smb3_update_ses_channels() which for a
> channel runs cifs_chan_skip_or_disable(). That clears the channel's
> slot in the session and calls cifs_put_tcp_session(), which can drop
> the last reference of the channel and tear it down.
>
> smb2_reconnect() then falls through to skip_add_channels and queues
> reconnect work on that server, using a server that may already be
> freed. The send path obtained the channel from cifs_pick_channel(),
> which does not take a reference, so the session's channel reference is
> the only one.
>
> Take our own reference on the channel before calling
> smb3_update_ses_channels() and drop it after the reconnect work has
> been queued, so the channel cannot be freed while it is still used.
>
> Fixes: f591062bdbf4 ("cifs: handle servers that still advertise multichannel after disabling")
> Cc: stable@vger.kernel.org
> Signed-off-by: Joseph Qi <joseph.qi@linux.alibaba.com>
Please check sashiko comments
https://sashiko.dev/#/patchset/20261103091558.2342761-1-joseph.qi%40linux.alibaba.com
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH 2/2] smb: client: skip NULL channel in __cifs_put_smb_ses()
2026-11-03 9:15 ` [PATCH 2/2] smb: client: skip NULL channel in __cifs_put_smb_ses() Joseph Qi
@ 2026-11-07 17:32 ` Paulo Alcantara
0 siblings, 0 replies; 4+ messages in thread
From: Paulo Alcantara @ 2026-11-07 17:32 UTC (permalink / raw)
To: Joseph Qi, Namjae Jeon; +Cc: linux-cifs, linux-kernel
Joseph Qi <joseph.qi@linux.alibaba.com> writes:
> cifs_chan_skip_or_disable() clears a secondary channel's slot in the
> session (ses->chans[chan_index].server = NULL) without lowering
> chan_count when the server stops supporting multichannel. When the
> session is later released, __cifs_put_smb_ses() walks every slot up to
> chan_count and calls cifs_put_tcp_session() on it, which dereferences
> the server pointer immediately, so a slot left NULL by the skip path
> makes the release crash with a NULL pointer dereference.
>
> Clearing a slot without lowering chan_count is older than
> cifs_chan_skip_or_disable(): cifs_chan_update_iface() could already
> do the same since b54034a73baf9 ("cifs: during reconnect, update
> interface if necessary"), and the release loop has been unguarded
> since then. 12d1e301bdfd1 ("cifs: do not let cifs_chan_update_iface
> deallocate channels") later removed that trigger, but the crash is
> reachable through it on older kernels.
>
> cifs_decrease_secondary_channels() already guards the same put with
> if (server). Add the same guard to the release loop so a skipped
> channel slot is left alone.
> ...
Applied.
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-11-07 17:32 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-03 9:15 [PATCH 1/2] smb: client: hold server ref while queueing reconnect work Joseph Qi
2026-11-03 9:15 ` [PATCH 2/2] smb: client: skip NULL channel in __cifs_put_smb_ses() Joseph Qi
2026-11-07 17:32 ` Paulo Alcantara
2026-11-07 17:28 ` [PATCH 1/2] smb: client: hold server ref while queueing reconnect work Paulo Alcantara
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®