From: David Howells dhowells@redhat.com
stable inclusion from stable-v5.10.137 commit cf65b5bfac3d17af93eb375d25c700706549d73d category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I60PLB
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=...
--------------------------------
commit e2ebff9c57fe4eb104ce4768f6ebcccf76bef849 upstream.
If something manages to set the maximum file size to MAX_OFFSET+1, this can cause the xfs and ext4 filesystems at least to become corrupt.
Ordinarily, the kernel protects against userspace trying this by checking the value early in the truncate() and ftruncate() system calls calls - but there are at least two places that this check is bypassed:
(1) Cachefiles will round up the EOF of the backing file to DIO block size so as to allow DIO on the final block - but this might push the offset negative. It then calls notify_change(), but this inadvertently bypasses the checking. This can be triggered if someone puts an 8EiB-1 file on a server for someone else to try and access by, say, nfs.
(2) ksmbd doesn't check the value it is given in set_end_of_file_info() and then calls vfs_truncate() directly - which also bypasses the check.
In both cases, it is potentially possible for a network filesystem to cause a disk filesystem to be corrupted: cachefiles in the client's cache filesystem; ksmbd in the server's filesystem.
nfsd is okay as it checks the value, but we can then remove this check too.
Fix this by adding a check to inode_newsize_ok(), as called from setattr_prepare(), thereby catching the issue as filesystems set up to perform the truncate with minimal opportunity for bypassing the new check.
Fixes: 1f08c925e7a3 ("cachefiles: Implement backing file wrangling") Fixes: f44158485826 ("cifsd: add file operations") Signed-off-by: David Howells dhowells@redhat.com Reported-by: Jeff Layton jlayton@kernel.org Tested-by: Jeff Layton jlayton@kernel.org Reviewed-by: Namjae Jeon linkinjeon@kernel.org Cc: stable@kernel.org Acked-by: Alexander Viro viro@zeniv.linux.org.uk cc: Steve French sfrench@samba.org cc: Hyunchul Lee hyc.lee@gmail.com cc: Chuck Lever chuck.lever@oracle.com cc: Dave Wysochanski dwysocha@redhat.com Signed-off-by: Linus Torvalds torvalds@linux-foundation.org Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com Reviewed-by: Wei Li liwei391@huawei.com --- fs/attr.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/fs/attr.c b/fs/attr.c index b4bbdbd4c8ca..848ffe6e3c24 100644 --- a/fs/attr.c +++ b/fs/attr.c @@ -134,6 +134,8 @@ EXPORT_SYMBOL(setattr_prepare); */ int inode_newsize_ok(const struct inode *inode, loff_t offset) { + if (offset < 0) + return -EINVAL; if (inode->i_size < offset) { unsigned long limit;