aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/smb2inode.c
diff options
context:
space:
mode:
authorSteve French <stfrench@microsoft.com>2022-05-12 10:18:00 -0500
committerSteve French <stfrench@microsoft.com>2022-05-17 13:47:27 -0500
commit0a55cf74ffb5d004b93647e4389096880ce37d6b (patch)
treea2e7894e68b7b08eef200b50ca2dabec3f1454ee /fs/cifs/smb2inode.c
parentLinux 5.18-rc7 (diff)
downloadlinux-dev-0a55cf74ffb5d004b93647e4389096880ce37d6b.tar.xz
linux-dev-0a55cf74ffb5d004b93647e4389096880ce37d6b.zip
SMB3: EBADF/EIO errors in rename/open caused by race condition in smb2_compound_op
There is a race condition in smb2_compound_op: after_close: num_rqst++; if (cfile) { cifsFileInfo_put(cfile); // sends SMB2_CLOSE to the server cfile = NULL; This is triggered by smb2_query_path_info operation that happens during revalidate_dentry. In smb2_query_path_info, get_readable_path is called to load the cfile, increasing the reference counter. If in the meantime, this reference becomes the very last, this call to cifsFileInfo_put(cfile) will trigger a SMB2_CLOSE request sent to the server just before sending this compound request – and so then the compound request fails either with EBADF/EIO depending on the timing at the server, because the handle is already closed. In the first scenario, the race seems to be happening between smb2_query_path_info triggered by the rename operation, and between “cleanup” of asynchronous writes – while fsync(fd) likely waits for the asynchronous writes to complete, releasing the writeback structures can happen after the close(fd) call. So the EBADF/EIO errors will pop up if the timing is such that: 1) There are still outstanding references after close(fd) in the writeback structures 2) smb2_query_path_info successfully fetches the cfile, increasing the refcounter by 1 3) All writeback structures release the same cfile, reducing refcounter to 1 4) smb2_compound_op is called with that cfile In the second scenario, the race seems to be similar – here open triggers the smb2_query_path_info operation, and if all other threads in the meantime decrease the refcounter to 1 similarly to the first scenario, again SMB2_CLOSE will be sent to the server just before issuing the compound request. This case is harder to reproduce. See https://bugzilla.samba.org/show_bug.cgi?id=15051 Cc: stable@vger.kernel.org Fixes: 8de9e86c67ba ("cifs: create a helper to find a writeable handle by path name") Signed-off-by: Ondrej Hubsch <ohubsch@purestorage.com> Reviewed-by: Ronnie Sahlberg <lsahlber@redhat.com> Reviewed-by: Paulo Alcantara (SUSE) <pc@cjr.nz> Signed-off-by: Steve French <stfrench@microsoft.com>
Diffstat (limited to 'fs/cifs/smb2inode.c')
-rw-r--r--fs/cifs/smb2inode.c2
1 files changed, 0 insertions, 2 deletions
diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c
index fe5bfa245fa7..1b89b9b8a212 100644
--- a/fs/cifs/smb2inode.c
+++ b/fs/cifs/smb2inode.c
@@ -362,8 +362,6 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
num_rqst++;
if (cfile) {
- cifsFileInfo_put(cfile);
- cfile = NULL;
rc = compound_send_recv(xid, ses, server,
flags, num_rqst - 2,
&rqst[1], &resp_buftype[1],