summaryrefslogtreecommitdiff
path: root/fs/fuse/dev.c
diff options
context:
space:
mode:
authorJoanne Koong <joannelkoong@gmail.com>2026-01-20 14:44:46 -0800
committerMiklos Szeredi <mszeredi@redhat.com>2026-03-03 10:05:39 +0100
commit65161470f95bb579a72673bf303ecf0800b9054b (patch)
treea4303a356eea3ff069b5fa68c89d5123bdf95709 /fs/fuse/dev.c
parent59ba47b6be9cd0146ef9a55c6e32e337e11e7625 (diff)
downloadlinux-next-65161470f95bb579a72673bf303ecf0800b9054b.tar.gz
linux-next-65161470f95bb579a72673bf303ecf0800b9054b.zip
fuse: validate outarg offset and size in notify store/retrieve
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>
Diffstat (limited to 'fs/fuse/dev.c')
-rw-r--r--fs/fuse/dev.c14
1 files changed, 10 insertions, 4 deletions
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 8596e693970b..8e23ec84ec8a 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -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;