Skip to content

Commit 90c49fc

Browse files
Paulo AlcantaraSteve French
authored andcommitted
cifs: fix potential use-after-free bugs in TCP_Server_Info::hostname
TCP_Server_Info::hostname may be updated once or many times during reconnect, so protect its access outside reconnect path as well and then prevent any potential use-after-free bugs. Cc: [email protected] Signed-off-by: Paulo Alcantara (SUSE) <[email protected]> Signed-off-by: Steve French <[email protected]>
1 parent 1810769 commit 90c49fc

File tree

4 files changed

+23
-13
lines changed

4 files changed

+23
-13
lines changed

fs/cifs/cifs_debug.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,8 +280,10 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
280280
seq_printf(m, "\n%d) ConnectionId: 0x%llx ",
281281
c, server->conn_id);
282282

283+
spin_lock(&server->srv_lock);
283284
if (server->hostname)
284285
seq_printf(m, "Hostname: %s ", server->hostname);
286+
spin_unlock(&server->srv_lock);
285287
#ifdef CONFIG_CIFS_SMB_DIRECT
286288
if (!server->rdma)
287289
goto skip_rdma;
@@ -623,10 +625,13 @@ static int cifs_stats_proc_show(struct seq_file *m, void *v)
623625
server->fastest_cmd[j],
624626
server->slowest_cmd[j]);
625627
for (j = 0; j < NUMBER_OF_SMB2_COMMANDS; j++)
626-
if (atomic_read(&server->smb2slowcmd[j]))
628+
if (atomic_read(&server->smb2slowcmd[j])) {
629+
spin_lock(&server->srv_lock);
627630
seq_printf(m, " %d slow responses from %s for command %d\n",
628631
atomic_read(&server->smb2slowcmd[j]),
629632
server->hostname, j);
633+
spin_unlock(&server->srv_lock);
634+
}
630635
#endif /* STATS2 */
631636
list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
632637
list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {

fs/cifs/cifs_debug.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -81,19 +81,19 @@ do { \
8181

8282
#define cifs_server_dbg_func(ratefunc, type, fmt, ...) \
8383
do { \
84-
const char *sn = ""; \
85-
if (server && server->hostname) \
86-
sn = server->hostname; \
84+
spin_lock(&server->srv_lock); \
8785
if ((type) & FYI && cifsFYI & CIFS_INFO) { \
8886
pr_debug_ ## ratefunc("%s: \\\\%s " fmt, \
89-
__FILE__, sn, ##__VA_ARGS__); \
87+
__FILE__, server->hostname, \
88+
##__VA_ARGS__); \
9089
} else if ((type) & VFS) { \
9190
pr_err_ ## ratefunc("VFS: \\\\%s " fmt, \
92-
sn, ##__VA_ARGS__); \
91+
server->hostname, ##__VA_ARGS__); \
9392
} else if ((type) & NOISY && (NOISY != 0)) { \
9493
pr_debug_ ## ratefunc("\\\\%s " fmt, \
95-
sn, ##__VA_ARGS__); \
94+
server->hostname, ##__VA_ARGS__); \
9695
} \
96+
spin_unlock(&server->srv_lock); \
9797
} while (0)
9898

9999
#define cifs_server_dbg(type, fmt, ...) \

fs/cifs/connect.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -403,8 +403,10 @@ static int __reconnect_target_unlocked(struct TCP_Server_Info *server, const cha
403403
if (server->hostname != target) {
404404
hostname = extract_hostname(target);
405405
if (!IS_ERR(hostname)) {
406+
spin_lock(&server->srv_lock);
406407
kfree(server->hostname);
407408
server->hostname = hostname;
409+
spin_unlock(&server->srv_lock);
408410
} else {
409411
cifs_dbg(FYI, "%s: couldn't extract hostname or address from dfs target: %ld\n",
410412
__func__, PTR_ERR(hostname));
@@ -561,9 +563,7 @@ cifs_echo_request(struct work_struct *work)
561563
goto requeue_echo;
562564

563565
rc = server->ops->echo ? server->ops->echo(server) : -ENOSYS;
564-
if (rc)
565-
cifs_dbg(FYI, "Unable to send echo request to server: %s\n",
566-
server->hostname);
566+
cifs_server_dbg(FYI, "send echo request: rc = %d\n", rc);
567567

568568
/* Check witness registrations */
569569
cifs_swn_check();
@@ -1404,6 +1404,8 @@ static int match_server(struct TCP_Server_Info *server, struct smb3_fs_context *
14041404
{
14051405
struct sockaddr *addr = (struct sockaddr *)&ctx->dstaddr;
14061406

1407+
lockdep_assert_held(&server->srv_lock);
1408+
14071409
if (ctx->nosharesock)
14081410
return 0;
14091411

@@ -1810,7 +1812,9 @@ cifs_setup_ipc(struct cifs_ses *ses, struct smb3_fs_context *ctx)
18101812
if (tcon == NULL)
18111813
return -ENOMEM;
18121814

1815+
spin_lock(&server->srv_lock);
18131816
scnprintf(unc, sizeof(unc), "\\\\%s\\IPC$", server->hostname);
1817+
spin_unlock(&server->srv_lock);
18141818

18151819
xid = get_xid();
18161820
tcon->ses = ses;

fs/cifs/sess.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ cifs_chan_is_iface_active(struct cifs_ses *ses,
159159
/* returns number of channels added */
160160
int cifs_try_adding_channels(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses)
161161
{
162+
struct TCP_Server_Info *server = ses->server;
162163
int old_chan_count, new_chan_count;
163164
int left;
164165
int rc = 0;
@@ -178,16 +179,16 @@ int cifs_try_adding_channels(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses)
178179
return 0;
179180
}
180181

181-
if (ses->server->dialect < SMB30_PROT_ID) {
182+
if (server->dialect < SMB30_PROT_ID) {
182183
spin_unlock(&ses->chan_lock);
183184
cifs_dbg(VFS, "multichannel is not supported on this protocol version, use 3.0 or above\n");
184185
return 0;
185186
}
186187

187-
if (!(ses->server->capabilities & SMB2_GLOBAL_CAP_MULTI_CHANNEL)) {
188+
if (!(server->capabilities & SMB2_GLOBAL_CAP_MULTI_CHANNEL)) {
188189
ses->chan_max = 1;
189190
spin_unlock(&ses->chan_lock);
190-
cifs_dbg(VFS, "server %s does not support multichannel\n", ses->server->hostname);
191+
cifs_server_dbg(VFS, "no multichannel support\n");
191192
return 0;
192193
}
193194
spin_unlock(&ses->chan_lock);

0 commit comments

Comments
 (0)