| From d6b94584b9a7f11c5e9ea09520741baa8a1ff732 Mon Sep 17 00:00:00 2001 |
| From: Pavel Shilovsky <pshilov@microsoft.com> |
| Date: Wed, 23 Oct 2019 15:37:19 -0700 |
| Subject: [PATCH] CIFS: Fix use after free of file info structures |
| |
| commit 1a67c415965752879e2e9fad407bc44fc7f25f23 upstream. |
| |
| 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> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/fs/cifs/file.c b/fs/cifs/file.c |
| index 4c1aeb2cf7f5..53dbb6e0d390 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) |
| bool oplock_break_cancelled; |
| |
| spin_lock(&tcon->open_file_lock); |
| - |
| + spin_lock(&cifsi->open_file_lock); |
| spin_lock(&cifs_file->file_info_lock); |
| if (--cifs_file->count > 0) { |
| spin_unlock(&cifs_file->file_info_lock); |
| + spin_unlock(&cifsi->open_file_lock); |
| spin_unlock(&tcon->open_file_lock); |
| return; |
| } |
| @@ -421,9 +422,7 @@ void _cifsFileInfo_put(struct cifsFileInfo *cifs_file, bool wait_oplock_handler) |
| cifs_add_pending_open_locked(&fid, cifs_file->tlink, &open); |
| |
| /* remove it from the lists */ |
| - spin_lock(&cifsi->open_file_lock); |
| list_del(&cifs_file->flist); |
| - spin_unlock(&cifsi->open_file_lock); |
| list_del(&cifs_file->tlist); |
| atomic_dec(&tcon->num_local_opens); |
| |
| @@ -440,6 +439,7 @@ void _cifsFileInfo_put(struct cifsFileInfo *cifs_file, bool wait_oplock_handler) |
| cifs_set_oplock_level(cifsi, 0); |
| } |
| |
| + spin_unlock(&cifsi->open_file_lock); |
| spin_unlock(&tcon->open_file_lock); |
| |
| oplock_break_cancelled = wait_oplock_handler ? |
| -- |
| 2.7.4 |
| |