syzbot report KMSAN: uninit-value in pick_link, the root cause is that squashfs_symlink_read_folio did not check the length, resulting in folio not being initialized and did not return the corresponding error code. The length is calculated from i_size, this case is about symlink, so i_size value is derived from symlink_size, so it is necessary to add a check to confirm that symlink_size value is valid, otherwise an error -EINVAL will be returned. If symlink_size is too large, it may result in a negative value when calculating length in squashfs_symlink_read_folio due to int overflow, and its value must be greater than PAGE_SIZE at this time. Reported-and-tested-by: syzbot+24ac24ff58dc5b0d26b9@xxxxxxxxxxxxxxxxxxxxxxxxx Closes: https://syzkaller.appspot.com/bug?extid=24ac24ff58dc5b0d26b9 Signed-off-by: Lizhi Xu <lizhi.xu@xxxxxxxxxxxxx> --- fs/squashfs/inode.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/fs/squashfs/inode.c b/fs/squashfs/inode.c index 16bd693d0b3a..bed6764e4461 100644 --- a/fs/squashfs/inode.c +++ b/fs/squashfs/inode.c @@ -273,14 +273,21 @@ int squashfs_read_inode(struct inode *inode, long long ino) case SQUASHFS_SYMLINK_TYPE: case SQUASHFS_LSYMLINK_TYPE: { struct squashfs_symlink_inode *sqsh_ino = &squashfs_ino.symlink; + loff_t symlink_size; err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset, sizeof(*sqsh_ino)); if (err < 0) goto failed_read; + symlink_size = le32_to_cpu(sqsh_ino->symlink_size); + if (symlink_size > PAGE_SIZE) { + ERROR("Corrupted symlink, size [%llu]\n", symlink_size); + return -EINVAL; + } + set_nlink(inode, le32_to_cpu(sqsh_ino->nlink)); - inode->i_size = le32_to_cpu(sqsh_ino->symlink_size); + inode->i_size = symlink_size; inode->i_op = &squashfs_symlink_inode_ops; inode_nohighmem(inode); inode->i_data.a_ops = &squashfs_symlink_aops; -- 2.43.0