Commit cbe30b89 authored by Paulo Alcantara's avatar Paulo Alcantara Committed by Wang Zhaolong
Browse files

smb: client: fix potential deadlock when releasing mids

mainline inclusion
from mainline-v6.7-rc1
commit e6322fd177c6885a21dd4609dc5e5c973d1a2eb7
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/I9R4KS
CVE: CVE-2023-52757

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=e6322fd177c6885a21dd4609dc5e5c973d1a2eb7



--------------------------------

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: default avatarPaulo Alcantara (SUSE) <pc@manguebit.com>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
Conflicts:
    fs/smb/client/cifsproto.h
    fs/smb/client/smb2misc.c
    fs/smb/client/transport.c
    fs/cifs/cifsproto.h
    fs/cifs/smb2misc.c
    fs/cifs/transport.c
[Path is changed and related functions has been refactored for a long time]
Signed-off-by: default avatarWang Zhaolong <wangzhaolong1@huawei.com>
parent f4b00a3e
Loading
Loading
Loading
Loading
+6 −1
Original line number Diff line number Diff line
@@ -85,7 +85,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);
@@ -646,4 +646,9 @@ static inline int cifs_create_options(struct cifs_sb_info *cifs_sb, int options)
		return options;
}

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 */
+1 −1
Original line number Diff line number Diff line
@@ -780,7 +780,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;

+1 −8
Original line number Diff line number Diff line
@@ -88,7 +88,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);
@@ -168,13 +168,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);