Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Squashfs: add additional inode sanity checking

Patch series "Squashfs: performance improvement and a sanity check".

This patchset adds an additional sanity check when reading regular file
inodes, and adds support for SEEK_DATA/SEEK_HOLE lseek() whence values.


This patch (of 2):

Add an additional sanity check when reading regular file inodes.

A regular file if the file size is an exact multiple of the filesystem
block size cannot have a fragment. This is because by definition a
fragment block stores tailends which are not a whole block in size.

Link: https://lkml.kernel.org/r/20250923220652.568416-1-phillip@squashfs.org.uk
Link: https://lkml.kernel.org/r/20250923220652.568416-2-phillip@squashfs.org.uk
Signed-off-by: Phillip Lougher <phillip@squashfs.org.uk>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Phillip Lougher and committed by
Andrew Morton
9ee94bfb 1260cbcf

+18 -2
+18 -2
fs/squashfs/inode.c
··· 144 144 if (err < 0) 145 145 goto failed_read; 146 146 147 + inode->i_size = le32_to_cpu(sqsh_ino->file_size); 147 148 frag = le32_to_cpu(sqsh_ino->fragment); 148 149 if (frag != SQUASHFS_INVALID_FRAG) { 150 + /* 151 + * the file cannot have a fragment (tailend) and have a 152 + * file size a multiple of the block size 153 + */ 154 + if ((inode->i_size & (msblk->block_size - 1)) == 0) { 155 + err = -EINVAL; 156 + goto failed_read; 157 + } 149 158 frag_offset = le32_to_cpu(sqsh_ino->offset); 150 159 frag_size = squashfs_frag_lookup(sb, frag, &frag_blk); 151 160 if (frag_size < 0) { ··· 168 159 } 169 160 170 161 set_nlink(inode, 1); 171 - inode->i_size = le32_to_cpu(sqsh_ino->file_size); 172 162 inode->i_fop = &generic_ro_fops; 173 163 inode->i_mode |= S_IFREG; 174 164 inode->i_blocks = ((inode->i_size - 1) >> 9) + 1; ··· 196 188 if (err < 0) 197 189 goto failed_read; 198 190 191 + inode->i_size = le64_to_cpu(sqsh_ino->file_size); 199 192 frag = le32_to_cpu(sqsh_ino->fragment); 200 193 if (frag != SQUASHFS_INVALID_FRAG) { 194 + /* 195 + * the file cannot have a fragment (tailend) and have a 196 + * file size a multiple of the block size 197 + */ 198 + if ((inode->i_size & (msblk->block_size - 1)) == 0) { 199 + err = -EINVAL; 200 + goto failed_read; 201 + } 201 202 frag_offset = le32_to_cpu(sqsh_ino->offset); 202 203 frag_size = squashfs_frag_lookup(sb, frag, &frag_blk); 203 204 if (frag_size < 0) { ··· 221 204 222 205 xattr_id = le32_to_cpu(sqsh_ino->xattr); 223 206 set_nlink(inode, le32_to_cpu(sqsh_ino->nlink)); 224 - inode->i_size = le64_to_cpu(sqsh_ino->file_size); 225 207 inode->i_op = &squashfs_inode_ops; 226 208 inode->i_fop = &generic_ro_fops; 227 209 inode->i_mode |= S_IFREG;