Skip to content

Commit

Permalink
smb: client: fix potential deadlock when releasing mids
Browse files Browse the repository at this point in the history
commit e6322fd 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>
  • Loading branch information
pcacjr authored and gregkh committed Nov 28, 2023
1 parent 5588175 commit 9eb44db
Show file tree
Hide file tree
Showing 3 changed files with 8 additions and 12 deletions.
7 changes: 6 additions & 1 deletion fs/smb/client/cifsproto.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ extern char *cifs_compose_mount_options(const char *sb_mountdata,
const char *fullpath, const struct dfs_info3_param *ref,
char **devname);
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);
Expand Down Expand Up @@ -694,4 +694,9 @@ struct super_block *cifs_get_tcon_super(struct cifs_tcon *tcon);
void cifs_put_tcon_super(struct super_block *sb);
int cifs_wait_for_server_reconnect(struct TCP_Server_Info *server, bool retry);

static inline void release_mid(struct mid_q_entry *mid)
{
kref_put(&mid->refcount, __release_mid);
}

#endif /* _CIFSPROTO_H */
2 changes: 1 addition & 1 deletion fs/smb/client/smb2misc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
11 changes: 1 addition & 10 deletions fs/smb/client/transport.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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)
{
Expand Down

0 comments on commit 9eb44db

Please sign in to comment.