summaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorWentao Liang <vulab@iscas.ac.cn>2026-09-17 16:34:39 +0000
committerPaulo Alcantara <pc@manguebit.org>2026-09-17 19:29:25 -0300
commit717e0a25036b6c92cecace30913b2d874a4c22b8 (patch)
tree32363e9fdd9a75ee9eef2c6a9ca9205406d3aab2 /fs
parent5f0306e731e2f46e91419eae57eee3a241c055e0 (diff)
downloadlwn-717e0a25036b6c92cecace30913b2d874a4c22b8.tar.gz
lwn-717e0a25036b6c92cecace30913b2d874a4c22b8.zip
cifs: Fix server use-after-free in cifs_chan_skip_or_disable()
When a secondary channel is no longer supported by the server, cifs_chan_skip_or_disable() drops the channel reference with cifs_put_tcp_session() and then continues to use the server pointer by calling cifs_signal_cifsd_for_reconnect() on it and reading its primary_server pointer. cifs_put_tcp_session() can drop the last reference of the channel and tear it down, so both the channel and the primary server (whose reference is also dropped by cifs_put_tcp_session()) can be freed before they are signaled for reconnect. Signal the channel and the primary server and capture the primary server pointer before dropping the channel reference with cifs_put_tcp_session(). Fixes: f591062bdbf4 ("cifs: handle servers that still advertise multichannel after disabling") Cc: stable@vger.kernel.org Signed-off-by: Wentao Liang <vulab@iscas.ac.cn> Signed-off-by: Paulo Alcantara <pc@manguebit.org>
Diffstat (limited to 'fs')
-rw-r--r--fs/smb/client/smb2pdu.c13
1 files changed, 7 insertions, 6 deletions
diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
index dea05aeb53a1..880ce12f50c4 100644
--- a/fs/smb/client/smb2pdu.c
+++ b/fs/smb/client/smb2pdu.c
@@ -189,18 +189,19 @@ cifs_chan_skip_or_disable(struct cifs_ses *ses,
spin_unlock(&ses->chan_lock);
/*
- * the above reference of server by channel
- * needs to be dropped without holding chan_lock
- * as cifs_put_tcp_session takes a higher lock
- * i.e. cifs_tcp_ses_lock
+ * signal the channel and its primary server to
+ * reconnect before dropping the above reference of
+ * server by channel, which is done without holding
+ * chan_lock as cifs_put_tcp_session takes a higher
+ * lock i.e. cifs_tcp_ses_lock
*/
- cifs_put_tcp_session(server, from_reconnect);
-
cifs_signal_cifsd_for_reconnect(server, false);
/* mark primary server as needing reconnect */
pserver = server->primary_server;
cifs_signal_cifsd_for_reconnect(pserver, false);
+
+ cifs_put_tcp_session(server, from_reconnect);
skip_terminate:
return -EHOSTDOWN;
}