diff options
| author | Joanne Koong <joannelkoong@gmail.com> | 2026-01-20 14:44:46 -0800 |
|---|---|---|
| committer | Miklos Szeredi <mszeredi@redhat.com> | 2026-03-03 10:05:39 +0100 |
| commit | 65161470f95bb579a72673bf303ecf0800b9054b (patch) | |
| tree | a4303a356eea3ff069b5fa68c89d5123bdf95709 /fs/fuse/dev.c | |
| parent | 59ba47b6be9cd0146ef9a55c6e32e337e11e7625 (diff) | |
| download | linux-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.c | 14 |
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; |
