Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4a60e543 authored by Linus Torvalds's avatar Linus Torvalds Committed by Greg Kroah-Hartman
Browse files

squashfs: more metadata hardenings



commit 71755ee5350b63fb1f283de8561cdb61b47f4d1d upstream.

The squashfs fragment reading code doesn't actually verify that the
fragment is inside the fragment table.  The end result _is_ verified to
be inside the image when actually reading the fragment data, but before
that is done, we may end up taking a page fault because the fragment
table itself might not even exist.

Another report from Anatoly and his endless squashfs image fuzzing.

Reported-by: default avatarАнатолий Тросиненко <anatoly.trosinenko@gmail.com>
Acked-by: default avatar: Phillip Lougher <phillip.lougher@gmail.com&gt;,>
Cc: Willy Tarreau <w@1wt.eu>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent a220a703
Loading
Loading
Loading
Loading
+9 −4
Original line number Diff line number Diff line
@@ -49,11 +49,16 @@ int squashfs_frag_lookup(struct super_block *sb, unsigned int fragment,
				u64 *fragment_block)
{
	struct squashfs_sb_info *msblk = sb->s_fs_info;
	int block = SQUASHFS_FRAGMENT_INDEX(fragment);
	int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET(fragment);
	u64 start_block = le64_to_cpu(msblk->fragment_index[block]);
	int block, offset, size;
	struct squashfs_fragment_entry fragment_entry;
	int size;
	u64 start_block;

	if (fragment >= msblk->fragments)
		return -EIO;
	block = SQUASHFS_FRAGMENT_INDEX(fragment);
	offset = SQUASHFS_FRAGMENT_INDEX_OFFSET(fragment);

	start_block = le64_to_cpu(msblk->fragment_index[block]);

	size = squashfs_read_metadata(sb, &fragment_entry, &start_block,
					&offset, sizeof(fragment_entry));
+1 −0
Original line number Diff line number Diff line
@@ -75,6 +75,7 @@ struct squashfs_sb_info {
	unsigned short				block_log;
	long long				bytes_used;
	unsigned int				inodes;
	unsigned int				fragments;
	int					xattr_ids;
};
#endif
+3 −2
Original line number Diff line number Diff line
@@ -176,6 +176,7 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
	msblk->inode_table = le64_to_cpu(sblk->inode_table_start);
	msblk->directory_table = le64_to_cpu(sblk->directory_table_start);
	msblk->inodes = le32_to_cpu(sblk->inodes);
	msblk->fragments = le32_to_cpu(sblk->fragments);
	flags = le16_to_cpu(sblk->flags);

	TRACE("Found valid superblock on %s\n", bdevname(sb->s_bdev, b));
@@ -186,7 +187,7 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
	TRACE("Filesystem size %lld bytes\n", msblk->bytes_used);
	TRACE("Block size %d\n", msblk->block_size);
	TRACE("Number of inodes %d\n", msblk->inodes);
	TRACE("Number of fragments %d\n", le32_to_cpu(sblk->fragments));
	TRACE("Number of fragments %d\n", msblk->fragments);
	TRACE("Number of ids %d\n", le16_to_cpu(sblk->no_ids));
	TRACE("sblk->inode_table_start %llx\n", msblk->inode_table);
	TRACE("sblk->directory_table_start %llx\n", msblk->directory_table);
@@ -273,7 +274,7 @@ allocate_id_index_table:
	sb->s_export_op = &squashfs_export_ops;

handle_fragments:
	fragments = le32_to_cpu(sblk->fragments);
	fragments = msblk->fragments;
	if (fragments == 0)
		goto check_directory_table;