summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Wysochanski <dwysocha@redhat.com>2019-10-03 01:16:27 -0400
committerSteve French <stfrench@microsoft.com>2019-10-06 23:04:57 -0400
commitcb248819d209d113e45fed459773991518e8e80b (patch)
tree40d60b9d81cb0cc4cda0f06d204892a479aa2b64
parentdd19c106a36690b47bb1acc68372f2b472b495b8 (diff)
cifs: use cifsInodeInfo->open_file_lock while iterating to avoid a panic
Commit 487317c99477 ("cifs: add spinlock for the openFileList to cifsInodeInfo") added cifsInodeInfo->open_file_lock spin_lock to protect the openFileList, but missed a few places where cifs_inode->openFileList was enumerated. Change these remaining tcon->open_file_lock to cifsInodeInfo->open_file_lock to avoid panic in is_size_safe_to_change. [17313.245641] RIP: 0010:is_size_safe_to_change+0x57/0xb0 [cifs] [17313.245645] Code: 68 40 48 89 ef e8 19 67 b7 f1 48 8b 43 40 48 8d 4b 40 48 8d 50 f0 48 39 c1 75 0f eb 47 48 8b 42 10 48 8d 50 f0 48 39 c1 74 3a <8b> 80 88 00 00 00 83 c0 01 a8 02 74 e6 48 89 ef c6 07 00 0f 1f 40 [17313.245649] RSP: 0018:ffff94ae1baefa30 EFLAGS: 00010202 [17313.245654] RAX: dead000000000100 RBX: ffff88dc72243300 RCX: ffff88dc72243340 [17313.245657] RDX: dead0000000000f0 RSI: 00000000098f7940 RDI: ffff88dd3102f040 [17313.245659] RBP: ffff88dd3102f040 R08: 0000000000000000 R09: ffff94ae1baefc40 [17313.245661] R10: ffffcdc8bb1c4e80 R11: ffffcdc8b50adb08 R12: 00000000098f7940 [17313.245663] R13: ffff88dc72243300 R14: ffff88dbc8f19600 R15: ffff88dc72243428 [17313.245667] FS: 00007fb145485700(0000) GS:ffff88dd3e000000(0000) knlGS:0000000000000000 [17313.245670] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [17313.245672] CR2: 0000026bb46c6000 CR3: 0000004edb110003 CR4: 00000000007606e0 [17313.245753] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [17313.245756] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [17313.245759] PKRU: 55555554 [17313.245761] Call Trace: [17313.245803] cifs_fattr_to_inode+0x16b/0x580 [cifs] [17313.245838] cifs_get_inode_info+0x35c/0xa60 [cifs] [17313.245852] ? kmem_cache_alloc_trace+0x151/0x1d0 [17313.245885] cifs_open+0x38f/0x990 [cifs] [17313.245921] ? cifs_revalidate_dentry_attr+0x3e/0x350 [cifs] [17313.245953] ? cifsFileInfo_get+0x30/0x30 [cifs] [17313.245960] ? do_dentry_open+0x132/0x330 [17313.245963] do_dentry_open+0x132/0x330 [17313.245969] path_openat+0x573/0x14d0 [17313.245974] do_filp_open+0x93/0x100 [17313.245979] ? __check_object_size+0xa3/0x181 [17313.245986] ? audit_alloc_name+0x7e/0xd0 [17313.245992] do_sys_open+0x184/0x220 [17313.245999] do_syscall_64+0x5b/0x1b0 Fixes: 487317c99477 ("cifs: add spinlock for the openFileList to cifsInodeInfo") CC: Stable <stable@vger.kernel.org> Signed-off-by: Dave Wysochanski <dwysocha@redhat.com> Reviewed-by: Ronnie Sahlberg <lsahlber@redhat.com> Signed-off-by: Steve French <stfrench@microsoft.com>
-rw-r--r--fs/cifs/file.c27
1 files changed, 11 insertions, 16 deletions
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 4b95700c507c..3758237bf951 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -1840,13 +1840,12 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
1840{ 1840{
1841 struct cifsFileInfo *open_file = NULL; 1841 struct cifsFileInfo *open_file = NULL;
1842 struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb); 1842 struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);
1843 struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
1844 1843
1845 /* only filter by fsuid on multiuser mounts */ 1844 /* only filter by fsuid on multiuser mounts */
1846 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)) 1845 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
1847 fsuid_only = false; 1846 fsuid_only = false;
1848 1847
1849 spin_lock(&tcon->open_file_lock); 1848 spin_lock(&cifs_inode->open_file_lock);
1850 /* we could simply get the first_list_entry since write-only entries 1849 /* we could simply get the first_list_entry since write-only entries
1851 are always at the end of the list but since the first entry might 1850 are always at the end of the list but since the first entry might
1852 have a close pending, we go through the whole list */ 1851 have a close pending, we go through the whole list */
@@ -1858,7 +1857,7 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
1858 /* found a good file */ 1857 /* found a good file */
1859 /* lock it so it will not be closed on us */ 1858 /* lock it so it will not be closed on us */
1860 cifsFileInfo_get(open_file); 1859 cifsFileInfo_get(open_file);
1861 spin_unlock(&tcon->open_file_lock); 1860 spin_unlock(&cifs_inode->open_file_lock);
1862 return open_file; 1861 return open_file;
1863 } /* else might as well continue, and look for 1862 } /* else might as well continue, and look for
1864 another, or simply have the caller reopen it 1863 another, or simply have the caller reopen it
@@ -1866,7 +1865,7 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
1866 } else /* write only file */ 1865 } else /* write only file */
1867 break; /* write only files are last so must be done */ 1866 break; /* write only files are last so must be done */
1868 } 1867 }
1869 spin_unlock(&tcon->open_file_lock); 1868 spin_unlock(&cifs_inode->open_file_lock);
1870 return NULL; 1869 return NULL;
1871} 1870}
1872 1871
@@ -1877,7 +1876,6 @@ cifs_get_writable_file(struct cifsInodeInfo *cifs_inode, bool fsuid_only,
1877{ 1876{
1878 struct cifsFileInfo *open_file, *inv_file = NULL; 1877 struct cifsFileInfo *open_file, *inv_file = NULL;
1879 struct cifs_sb_info *cifs_sb; 1878 struct cifs_sb_info *cifs_sb;
1880 struct cifs_tcon *tcon;
1881 bool any_available = false; 1879 bool any_available = false;
1882 int rc = -EBADF; 1880 int rc = -EBADF;
1883 unsigned int refind = 0; 1881 unsigned int refind = 0;
@@ -1897,16 +1895,15 @@ cifs_get_writable_file(struct cifsInodeInfo *cifs_inode, bool fsuid_only,
1897 } 1895 }
1898 1896
1899 cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb); 1897 cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);
1900 tcon = cifs_sb_master_tcon(cifs_sb);
1901 1898
1902 /* only filter by fsuid on multiuser mounts */ 1899 /* only filter by fsuid on multiuser mounts */
1903 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)) 1900 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
1904 fsuid_only = false; 1901 fsuid_only = false;
1905 1902
1906 spin_lock(&tcon->open_file_lock); 1903 spin_lock(&cifs_inode->open_file_lock);
1907refind_writable: 1904refind_writable:
1908 if (refind > MAX_REOPEN_ATT) { 1905 if (refind > MAX_REOPEN_ATT) {
1909 spin_unlock(&tcon->open_file_lock); 1906 spin_unlock(&cifs_inode->open_file_lock);
1910 return rc; 1907 return rc;
1911 } 1908 }
1912 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { 1909 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
@@ -1918,7 +1915,7 @@ refind_writable:
1918 if (!open_file->invalidHandle) { 1915 if (!open_file->invalidHandle) {
1919 /* found a good writable file */ 1916 /* found a good writable file */
1920 cifsFileInfo_get(open_file); 1917 cifsFileInfo_get(open_file);
1921 spin_unlock(&tcon->open_file_lock); 1918 spin_unlock(&cifs_inode->open_file_lock);
1922 *ret_file = open_file; 1919 *ret_file = open_file;
1923 return 0; 1920 return 0;
1924 } else { 1921 } else {
@@ -1938,7 +1935,7 @@ refind_writable:
1938 cifsFileInfo_get(inv_file); 1935 cifsFileInfo_get(inv_file);
1939 } 1936 }
1940 1937
1941 spin_unlock(&tcon->open_file_lock); 1938 spin_unlock(&cifs_inode->open_file_lock);
1942 1939
1943 if (inv_file) { 1940 if (inv_file) {
1944 rc = cifs_reopen_file(inv_file, false); 1941 rc = cifs_reopen_file(inv_file, false);
@@ -1953,7 +1950,7 @@ refind_writable:
1953 cifsFileInfo_put(inv_file); 1950 cifsFileInfo_put(inv_file);
1954 ++refind; 1951 ++refind;
1955 inv_file = NULL; 1952 inv_file = NULL;
1956 spin_lock(&tcon->open_file_lock); 1953 spin_lock(&cifs_inode->open_file_lock);
1957 goto refind_writable; 1954 goto refind_writable;
1958 } 1955 }
1959 1956
@@ -4461,17 +4458,15 @@ static int cifs_readpage(struct file *file, struct page *page)
4461static int is_inode_writable(struct cifsInodeInfo *cifs_inode) 4458static int is_inode_writable(struct cifsInodeInfo *cifs_inode)
4462{ 4459{
4463 struct cifsFileInfo *open_file; 4460 struct cifsFileInfo *open_file;
4464 struct cifs_tcon *tcon =
4465 cifs_sb_master_tcon(CIFS_SB(cifs_inode->vfs_inode.i_sb));
4466 4461
4467 spin_lock(&tcon->open_file_lock); 4462 spin_lock(&cifs_inode->open_file_lock);
4468 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { 4463 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
4469 if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) { 4464 if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) {
4470 spin_unlock(&tcon->open_file_lock); 4465 spin_unlock(&cifs_inode->open_file_lock);
4471 return 1; 4466 return 1;
4472 } 4467 }
4473 } 4468 }
4474 spin_unlock(&tcon->open_file_lock); 4469 spin_unlock(&cifs_inode->open_file_lock);
4475 return 0; 4470 return 0;
4476} 4471}
4477 4472