Commit 2f4e429c authored by Shyam Prasad N's avatar Shyam Prasad N Committed by Steve French

cifs: lock chan_lock outside match_session

Coverity had rightly indicated a possible deadlock
due to chan_lock being done inside match_session.
All callers of match_* functions should pick up the
necessary locks and call them.
Signed-off-by: default avatarShyam Prasad N <sprasad@microsoft.com>
Reviewed-by: default avatarPaulo Alcantara (SUSE) <pc@manguebit.com>
Cc: stable@vger.kernel.org
Fixes: 724244cd ("cifs: protect session channel fields with chan_lock")
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent 2f0e4f03
...@@ -1721,7 +1721,7 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx, ...@@ -1721,7 +1721,7 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx,
return ERR_PTR(rc); return ERR_PTR(rc);
} }
/* this function must be called with ses_lock held */ /* this function must be called with ses_lock and chan_lock held */
static int match_session(struct cifs_ses *ses, struct smb3_fs_context *ctx) static int match_session(struct cifs_ses *ses, struct smb3_fs_context *ctx)
{ {
if (ctx->sectype != Unspecified && if (ctx->sectype != Unspecified &&
...@@ -1732,12 +1732,8 @@ static int match_session(struct cifs_ses *ses, struct smb3_fs_context *ctx) ...@@ -1732,12 +1732,8 @@ static int match_session(struct cifs_ses *ses, struct smb3_fs_context *ctx)
* If an existing session is limited to less channels than * If an existing session is limited to less channels than
* requested, it should not be reused * requested, it should not be reused
*/ */
spin_lock(&ses->chan_lock); if (ses->chan_max < ctx->max_channels)
if (ses->chan_max < ctx->max_channels) {
spin_unlock(&ses->chan_lock);
return 0; return 0;
}
spin_unlock(&ses->chan_lock);
switch (ses->sectype) { switch (ses->sectype) {
case Kerberos: case Kerberos:
...@@ -1865,10 +1861,13 @@ cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx) ...@@ -1865,10 +1861,13 @@ cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
spin_unlock(&ses->ses_lock); spin_unlock(&ses->ses_lock);
continue; continue;
} }
spin_lock(&ses->chan_lock);
if (!match_session(ses, ctx)) { if (!match_session(ses, ctx)) {
spin_unlock(&ses->chan_lock);
spin_unlock(&ses->ses_lock); spin_unlock(&ses->ses_lock);
continue; continue;
} }
spin_unlock(&ses->chan_lock);
spin_unlock(&ses->ses_lock); spin_unlock(&ses->ses_lock);
++ses->ses_count; ++ses->ses_count;
...@@ -2693,6 +2692,7 @@ cifs_match_super(struct super_block *sb, void *data) ...@@ -2693,6 +2692,7 @@ cifs_match_super(struct super_block *sb, void *data)
spin_lock(&tcp_srv->srv_lock); spin_lock(&tcp_srv->srv_lock);
spin_lock(&ses->ses_lock); spin_lock(&ses->ses_lock);
spin_lock(&ses->chan_lock);
spin_lock(&tcon->tc_lock); spin_lock(&tcon->tc_lock);
if (!match_server(tcp_srv, ctx, dfs_super_cmp) || if (!match_server(tcp_srv, ctx, dfs_super_cmp) ||
!match_session(ses, ctx) || !match_session(ses, ctx) ||
...@@ -2705,6 +2705,7 @@ cifs_match_super(struct super_block *sb, void *data) ...@@ -2705,6 +2705,7 @@ cifs_match_super(struct super_block *sb, void *data)
rc = compare_mount_options(sb, mnt_data); rc = compare_mount_options(sb, mnt_data);
out: out:
spin_unlock(&tcon->tc_lock); spin_unlock(&tcon->tc_lock);
spin_unlock(&ses->chan_lock);
spin_unlock(&ses->ses_lock); spin_unlock(&ses->ses_lock);
spin_unlock(&tcp_srv->srv_lock); spin_unlock(&tcp_srv->srv_lock);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment