]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
fuse: validate outarg offset and size in notify store/retrieve
authorJoanne Koong <joannelkoong@gmail.com>
Tue, 20 Jan 2026 22:44:46 +0000 (14:44 -0800)
committerMiklos Szeredi <mszeredi@redhat.com>
Tue, 3 Mar 2026 09:05:39 +0000 (10:05 +0100)
Add validation checking for outarg offset and outarg size values passed
in by the server. MAX_LFS_FILESIZE is the maximum file size supported.
The fuse_notify_store_out and fuse_notify_retrieve_out structs take in
a uint64_t offset.

Add logic to ensure:
* outarg.offset is less than MAX_LFS_FILESIZE
* outarg.offset + outarg.size cannot exceed MAX_LFS_FILESIZE
* potential uint64_t overflow is fixed when adding outarg.offset and
  outarg.size.

Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
fs/fuse/dev.c

index 8596e693970bf15824b949a4c21571140d58188d..8e23ec84ec8a9ab6465b421276a53ec9fb3ef091 100644 (file)
@@ -1783,7 +1783,11 @@ static int fuse_notify_store(struct fuse_conn *fc, unsigned int size,
        if (size - sizeof(outarg) != outarg.size)
                return -EINVAL;
 
+       if (outarg.offset >= MAX_LFS_FILESIZE)
+               return -EINVAL;
+
        nodeid = outarg.nodeid;
+       num = min(outarg.size, MAX_LFS_FILESIZE - outarg.offset);
 
        down_read(&fc->killsb);
 
@@ -1796,13 +1800,12 @@ static int fuse_notify_store(struct fuse_conn *fc, unsigned int size,
        index = outarg.offset >> PAGE_SHIFT;
        offset = outarg.offset & ~PAGE_MASK;
        file_size = i_size_read(inode);
-       end = outarg.offset + outarg.size;
+       end = outarg.offset + num;
        if (end > file_size) {
                file_size = end;
-               fuse_write_update_attr(inode, file_size, outarg.size);
+               fuse_write_update_attr(inode, file_size, num);
        }
 
-       num = outarg.size;
        while (num) {
                struct folio *folio;
                unsigned int folio_offset;
@@ -1882,7 +1885,7 @@ static int fuse_retrieve(struct fuse_mount *fm, struct inode *inode,
        num = min(outarg->size, fc->max_write);
        if (outarg->offset > file_size)
                num = 0;
-       else if (outarg->offset + num > file_size)
+       else if (num > file_size - outarg->offset)
                num = file_size - outarg->offset;
 
        num_pages = (num + offset + PAGE_SIZE - 1) >> PAGE_SHIFT;
@@ -1964,6 +1967,9 @@ static int fuse_notify_retrieve(struct fuse_conn *fc, unsigned int size,
 
        fuse_copy_finish(cs);
 
+       if (outarg.offset >= MAX_LFS_FILESIZE)
+               return -EINVAL;
+
        down_read(&fc->killsb);
        err = -ENOENT;
        nodeid = outarg.nodeid;