Skip to content

Commit 7e5a70a

Browse files
aaptelsmfrench
authored andcommitted
CIFS: fix deadlock in cached root handling
Prevent deadlock between open_shroot() and cifs_mark_open_files_invalid() by releasing the lock before entering SMB2_open, taking it again after and checking if we still need to use the result. Link: https://lore.kernel.org/linux-cifs/[email protected]/T/#u Fixes: 3d4ef9a ("smb3: fix redundant opens on root") Signed-off-by: Aurelien Aptel <[email protected]> Reviewed-by: Pavel Shilovsky <[email protected]> Signed-off-by: Steve French <[email protected]> CC: Stable <[email protected]>
1 parent ae9b728 commit 7e5a70a

File tree

1 file changed

+45
-1
lines changed

1 file changed

+45
-1
lines changed

fs/cifs/smb2ops.c

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -694,8 +694,51 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid)
694694

695695
smb2_set_related(&rqst[1]);
696696

697+
/*
698+
* We do not hold the lock for the open because in case
699+
* SMB2_open needs to reconnect, it will end up calling
700+
* cifs_mark_open_files_invalid() which takes the lock again
701+
* thus causing a deadlock
702+
*/
703+
704+
mutex_unlock(&tcon->crfid.fid_mutex);
697705
rc = compound_send_recv(xid, ses, flags, 2, rqst,
698706
resp_buftype, rsp_iov);
707+
mutex_lock(&tcon->crfid.fid_mutex);
708+
709+
/*
710+
* Now we need to check again as the cached root might have
711+
* been successfully re-opened from a concurrent process
712+
*/
713+
714+
if (tcon->crfid.is_valid) {
715+
/* work was already done */
716+
717+
/* stash fids for close() later */
718+
struct cifs_fid fid = {
719+
.persistent_fid = pfid->persistent_fid,
720+
.volatile_fid = pfid->volatile_fid,
721+
};
722+
723+
/*
724+
* caller expects this func to set pfid to a valid
725+
* cached root, so we copy the existing one and get a
726+
* reference.
727+
*/
728+
memcpy(pfid, tcon->crfid.fid, sizeof(*pfid));
729+
kref_get(&tcon->crfid.refcount);
730+
731+
mutex_unlock(&tcon->crfid.fid_mutex);
732+
733+
if (rc == 0) {
734+
/* close extra handle outside of crit sec */
735+
SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
736+
}
737+
goto oshr_free;
738+
}
739+
740+
/* Cached root is still invalid, continue normaly */
741+
699742
if (rc)
700743
goto oshr_exit;
701744

@@ -729,8 +772,9 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid)
729772
(char *)&tcon->crfid.file_all_info))
730773
tcon->crfid.file_all_info_is_valid = 1;
731774

732-
oshr_exit:
775+
oshr_exit:
733776
mutex_unlock(&tcon->crfid.fid_mutex);
777+
oshr_free:
734778
SMB2_open_free(&rqst[0]);
735779
SMB2_query_info_free(&rqst[1]);
736780
free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);

0 commit comments

Comments
 (0)