]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
Squashfs: add additional inode sanity checking
authorPhillip Lougher <phillip@squashfs.org.uk>
Mon, 13 Oct 2025 20:41:26 +0000 (16:41 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 19 Oct 2025 14:23:20 +0000 (16:23 +0200)
[ Upstream commit 9ee94bfbe930a1b39df53fa2d7b31141b780eb5a ]

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>
Stable-dep-of: 9f1c14c1de1b ("Squashfs: reject negative file sizes in squashfs_read_inode()")
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/squashfs/inode.c

index c381d08c30c207e9a5b6a07dbf83dae7a1a9fffe..b0a5ce62dae486cf40c2529956e5d991838fd2bb 100644 (file)
@@ -140,8 +140,17 @@ int squashfs_read_inode(struct inode *inode, long long ino)
                if (err < 0)
                        goto failed_read;
 
+               inode->i_size = le32_to_cpu(sqsh_ino->file_size);
                frag = le32_to_cpu(sqsh_ino->fragment);
                if (frag != SQUASHFS_INVALID_FRAG) {
+                       /*
+                        * the file cannot have a fragment (tailend) and have a
+                        * file size a multiple of the block size
+                        */
+                       if ((inode->i_size & (msblk->block_size - 1)) == 0) {
+                               err = -EINVAL;
+                               goto failed_read;
+                       }
                        frag_offset = le32_to_cpu(sqsh_ino->offset);
                        frag_size = squashfs_frag_lookup(sb, frag, &frag_blk);
                        if (frag_size < 0) {
@@ -155,7 +164,6 @@ int squashfs_read_inode(struct inode *inode, long long ino)
                }
 
                set_nlink(inode, 1);
-               inode->i_size = le32_to_cpu(sqsh_ino->file_size);
                inode->i_fop = &generic_ro_fops;
                inode->i_mode |= S_IFREG;
                inode->i_blocks = ((inode->i_size - 1) >> 9) + 1;
@@ -184,8 +192,17 @@ int squashfs_read_inode(struct inode *inode, long long ino)
                if (err < 0)
                        goto failed_read;
 
+               inode->i_size = le64_to_cpu(sqsh_ino->file_size);
                frag = le32_to_cpu(sqsh_ino->fragment);
                if (frag != SQUASHFS_INVALID_FRAG) {
+                       /*
+                        * the file cannot have a fragment (tailend) and have a
+                        * file size a multiple of the block size
+                        */
+                       if ((inode->i_size & (msblk->block_size - 1)) == 0) {
+                               err = -EINVAL;
+                               goto failed_read;
+                       }
                        frag_offset = le32_to_cpu(sqsh_ino->offset);
                        frag_size = squashfs_frag_lookup(sb, frag, &frag_blk);
                        if (frag_size < 0) {
@@ -200,7 +217,6 @@ int squashfs_read_inode(struct inode *inode, long long ino)
 
                xattr_id = le32_to_cpu(sqsh_ino->xattr);
                set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));
-               inode->i_size = le64_to_cpu(sqsh_ino->file_size);
                inode->i_op = &squashfs_inode_ops;
                inode->i_fop = &generic_ro_fops;
                inode->i_mode |= S_IFREG;