Commit 9ee94bfb authored by Phillip Lougher's avatar Phillip Lougher Committed by Andrew Morton
Browse files

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: default avatarPhillip Lougher <phillip@squashfs.org.uk>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
parent 1260cbcf
Loading
Loading
Loading
Loading
+18 −2
Original line number Diff line number Diff line
@@ -144,8 +144,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) {
@@ -159,7 +168,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;
@@ -188,8 +196,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) {
@@ -204,7 +221,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;