Skip to content

Commit 71755ee

Browse files
committed
squashfs: more metadata hardening
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: Анатолий Тросиненко <[email protected]> Acked-by:: Phillip Lougher <[email protected]>, Cc: Willy Tarreau <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 6b47037 commit 71755ee

File tree

3 files changed

+13
-6
lines changed

3 files changed

+13
-6
lines changed

fs/squashfs/fragment.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,16 @@ int squashfs_frag_lookup(struct super_block *sb, unsigned int fragment,
4949
u64 *fragment_block)
5050
{
5151
struct squashfs_sb_info *msblk = sb->s_fs_info;
52-
int block = SQUASHFS_FRAGMENT_INDEX(fragment);
53-
int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET(fragment);
54-
u64 start_block = le64_to_cpu(msblk->fragment_index[block]);
52+
int block, offset, size;
5553
struct squashfs_fragment_entry fragment_entry;
56-
int size;
54+
u64 start_block;
55+
56+
if (fragment >= msblk->fragments)
57+
return -EIO;
58+
block = SQUASHFS_FRAGMENT_INDEX(fragment);
59+
offset = SQUASHFS_FRAGMENT_INDEX_OFFSET(fragment);
60+
61+
start_block = le64_to_cpu(msblk->fragment_index[block]);
5762

5863
size = squashfs_read_metadata(sb, &fragment_entry, &start_block,
5964
&offset, sizeof(fragment_entry));

fs/squashfs/squashfs_fs_sb.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ struct squashfs_sb_info {
7575
unsigned short block_log;
7676
long long bytes_used;
7777
unsigned int inodes;
78+
unsigned int fragments;
7879
int xattr_ids;
7980
};
8081
#endif

fs/squashfs/super.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
175175
msblk->inode_table = le64_to_cpu(sblk->inode_table_start);
176176
msblk->directory_table = le64_to_cpu(sblk->directory_table_start);
177177
msblk->inodes = le32_to_cpu(sblk->inodes);
178+
msblk->fragments = le32_to_cpu(sblk->fragments);
178179
flags = le16_to_cpu(sblk->flags);
179180

180181
TRACE("Found valid superblock on %pg\n", sb->s_bdev);
@@ -185,7 +186,7 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
185186
TRACE("Filesystem size %lld bytes\n", msblk->bytes_used);
186187
TRACE("Block size %d\n", msblk->block_size);
187188
TRACE("Number of inodes %d\n", msblk->inodes);
188-
TRACE("Number of fragments %d\n", le32_to_cpu(sblk->fragments));
189+
TRACE("Number of fragments %d\n", msblk->fragments);
189190
TRACE("Number of ids %d\n", le16_to_cpu(sblk->no_ids));
190191
TRACE("sblk->inode_table_start %llx\n", msblk->inode_table);
191192
TRACE("sblk->directory_table_start %llx\n", msblk->directory_table);
@@ -272,7 +273,7 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
272273
sb->s_export_op = &squashfs_export_ops;
273274

274275
handle_fragments:
275-
fragments = le32_to_cpu(sblk->fragments);
276+
fragments = msblk->fragments;
276277
if (fragments == 0)
277278
goto check_directory_table;
278279

0 commit comments

Comments
 (0)