diff options
author | Phillip Lougher <phillip@lougher.demon.co.uk> | 2009-03-04 19:31:12 -0500 |
---|---|---|
committer | Phillip Lougher <phillip@lougher.demon.co.uk> | 2009-03-04 19:31:12 -0500 |
commit | 118e1ef6fabfc023126e6075f6ac0fc729cb5285 (patch) | |
tree | 3c497ad9fcc5a459de9d75a688bb78c5220e8dd5 | |
parent | 2450cf51a1bdba7037e91b1bcc494b01c58aaf66 (diff) |
Squashfs: Fix oops when reading fsfuzzer corrupted filesystems
This fixes a code regression caused by the recent mainlining changes.
The recent code changes call zlib_inflate repeatedly, decompressing into
separate 4K buffers, this code didn't check for the possibility that
zlib_inflate might ask for too many buffers when decompressing corrupted
data.
Signed-off-by: Phillip Lougher <phillip@lougher.demon.co.uk>
-rw-r--r-- | fs/squashfs/block.c | 13 | ||||
-rw-r--r-- | fs/squashfs/cache.c | 4 | ||||
-rw-r--r-- | fs/squashfs/squashfs.h | 2 | ||||
-rw-r--r-- | fs/squashfs/super.c | 2 |
4 files changed, 15 insertions, 6 deletions
diff --git a/fs/squashfs/block.c b/fs/squashfs/block.c index c837dfc2b3c6..321728f48f2d 100644 --- a/fs/squashfs/block.c +++ b/fs/squashfs/block.c | |||
@@ -80,7 +80,7 @@ static struct buffer_head *get_block_length(struct super_block *sb, | |||
80 | * generated a larger block - this does occasionally happen with zlib). | 80 | * generated a larger block - this does occasionally happen with zlib). |
81 | */ | 81 | */ |
82 | int squashfs_read_data(struct super_block *sb, void **buffer, u64 index, | 82 | int squashfs_read_data(struct super_block *sb, void **buffer, u64 index, |
83 | int length, u64 *next_index, int srclength) | 83 | int length, u64 *next_index, int srclength, int pages) |
84 | { | 84 | { |
85 | struct squashfs_sb_info *msblk = sb->s_fs_info; | 85 | struct squashfs_sb_info *msblk = sb->s_fs_info; |
86 | struct buffer_head **bh; | 86 | struct buffer_head **bh; |
@@ -185,6 +185,14 @@ int squashfs_read_data(struct super_block *sb, void **buffer, u64 index, | |||
185 | } | 185 | } |
186 | 186 | ||
187 | if (msblk->stream.avail_out == 0) { | 187 | if (msblk->stream.avail_out == 0) { |
188 | if (page == pages) { | ||
189 | ERROR("zlib_inflate tried to " | ||
190 | "decompress too much data, " | ||
191 | "expected %d bytes. Zlib " | ||
192 | "data probably corrupt\n", | ||
193 | srclength); | ||
194 | goto release_mutex; | ||
195 | } | ||
188 | msblk->stream.next_out = buffer[page++]; | 196 | msblk->stream.next_out = buffer[page++]; |
189 | msblk->stream.avail_out = PAGE_CACHE_SIZE; | 197 | msblk->stream.avail_out = PAGE_CACHE_SIZE; |
190 | } | 198 | } |
@@ -268,7 +276,8 @@ block_release: | |||
268 | put_bh(bh[k]); | 276 | put_bh(bh[k]); |
269 | 277 | ||
270 | read_failure: | 278 | read_failure: |
271 | ERROR("sb_bread failed reading block 0x%llx\n", cur_index); | 279 | ERROR("squashfs_read_data failed to read block 0x%llx\n", |
280 | (unsigned long long) index); | ||
272 | kfree(bh); | 281 | kfree(bh); |
273 | return -EIO; | 282 | return -EIO; |
274 | } | 283 | } |
diff --git a/fs/squashfs/cache.c b/fs/squashfs/cache.c index f29eda16d25e..1c4739e33af6 100644 --- a/fs/squashfs/cache.c +++ b/fs/squashfs/cache.c | |||
@@ -119,7 +119,7 @@ struct squashfs_cache_entry *squashfs_cache_get(struct super_block *sb, | |||
119 | 119 | ||
120 | entry->length = squashfs_read_data(sb, entry->data, | 120 | entry->length = squashfs_read_data(sb, entry->data, |
121 | block, length, &entry->next_index, | 121 | block, length, &entry->next_index, |
122 | cache->block_size); | 122 | cache->block_size, cache->pages); |
123 | 123 | ||
124 | spin_lock(&cache->lock); | 124 | spin_lock(&cache->lock); |
125 | 125 | ||
@@ -406,7 +406,7 @@ int squashfs_read_table(struct super_block *sb, void *buffer, u64 block, | |||
406 | for (i = 0; i < pages; i++, buffer += PAGE_CACHE_SIZE) | 406 | for (i = 0; i < pages; i++, buffer += PAGE_CACHE_SIZE) |
407 | data[i] = buffer; | 407 | data[i] = buffer; |
408 | res = squashfs_read_data(sb, data, block, length | | 408 | res = squashfs_read_data(sb, data, block, length | |
409 | SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, length); | 409 | SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, length, pages); |
410 | kfree(data); | 410 | kfree(data); |
411 | return res; | 411 | return res; |
412 | } | 412 | } |
diff --git a/fs/squashfs/squashfs.h b/fs/squashfs/squashfs.h index 6b2515d027d5..0e9feb6adf7e 100644 --- a/fs/squashfs/squashfs.h +++ b/fs/squashfs/squashfs.h | |||
@@ -34,7 +34,7 @@ static inline struct squashfs_inode_info *squashfs_i(struct inode *inode) | |||
34 | 34 | ||
35 | /* block.c */ | 35 | /* block.c */ |
36 | extern int squashfs_read_data(struct super_block *, void **, u64, int, u64 *, | 36 | extern int squashfs_read_data(struct super_block *, void **, u64, int, u64 *, |
37 | int); | 37 | int, int); |
38 | 38 | ||
39 | /* cache.c */ | 39 | /* cache.c */ |
40 | extern struct squashfs_cache *squashfs_cache_init(char *, int, int); | 40 | extern struct squashfs_cache *squashfs_cache_init(char *, int, int); |
diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c index 071df5b5b491..681ec0d83799 100644 --- a/fs/squashfs/super.c +++ b/fs/squashfs/super.c | |||
@@ -389,7 +389,7 @@ static int __init init_squashfs_fs(void) | |||
389 | return err; | 389 | return err; |
390 | } | 390 | } |
391 | 391 | ||
392 | printk(KERN_INFO "squashfs: version 4.0 (2009/01/03) " | 392 | printk(KERN_INFO "squashfs: version 4.0 (2009/01/31) " |
393 | "Phillip Lougher\n"); | 393 | "Phillip Lougher\n"); |
394 | 394 | ||
395 | return 0; | 395 | return 0; |