The commit is pushed to "branch-rh8-4.18.0-240.1.1.vz8.5.x-ovz" and will appear 
at https://src.openvz.org/scm/ovz/vzkernel.git
after rh8-4.18.0-240.1.1.vz8.5.19
------>
commit e09b1fecb7cb6aee6a822e7a1dfb3ea8c97020d7
Author: Alexey Kuznetsov <kuz...@acronis.com>
Date:   Fri Apr 23 11:55:02 2021 +0300

    fs/fuse: released handle could be used in fiemap
    
    It was missed that handle must be held while passing request to user,
    otherwise vstorage-mount can crash.
    
    https://pmc.acronis.com/browse/VSTOR-42949
    Signed-off-by: Alexey Kuznetsov <kuz...@acronis.com>
    Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 fs/fuse/file.c | 39 +++++++++++++++++++++++++++++----------
 1 file changed, 29 insertions(+), 10 deletions(-)

diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index b0db23314971..e08e557ecaf2 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -3860,8 +3860,9 @@ static int fuse_request_fiemap(struct inode *inode, u32 
cur_max,
 {
        struct fuse_conn *fc = get_fuse_conn(inode);
        struct fuse_inode *fi = get_fuse_inode(inode);
+       struct fuse_file *ff = NULL;
        struct fuse_args_pages ap = {};
-       struct fuse_ioctl_in inarg;
+       struct fuse_ioctl_in inarg = (struct fuse_ioctl_in) { .cmd = 
FS_IOC_FIEMAP };
        struct fuse_ioctl_out outarg;
        struct fiemap ifiemap;
        struct fiemap ofiemap;
@@ -3871,11 +3872,30 @@ static int fuse_request_fiemap(struct inode *inode, u32 
cur_max,
 
        err = 0;
        spin_lock(&fi->lock);
-       if (!list_empty(&fi->write_files)) {
-               struct fuse_file *ff = list_entry(fi->write_files.next, struct 
fuse_file, write_entry);
+       /* Kernel API is weird in this place, we have to find a file associated 
with this inode.
+        * This problem is similar to writepage routines, but it is much worse. 
When doing
+        * writepage, we have some file open for write and can take any file 
from write_files
+        * and it is safe to keep it with get/put. But here we can have the 
file open for read
+        * and no files open for write. Even worse, if we select a random file 
open for write,
+        * it can be closed by user from another thread and its close will 
violate close_wait requirement.
+        * So, we have to search for a read-only file first and fallback to 
writable only
+        * if there is no such file.
+        */
+       if (!list_empty(&fi->rw_files)) {
+               struct fuse_file *t_ff;
+               list_for_each_entry(t_ff, &fi->rw_files, rw_entry) {
+                       if (list_empty(&t_ff->write_entry)) {
+                               ff = t_ff;
+                               break;
+                       }
+               }
+               if (!ff)
+                       ff = list_entry(fi->rw_files.next, struct fuse_file, 
rw_entry);
+               fuse_file_get(ff);
                inarg.fh = ff->fh;
-       } else if (!list_empty(&fi->rw_files)) {
-               struct fuse_file *ff = list_entry(fi->rw_files.next, struct 
fuse_file, rw_entry);
+       } else if (!list_empty(&fi->write_files)) {
+               ff = list_entry(fi->write_files.next, struct fuse_file, 
write_entry);
+               fuse_file_get(ff);
                inarg.fh = ff->fh;
        } else {
                err = -EINVAL;
@@ -3884,10 +3904,6 @@ static int fuse_request_fiemap(struct inode *inode, u32 
cur_max,
        if (err)
                return err;
 
-       inarg.cmd = FS_IOC_FIEMAP;
-       inarg.arg = 0;
-       inarg.flags = 0;
-
        ifiemap.fm_start = *start_p;
        ifiemap.fm_length = *len_p;
        ifiemap.fm_flags = dest->fi_flags;
@@ -3899,8 +3915,10 @@ static int fuse_request_fiemap(struct inode *inode, u32 
cur_max,
                npages = (cur_max*sizeof(struct fiemap_extent) + PAGE_SIZE - 1) 
/ PAGE_SIZE;
 
        ap.pages = fuse_pages_alloc(fc->max_pages, GFP_KERNEL, &ap.descs);
-       if (!ap.pages)
+       if (!ap.pages) {
+               fuse_file_put(ff, false, false);
                return -ENOMEM;
+       }
 
        ap.args.io_inode = inode;
        ap.args.opcode = FUSE_IOCTL;
@@ -3982,6 +4000,7 @@ static int fuse_request_fiemap(struct inode *inode, u32 
cur_max,
                __free_page(ap.pages[allocated]);
                ap.pages[allocated] = NULL;
        }
+       fuse_file_put(ff, false, false);
        return err;
 }
 
_______________________________________________
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel

Reply via email to