cifs: fix potential use-after-free bugs in TCP_Server_Info::hostname
commit 90c49fce1c43e1cc152695e20363ff5087897c09 upstream. 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: stable@vger.kernel.org Signed-off-by: Paulo Alcantara (SUSE) <pc@manguebit.com> Signed-off-by: Steve French <stfrench@microsoft.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
a744060574
commit
64d62ac6d6
@ -279,8 +279,10 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
|
||||
seq_printf(m, "\n%d) ConnectionId: 0x%llx ",
|
||||
c, server->conn_id);
|
||||
|
||||
spin_lock(&server->srv_lock);
|
||||
if (server->hostname)
|
||||
seq_printf(m, "Hostname: %s ", server->hostname);
|
||||
spin_unlock(&server->srv_lock);
|
||||
#ifdef CONFIG_CIFS_SMB_DIRECT
|
||||
if (!server->rdma)
|
||||
goto skip_rdma;
|
||||
@ -607,10 +609,13 @@ static int cifs_stats_proc_show(struct seq_file *m, void *v)
|
||||
server->fastest_cmd[j],
|
||||
server->slowest_cmd[j]);
|
||||
for (j = 0; j < NUMBER_OF_SMB2_COMMANDS; j++)
|
||||
if (atomic_read(&server->smb2slowcmd[j]))
|
||||
if (atomic_read(&server->smb2slowcmd[j])) {
|
||||
spin_lock(&server->srv_lock);
|
||||
seq_printf(m, " %d slow responses from %s for command %d\n",
|
||||
atomic_read(&server->smb2slowcmd[j]),
|
||||
server->hostname, j);
|
||||
spin_unlock(&server->srv_lock);
|
||||
}
|
||||
#endif /* STATS2 */
|
||||
list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
|
||||
list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
|
||||
|
@ -81,19 +81,19 @@ do { \
|
||||
|
||||
#define cifs_server_dbg_func(ratefunc, type, fmt, ...) \
|
||||
do { \
|
||||
const char *sn = ""; \
|
||||
if (server && server->hostname) \
|
||||
sn = server->hostname; \
|
||||
spin_lock(&server->srv_lock); \
|
||||
if ((type) & FYI && cifsFYI & CIFS_INFO) { \
|
||||
pr_debug_ ## ratefunc("%s: \\\\%s " fmt, \
|
||||
__FILE__, sn, ##__VA_ARGS__); \
|
||||
__FILE__, server->hostname, \
|
||||
##__VA_ARGS__); \
|
||||
} else if ((type) & VFS) { \
|
||||
pr_err_ ## ratefunc("VFS: \\\\%s " fmt, \
|
||||
sn, ##__VA_ARGS__); \
|
||||
server->hostname, ##__VA_ARGS__); \
|
||||
} else if ((type) & NOISY && (NOISY != 0)) { \
|
||||
pr_debug_ ## ratefunc("\\\\%s " fmt, \
|
||||
sn, ##__VA_ARGS__); \
|
||||
server->hostname, ##__VA_ARGS__); \
|
||||
} \
|
||||
spin_unlock(&server->srv_lock); \
|
||||
} while (0)
|
||||
|
||||
#define cifs_server_dbg(type, fmt, ...) \
|
||||
|
@ -452,8 +452,10 @@ static int __reconnect_target_unlocked(struct TCP_Server_Info *server, const cha
|
||||
if (server->hostname != target) {
|
||||
hostname = extract_hostname(target);
|
||||
if (!IS_ERR(hostname)) {
|
||||
spin_lock(&server->srv_lock);
|
||||
kfree(server->hostname);
|
||||
server->hostname = hostname;
|
||||
spin_unlock(&server->srv_lock);
|
||||
} else {
|
||||
cifs_dbg(FYI, "%s: couldn't extract hostname or address from dfs target: %ld\n",
|
||||
__func__, PTR_ERR(hostname));
|
||||
@ -620,9 +622,7 @@ cifs_echo_request(struct work_struct *work)
|
||||
goto requeue_echo;
|
||||
|
||||
rc = server->ops->echo ? server->ops->echo(server) : -ENOSYS;
|
||||
if (rc)
|
||||
cifs_dbg(FYI, "Unable to send echo request to server: %s\n",
|
||||
server->hostname);
|
||||
cifs_server_dbg(FYI, "send echo request: rc = %d\n", rc);
|
||||
|
||||
/* Check witness registrations */
|
||||
cifs_swn_check();
|
||||
@ -1462,6 +1462,8 @@ static int match_server(struct TCP_Server_Info *server, struct smb3_fs_context *
|
||||
{
|
||||
struct sockaddr *addr = (struct sockaddr *)&ctx->dstaddr;
|
||||
|
||||
lockdep_assert_held(&server->srv_lock);
|
||||
|
||||
if (ctx->nosharesock)
|
||||
return 0;
|
||||
|
||||
@ -1863,7 +1865,9 @@ cifs_setup_ipc(struct cifs_ses *ses, struct smb3_fs_context *ctx)
|
||||
if (tcon == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock(&server->srv_lock);
|
||||
scnprintf(unc, sizeof(unc), "\\\\%s\\IPC$", server->hostname);
|
||||
spin_unlock(&server->srv_lock);
|
||||
|
||||
xid = get_xid();
|
||||
tcon->ses = ses;
|
||||
|
@ -159,6 +159,7 @@ cifs_chan_is_iface_active(struct cifs_ses *ses,
|
||||
/* returns number of channels added */
|
||||
int cifs_try_adding_channels(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses)
|
||||
{
|
||||
struct TCP_Server_Info *server = ses->server;
|
||||
int old_chan_count, new_chan_count;
|
||||
int left;
|
||||
int rc = 0;
|
||||
@ -178,16 +179,16 @@ int cifs_try_adding_channels(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ses->server->dialect < SMB30_PROT_ID) {
|
||||
if (server->dialect < SMB30_PROT_ID) {
|
||||
spin_unlock(&ses->chan_lock);
|
||||
cifs_dbg(VFS, "multichannel is not supported on this protocol version, use 3.0 or above\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(ses->server->capabilities & SMB2_GLOBAL_CAP_MULTI_CHANNEL)) {
|
||||
if (!(server->capabilities & SMB2_GLOBAL_CAP_MULTI_CHANNEL)) {
|
||||
ses->chan_max = 1;
|
||||
spin_unlock(&ses->chan_lock);
|
||||
cifs_dbg(VFS, "server %s does not support multichannel\n", ses->server->hostname);
|
||||
cifs_server_dbg(VFS, "no multichannel support\n");
|
||||
return 0;
|
||||
}
|
||||
spin_unlock(&ses->chan_lock);
|
||||
|
Loading…
Reference in New Issue
Block a user