]> git.hungrycats.org Git - linux/commitdiff
smb: client: fix potential deadlock when releasing mids
authorPaulo Alcantara <pc@manguebit.com>
Wed, 25 Oct 2023 17:58:35 +0000 (14:58 -0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 28 Nov 2023 17:15:11 +0000 (17:15 +0000)
commit e6322fd177c6885a21dd4609dc5e5c973d1a2eb7 upstream.

All release_mid() callers seem to hold a reference of @mid so there is
no need to call kref_put(&mid->refcount, __release_mid) under
@server->mid_lock spinlock.  If they don't, then an use-after-free bug
would have occurred anyways.

By getting rid of such spinlock also fixes a potential deadlock as
shown below

CPU 0                                CPU 1
------------------------------------------------------------------
cifs_demultiplex_thread()            cifs_debug_data_proc_show()
 release_mid()
  spin_lock(&server->mid_lock);
                                     spin_lock(&cifs_tcp_ses_lock)
      spin_lock(&server->mid_lock)
  __release_mid()
   smb2_find_smb_tcon()
    spin_lock(&cifs_tcp_ses_lock) *deadlock*

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>
fs/smb/client/cifsproto.h
fs/smb/client/smb2misc.c
fs/smb/client/transport.c

index bd0a1505719a4ac5b5102c6f8d863d8543dc409a..a01ee1b0a66ce0b2cff04d48edc54c22ea6326b5 100644 (file)
@@ -81,7 +81,7 @@ extern char *cifs_build_path_to_root(struct smb3_fs_context *ctx,
 extern char *build_wildcard_path_from_dentry(struct dentry *direntry);
 char *cifs_build_devname(char *nodename, const char *prepath);
 extern void delete_mid(struct mid_q_entry *mid);
-extern void release_mid(struct mid_q_entry *mid);
+void __release_mid(struct kref *refcount);
 extern void cifs_wake_up_task(struct mid_q_entry *mid);
 extern int cifs_handle_standard(struct TCP_Server_Info *server,
                                struct mid_q_entry *mid);
@@ -741,4 +741,9 @@ static inline bool dfs_src_pathname_equal(const char *s1, const char *s2)
        return true;
 }
 
+static inline void release_mid(struct mid_q_entry *mid)
+{
+       kref_put(&mid->refcount, __release_mid);
+}
+
 #endif                 /* _CIFSPROTO_H */
index 3935a60db5c3107f04f333a5a3f8ff1356077e4e..446647df79dc3388e608a7bec672ebae89a5fdad 100644 (file)
@@ -787,7 +787,7 @@ __smb2_handle_cancelled_cmd(struct cifs_tcon *tcon, __u16 cmd, __u64 mid,
 {
        struct close_cancelled_open *cancelled;
 
-       cancelled = kzalloc(sizeof(*cancelled), GFP_ATOMIC);
+       cancelled = kzalloc(sizeof(*cancelled), GFP_KERNEL);
        if (!cancelled)
                return -ENOMEM;
 
index 2b9a2ed45a652db143b51e8474d004ff64938239..a48591d79b667bc11796e9d826c648e82e27c5ee 100644 (file)
@@ -76,7 +76,7 @@ alloc_mid(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server)
        return temp;
 }
 
-static void __release_mid(struct kref *refcount)
+void __release_mid(struct kref *refcount)
 {
        struct mid_q_entry *midEntry =
                        container_of(refcount, struct mid_q_entry, refcount);
@@ -156,15 +156,6 @@ static void __release_mid(struct kref *refcount)
        mempool_free(midEntry, cifs_mid_poolp);
 }
 
-void release_mid(struct mid_q_entry *mid)
-{
-       struct TCP_Server_Info *server = mid->server;
-
-       spin_lock(&server->mid_lock);
-       kref_put(&mid->refcount, __release_mid);
-       spin_unlock(&server->mid_lock);
-}
-
 void
 delete_mid(struct mid_q_entry *mid)
 {