Message ID | 20231030201956.2660-3-pc@manguebit.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | [1/4] smb: client: remove extra @chan_count check in __cifs_put_smb_ses() | expand |
fix was already in cifs-2.6.git for-next, but added Cc: stable Let me know if I missed anything On Mon, Oct 30, 2023 at 3:20 PM Paulo Alcantara <pc@manguebit.com> wrote: > > 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 anyway. > > 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: Frank Sorenson <sorenson@redhat.com> > Signed-off-by: Paulo Alcantara (SUSE) <pc@manguebit.com> > --- > fs/smb/client/cifsproto.h | 7 ++++++- > fs/smb/client/smb2misc.c | 2 +- > fs/smb/client/transport.c | 11 +---------- > 3 files changed, 8 insertions(+), 12 deletions(-) > > diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h > index 0c37eefa18a5..890ceddae07e 100644 > --- a/fs/smb/client/cifsproto.h > +++ b/fs/smb/client/cifsproto.h > @@ -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); > @@ -740,4 +740,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 */ > diff --git a/fs/smb/client/smb2misc.c b/fs/smb/client/smb2misc.c > index 25f7cd6f23d6..32dfa0f7a78c 100644 > --- a/fs/smb/client/smb2misc.c > +++ b/fs/smb/client/smb2misc.c > @@ -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; > > diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c > index 14710afdc2a3..d553b7a54621 100644 > --- a/fs/smb/client/transport.c > +++ b/fs/smb/client/transport.c > @@ -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) > { > -- > 2.42.0 >
diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h index 0c37eefa18a5..890ceddae07e 100644 --- a/fs/smb/client/cifsproto.h +++ b/fs/smb/client/cifsproto.h @@ -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); @@ -740,4 +740,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 */ diff --git a/fs/smb/client/smb2misc.c b/fs/smb/client/smb2misc.c index 25f7cd6f23d6..32dfa0f7a78c 100644 --- a/fs/smb/client/smb2misc.c +++ b/fs/smb/client/smb2misc.c @@ -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; diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c index 14710afdc2a3..d553b7a54621 100644 --- a/fs/smb/client/transport.c +++ b/fs/smb/client/transport.c @@ -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) {
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 anyway. 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: Frank Sorenson <sorenson@redhat.com> Signed-off-by: Paulo Alcantara (SUSE) <pc@manguebit.com> --- fs/smb/client/cifsproto.h | 7 ++++++- fs/smb/client/smb2misc.c | 2 +- fs/smb/client/transport.c | 11 +---------- 3 files changed, 8 insertions(+), 12 deletions(-)