Skip to content

Commit

Permalink
squashfs: more metadata hardening
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
torvalds committed Aug 2, 2018
1 parent 6b47037 commit 71755ee
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 @@ -175,6 +175,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 %pg\n", sb->s_bdev);
Expand All @@ -185,7 +186,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 @@ -272,7 +273,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 71755ee

Please sign in to comment.