diff options
author | Dave Wysochanski <dwysocha@redhat.com> | 2019-10-03 01:16:27 -0400 |
---|---|---|
committer | Steve French <stfrench@microsoft.com> | 2019-10-06 23:04:57 -0400 |
commit | cb248819d209d113e45fed459773991518e8e80b (patch) | |
tree | 40d60b9d81cb0cc4cda0f06d204892a479aa2b64 | |
parent | dd19c106a36690b47bb1acc68372f2b472b495b8 (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.c | 27 |
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); |
1907 | refind_writable: | 1904 | refind_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) | |||
4461 | static int is_inode_writable(struct cifsInodeInfo *cifs_inode) | 4458 | static 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 | ||