]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
cifs: lock chan_lock outside match_session
authorShyam Prasad N <sprasad@microsoft.com>
Mon, 20 Feb 2023 13:02:11 +0000 (13:02 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 30 Mar 2023 10:49:20 +0000 (12:49 +0200)
commit 2f4e429c846972c8405951a9ff7a82aceeca7461 upstream.

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: Shyam Prasad N <sprasad@microsoft.com>
Reviewed-by: Paulo Alcantara (SUSE) <pc@manguebit.com>
Cc: stable@vger.kernel.org
Fixes: 724244cdb382 ("cifs: protect session channel fields with chan_lock")
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/cifs/connect.c

index ecc1455358cc27e9dcb87cc3a51edfba402f9c00..7aecb1646b6fc5810f713c71e8cd52496891a4eb 100644 (file)
@@ -1774,7 +1774,7 @@ out_err:
        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)
 {
        if (ctx->sectype != Unspecified &&
@@ -1785,12 +1785,8 @@ static int match_session(struct cifs_ses *ses, struct smb3_fs_context *ctx)
         * If an existing session is limited to less channels than
         * requested, it should not be reused
         */
-       spin_lock(&ses->chan_lock);
-       if (ses->chan_max < ctx->max_channels) {
-               spin_unlock(&ses->chan_lock);
+       if (ses->chan_max < ctx->max_channels)
                return 0;
-       }
-       spin_unlock(&ses->chan_lock);
 
        switch (ses->sectype) {
        case Kerberos:
@@ -1918,10 +1914,13 @@ cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
                        spin_unlock(&ses->ses_lock);
                        continue;
                }
+               spin_lock(&ses->chan_lock);
                if (!match_session(ses, ctx)) {
+                       spin_unlock(&ses->chan_lock);
                        spin_unlock(&ses->ses_lock);
                        continue;
                }
+               spin_unlock(&ses->chan_lock);
                spin_unlock(&ses->ses_lock);
 
                ++ses->ses_count;
@@ -2742,6 +2741,7 @@ cifs_match_super(struct super_block *sb, void *data)
 
        spin_lock(&tcp_srv->srv_lock);
        spin_lock(&ses->ses_lock);
+       spin_lock(&ses->chan_lock);
        spin_lock(&tcon->tc_lock);
        if (!match_server(tcp_srv, ctx) ||
            !match_session(ses, ctx) ||
@@ -2754,6 +2754,7 @@ cifs_match_super(struct super_block *sb, void *data)
        rc = compare_mount_options(sb, mnt_data);
 out:
        spin_unlock(&tcon->tc_lock);
+       spin_unlock(&ses->chan_lock);
        spin_unlock(&ses->ses_lock);
        spin_unlock(&tcp_srv->srv_lock);