diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-08-02 11:43:35 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-08-02 12:32:23 -0400 |
commit | 71755ee5350b63fb1f283de8561cdb61b47f4d1d (patch) | |
tree | cfca6c7e5f8f30014724b955c845a1a2e80d95e5 | |
parent | 6b4703768268d09ac928c64474fd686adf4574f9 (diff) |
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: Анатолий Тросиненко <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>
-rw-r--r-- | fs/squashfs/fragment.c | 13 | ||||
-rw-r--r-- | fs/squashfs/squashfs_fs_sb.h | 1 | ||||
-rw-r--r-- | fs/squashfs/super.c | 5 |
3 files changed, 13 insertions, 6 deletions
diff --git a/fs/squashfs/fragment.c b/fs/squashfs/fragment.c index 86ad9a4b8c36..0681feab4a84 100644 --- a/fs/squashfs/fragment.c +++ b/fs/squashfs/fragment.c | |||
@@ -49,11 +49,16 @@ int squashfs_frag_lookup(struct super_block *sb, unsigned int fragment, | |||
49 | u64 *fragment_block) | 49 | u64 *fragment_block) |
50 | { | 50 | { |
51 | struct squashfs_sb_info *msblk = sb->s_fs_info; | 51 | struct squashfs_sb_info *msblk = sb->s_fs_info; |
52 | int block = SQUASHFS_FRAGMENT_INDEX(fragment); | 52 | int block, offset, size; |
53 | int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET(fragment); | ||
54 | u64 start_block = le64_to_cpu(msblk->fragment_index[block]); | ||
55 | struct squashfs_fragment_entry fragment_entry; | 53 | 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]); | ||
57 | 62 | ||
58 | size = squashfs_read_metadata(sb, &fragment_entry, &start_block, | 63 | size = squashfs_read_metadata(sb, &fragment_entry, &start_block, |
59 | &offset, sizeof(fragment_entry)); | 64 | &offset, sizeof(fragment_entry)); |
diff --git a/fs/squashfs/squashfs_fs_sb.h b/fs/squashfs/squashfs_fs_sb.h index 1da565cb50c3..ef69c31947bf 100644 --- a/fs/squashfs/squashfs_fs_sb.h +++ b/fs/squashfs/squashfs_fs_sb.h | |||
@@ -75,6 +75,7 @@ struct squashfs_sb_info { | |||
75 | unsigned short block_log; | 75 | unsigned short block_log; |
76 | long long bytes_used; | 76 | long long bytes_used; |
77 | unsigned int inodes; | 77 | unsigned int inodes; |
78 | unsigned int fragments; | ||
78 | int xattr_ids; | 79 | int xattr_ids; |
79 | }; | 80 | }; |
80 | #endif | 81 | #endif |
diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c index 8a73b97217c8..40e657386fa5 100644 --- a/fs/squashfs/super.c +++ b/fs/squashfs/super.c | |||
@@ -175,6 +175,7 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent) | |||
175 | msblk->inode_table = le64_to_cpu(sblk->inode_table_start); | 175 | msblk->inode_table = le64_to_cpu(sblk->inode_table_start); |
176 | msblk->directory_table = le64_to_cpu(sblk->directory_table_start); | 176 | msblk->directory_table = le64_to_cpu(sblk->directory_table_start); |
177 | msblk->inodes = le32_to_cpu(sblk->inodes); | 177 | msblk->inodes = le32_to_cpu(sblk->inodes); |
178 | msblk->fragments = le32_to_cpu(sblk->fragments); | ||
178 | flags = le16_to_cpu(sblk->flags); | 179 | flags = le16_to_cpu(sblk->flags); |
179 | 180 | ||
180 | TRACE("Found valid superblock on %pg\n", sb->s_bdev); | 181 | 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) | |||
185 | TRACE("Filesystem size %lld bytes\n", msblk->bytes_used); | 186 | TRACE("Filesystem size %lld bytes\n", msblk->bytes_used); |
186 | TRACE("Block size %d\n", msblk->block_size); | 187 | TRACE("Block size %d\n", msblk->block_size); |
187 | TRACE("Number of inodes %d\n", msblk->inodes); | 188 | 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); |
189 | TRACE("Number of ids %d\n", le16_to_cpu(sblk->no_ids)); | 190 | TRACE("Number of ids %d\n", le16_to_cpu(sblk->no_ids)); |
190 | TRACE("sblk->inode_table_start %llx\n", msblk->inode_table); | 191 | TRACE("sblk->inode_table_start %llx\n", msblk->inode_table); |
191 | TRACE("sblk->directory_table_start %llx\n", msblk->directory_table); | 192 | TRACE("sblk->directory_table_start %llx\n", msblk->directory_table); |
@@ -272,7 +273,7 @@ allocate_id_index_table: | |||
272 | sb->s_export_op = &squashfs_export_ops; | 273 | sb->s_export_op = &squashfs_export_ops; |
273 | 274 | ||
274 | handle_fragments: | 275 | handle_fragments: |
275 | fragments = le32_to_cpu(sblk->fragments); | 276 | fragments = msblk->fragments; |
276 | if (fragments == 0) | 277 | if (fragments == 0) |
277 | goto check_directory_table; | 278 | goto check_directory_table; |
278 | 279 | ||