Skip to content

Commit 69ef27a

Browse files
torvaldsZhengShunQian
authored andcommitted
squashfs: be more careful about metadata corruption
commit 01cfb79 upstream. Anatoly Trosinenko reports that a corrupted squashfs image can cause a kernel oops. It turns out that squashfs can end up being confused about negative fragment lengths. The regular squashfs_read_data() does check for negative lengths, but squashfs_read_metadata() did not, and the fragment size code just blindly trusted the on-disk value. Fix both the fragment parsing and the metadata reading code. Reported-by: Anatoly Trosinenko <[email protected]> Cc: Al Viro <[email protected]> Cc: Phillip Lougher <[email protected]> Cc: [email protected] Signed-off-by: Linus Torvalds <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 6cc9544 commit 69ef27a

File tree

4 files changed

+16
-5
lines changed

4 files changed

+16
-5
lines changed

fs/squashfs/cache.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,9 @@ int squashfs_read_metadata(struct super_block *sb, void *buffer,
340340

341341
TRACE("Entered squashfs_read_metadata [%llx:%x]\n", *block, *offset);
342342

343+
if (unlikely(length < 0))
344+
return -EIO;
345+
343346
while (length) {
344347
entry = squashfs_cache_get(sb, msblk->block_cache, *block, 0);
345348
if (entry->error) {

fs/squashfs/file.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,11 @@ static long long read_indexes(struct super_block *sb, int n,
198198
}
199199

200200
for (i = 0; i < blocks; i++) {
201-
int size = le32_to_cpu(blist[i]);
201+
int size = squashfs_block_size(blist[i]);
202+
if (size < 0) {
203+
err = size;
204+
goto failure;
205+
}
202206
block += SQUASHFS_COMPRESSED_SIZE_BLOCK(size);
203207
}
204208
n -= blocks;
@@ -371,7 +375,7 @@ static int read_blocklist(struct inode *inode, int index, u64 *block)
371375
sizeof(size));
372376
if (res < 0)
373377
return res;
374-
return le32_to_cpu(size);
378+
return squashfs_block_size(size);
375379
}
376380

377381
/* Copy data into page cache */

fs/squashfs/fragment.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,7 @@ int squashfs_frag_lookup(struct super_block *sb, unsigned int fragment,
6161
return size;
6262

6363
*fragment_block = le64_to_cpu(fragment_entry.start_block);
64-
size = le32_to_cpu(fragment_entry.size);
65-
66-
return size;
64+
return squashfs_block_size(fragment_entry.size);
6765
}
6866

6967

fs/squashfs/squashfs_fs.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,12 @@
129129

130130
#define SQUASHFS_COMPRESSED_BLOCK(B) (!((B) & SQUASHFS_COMPRESSED_BIT_BLOCK))
131131

132+
static inline int squashfs_block_size(__le32 raw)
133+
{
134+
u32 size = le32_to_cpu(raw);
135+
return (size >> 25) ? -EIO : size;
136+
}
137+
132138
/*
133139
* Inode number ops. Inodes consist of a compressed block number, and an
134140
* uncompressed offset within that block

0 commit comments

Comments
 (0)