]> git.ipfire.org Git - thirdparty/kernel/stable.git/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>
Fri, 2 May 2025 05:44:21 +0000 (07:44 +0200)
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>
[cifs_mid_q_entry_release() is renamed to release_mid() and
 _cifs_mid_q_entry_release() is renamed to __release_mid() by
 commit 70f08f914a37 ("cifs: remove useless DeleteMidQEntry()")
 which is integrated into v6.0, so preserve old names in v5.15.]
Signed-off-by: Cliff Liu <donghua.liu@windriver.com>
Signed-off-by: He Zhe <Zhe.He@windriver.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/cifs/cifsproto.h
fs/cifs/smb2misc.c
fs/cifs/transport.c

index 50844d51da5d98c907af8be48a8b5ec5442fd8ef..7d00802f972239cfc6c6dadde2a5f9532b7baf13 100644 (file)
@@ -83,7 +83,7 @@ extern struct mid_q_entry *AllocMidQEntry(const struct smb_hdr *smb_buffer,
                                        struct TCP_Server_Info *server);
 extern void DeleteMidQEntry(struct mid_q_entry *midEntry);
 extern void cifs_delete_mid(struct mid_q_entry *mid);
-extern void cifs_mid_q_entry_release(struct mid_q_entry *midEntry);
+void _cifs_mid_q_entry_release(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);
@@ -637,4 +637,9 @@ static inline int cifs_create_options(struct cifs_sb_info *cifs_sb, int options)
 struct super_block *cifs_get_tcon_super(struct cifs_tcon *tcon);
 void cifs_put_tcon_super(struct super_block *sb);
 
+static inline void cifs_mid_q_entry_release(struct mid_q_entry *midEntry)
+{
+       kref_put(&midEntry->refcount, _cifs_mid_q_entry_release);
+}
+
 #endif                 /* _CIFSPROTO_H */
index 8f409404aee1e24910264a52b6bac90f8decfda5..89a2f38f17f37f574cf1c98efce079bfb2799ce0 100644 (file)
@@ -759,7 +759,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 8cf12c106afa1dec76dfbc368530e1d65e82af00..c5c1e743359ddb42c6a42a8c0b86dd65c164c656 100644 (file)
@@ -75,7 +75,7 @@ AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server)
        return temp;
 }
 
-static void _cifs_mid_q_entry_release(struct kref *refcount)
+void _cifs_mid_q_entry_release(struct kref *refcount)
 {
        struct mid_q_entry *midEntry =
                        container_of(refcount, struct mid_q_entry, refcount);
@@ -155,13 +155,6 @@ static void _cifs_mid_q_entry_release(struct kref *refcount)
        mempool_free(midEntry, cifs_mid_poolp);
 }
 
-void cifs_mid_q_entry_release(struct mid_q_entry *midEntry)
-{
-       spin_lock(&GlobalMid_Lock);
-       kref_put(&midEntry->refcount, _cifs_mid_q_entry_release);
-       spin_unlock(&GlobalMid_Lock);
-}
-
 void DeleteMidQEntry(struct mid_q_entry *midEntry)
 {
        cifs_mid_q_entry_release(midEntry);