fuse: don't overflow LLONG_MAX with end offset
authorMiklos Szeredi <mszeredi@redhat.com>
Thu, 6 Feb 2020 15:39:28 +0000 (16:39 +0100)
committerMiklos Szeredi <mszeredi@redhat.com>
Thu, 6 Feb 2020 15:39:28 +0000 (16:39 +0100)
Handle the special case of fuse_readpages() wanting to read the last page
of a hugest file possible and overflowing the end offset in the process.

This is basically to unbreak xfstests:generic/525 and prevent filesystems
from doing bad things with an overflowing offset.

Reported-by: Xiao Yang <ice_yangxiao@163.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
fs/fuse/file.c

index 695369f46f92d1d42701c6205185fa9434ac70d6..3dd37a998ea93a1b92722612d00860e9347d66bd 100644 (file)
@@ -803,6 +803,10 @@ static int fuse_do_readpage(struct file *file, struct page *page)
 
        attr_ver = fuse_get_attr_version(fc);
 
+       /* Don't overflow end offset */
+       if (pos + (desc.length - 1) == LLONG_MAX)
+               desc.length--;
+
        fuse_read_args_fill(&ia, file, pos, desc.length, FUSE_READ);
        res = fuse_simple_request(fc, &ia.ap.args);
        if (res < 0)
@@ -888,6 +892,14 @@ static void fuse_send_readpages(struct fuse_io_args *ia, struct file *file)
        ap->args.out_pages = true;
        ap->args.page_zeroing = true;
        ap->args.page_replace = true;
+
+       /* Don't overflow end offset */
+       if (pos + (count - 1) == LLONG_MAX) {
+               count--;
+               ap->descs[ap->num_pages - 1].length--;
+       }
+       WARN_ON((loff_t) (pos + count) < 0);
+
        fuse_read_args_fill(ia, file, pos, count, FUSE_READ);
        ia->read.attr_ver = fuse_get_attr_version(fc);
        if (fc->async_read) {