summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPavel Shilovsky <pshilov@microsoft.com>2019-10-23 18:37:19 -0400
committerSteve French <stfrench@microsoft.com>2019-10-24 22:32:35 -0400
commit1a67c415965752879e2e9fad407bc44fc7f25f23 (patch)
treec66e3fc9f7fb3181082d2982b1f5db7278ba8ad7
parentabe57073d08c13b95a46ccf48cc9dc957d5c6fdb (diff)
CIFS: Fix use after free of file info structures
Currently the code assumes that if a file info entry belongs to lists of open file handles of an inode and a tcon then it has non-zero reference. The recent changes broke that assumption when putting the last reference of the file info. There may be a situation when a file is being deleted but nothing prevents another thread to reference it again and start using it. This happens because we do not hold the inode list lock while checking the number of references of the file info structure. Fix this by doing the proper locking when doing the check. Fixes: 487317c99477d ("cifs: add spinlock for the openFileList to cifsInodeInfo") Fixes: cb248819d209d ("cifs: use cifsInodeInfo->open_file_lock while iterating to avoid a panic") Cc: Stable <stable@vger.kernel.org> Reviewed-by: Ronnie Sahlberg <lsahlber@redhat.com> Signed-off-by: Pavel Shilovsky <pshilov@microsoft.com> Signed-off-by: Steve French <stfrench@microsoft.com>
-rw-r--r--fs/cifs/file.c6
1 files changed, 3 insertions, 3 deletions
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 5ad15de2bb4f..64827938ecf7 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -405,10 +405,11 @@ void _cifsFileInfo_put(struct cifsFileInfo *cifs_file, bool wait_oplock_handler)
405 bool oplock_break_cancelled; 405 bool oplock_break_cancelled;
406 406
407 spin_lock(&tcon->open_file_lock); 407 spin_lock(&tcon->open_file_lock);
408 408 spin_lock(&cifsi->open_file_lock);
409 spin_lock(&cifs_file->file_info_lock); 409 spin_lock(&cifs_file->file_info_lock);
410 if (--cifs_file->count > 0) { 410 if (--cifs_file->count > 0) {
411 spin_unlock(&cifs_file->file_info_lock); 411 spin_unlock(&cifs_file->file_info_lock);
412 spin_unlock(&cifsi->open_file_lock);
412 spin_unlock(&tcon->open_file_lock); 413 spin_unlock(&tcon->open_file_lock);
413 return; 414 return;
414 } 415 }
@@ -421,9 +422,7 @@ void _cifsFileInfo_put(struct cifsFileInfo *cifs_file, bool wait_oplock_handler)
421 cifs_add_pending_open_locked(&fid, cifs_file->tlink, &open); 422 cifs_add_pending_open_locked(&fid, cifs_file->tlink, &open);
422 423
423 /* remove it from the lists */ 424 /* remove it from the lists */
424 spin_lock(&cifsi->open_file_lock);
425 list_del(&cifs_file->flist); 425 list_del(&cifs_file->flist);
426 spin_unlock(&cifsi->open_file_lock);
427 list_del(&cifs_file->tlist); 426 list_del(&cifs_file->tlist);
428 atomic_dec(&tcon->num_local_opens); 427 atomic_dec(&tcon->num_local_opens);
429 428
@@ -440,6 +439,7 @@ void _cifsFileInfo_put(struct cifsFileInfo *cifs_file, bool wait_oplock_handler)
440 cifs_set_oplock_level(cifsi, 0); 439 cifs_set_oplock_level(cifsi, 0);
441 } 440 }
442 441
442 spin_unlock(&cifsi->open_file_lock);
443 spin_unlock(&tcon->open_file_lock); 443 spin_unlock(&tcon->open_file_lock);
444 444
445 oplock_break_cancelled = wait_oplock_handler ? 445 oplock_break_cancelled = wait_oplock_handler ?