Skip to content

Commit

Permalink
squashfs: more metadata hardenings
Browse files Browse the repository at this point in the history
commit 71755ee 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: Анатолий Тросиненко <anatoly.trosinenko@gmail.com>
Acked-by:: Phillip Lougher <phillip.lougher@gmail.com>,
Cc: Willy Tarreau <w@1wt.eu>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
torvalds authored and gregkh committed Aug 9, 2018
1 parent a220a70 commit 4a60e54
Show file tree
Hide file tree
Showing 3 changed files with 13 additions and 6 deletions.
13 changes: 9 additions & 4 deletions fs/squashfs/fragment.c
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down
1 change: 1 addition & 0 deletions fs/squashfs/squashfs_fs_sb.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
5 changes: 3 additions & 2 deletions fs/squashfs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand All @@ -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);
Expand Down Expand Up @@ -273,7 +274,7 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
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;

Expand Down

0 comments on commit 4a60e54

Please sign in to comment.