summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhillip Lougher <phillip@squashfs.org.uk>2018-08-02 11:45:15 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2018-08-02 12:34:02 -0400
commita3f94cb99a854fa381fe7fadd97c4f61633717a5 (patch)
tree9de67b4b1fa9b93ded20dc65bd4b7fd059ef6813
parent71755ee5350b63fb1f283de8561cdb61b47f4d1d (diff)
Squashfs: Compute expected length from inode size rather than block length
Previously in squashfs_readpage() when copying data into the page cache, it used the length of the datablock read from the filesystem (after decompression). However, if the filesystem has been corrupted this data block may be short, which will leave pages unfilled. The fix for this is to compute the expected number of bytes to copy from the inode size, and use this to detect if the block is short. Signed-off-by: Phillip Lougher <phillip@squashfs.org.uk> Tested-by: Willy Tarreau <w@1wt.eu> Cc: Анатолий Тросиненко <anatoly.trosinenko@gmail.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--fs/squashfs/file.c25
-rw-r--r--fs/squashfs/file_cache.c4
-rw-r--r--fs/squashfs/file_direct.c16
-rw-r--r--fs/squashfs/squashfs.h2
4 files changed, 24 insertions, 23 deletions
diff --git a/fs/squashfs/file.c b/fs/squashfs/file.c
index cce3060650ae..f1c1430ae721 100644
--- a/fs/squashfs/file.c
+++ b/fs/squashfs/file.c
@@ -431,10 +431,9 @@ skip_page:
431} 431}
432 432
433/* Read datablock stored packed inside a fragment (tail-end packed block) */ 433/* Read datablock stored packed inside a fragment (tail-end packed block) */
434static int squashfs_readpage_fragment(struct page *page) 434static int squashfs_readpage_fragment(struct page *page, int expected)
435{ 435{
436 struct inode *inode = page->mapping->host; 436 struct inode *inode = page->mapping->host;
437 struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
438 struct squashfs_cache_entry *buffer = squashfs_get_fragment(inode->i_sb, 437 struct squashfs_cache_entry *buffer = squashfs_get_fragment(inode->i_sb,
439 squashfs_i(inode)->fragment_block, 438 squashfs_i(inode)->fragment_block,
440 squashfs_i(inode)->fragment_size); 439 squashfs_i(inode)->fragment_size);
@@ -445,23 +444,16 @@ static int squashfs_readpage_fragment(struct page *page)
445 squashfs_i(inode)->fragment_block, 444 squashfs_i(inode)->fragment_block,
446 squashfs_i(inode)->fragment_size); 445 squashfs_i(inode)->fragment_size);
447 else 446 else
448 squashfs_copy_cache(page, buffer, i_size_read(inode) & 447 squashfs_copy_cache(page, buffer, expected,
449 (msblk->block_size - 1),
450 squashfs_i(inode)->fragment_offset); 448 squashfs_i(inode)->fragment_offset);
451 449
452 squashfs_cache_put(buffer); 450 squashfs_cache_put(buffer);
453 return res; 451 return res;
454} 452}
455 453
456static int squashfs_readpage_sparse(struct page *page, int index, int file_end) 454static int squashfs_readpage_sparse(struct page *page, int expected)
457{ 455{
458 struct inode *inode = page->mapping->host; 456 squashfs_copy_cache(page, NULL, expected, 0);
459 struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
460 int bytes = index == file_end ?
461 (i_size_read(inode) & (msblk->block_size - 1)) :
462 msblk->block_size;
463
464 squashfs_copy_cache(page, NULL, bytes, 0);
465 return 0; 457 return 0;
466} 458}
467 459
@@ -471,6 +463,9 @@ static int squashfs_readpage(struct file *file, struct page *page)
471 struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; 463 struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
472 int index = page->index >> (msblk->block_log - PAGE_SHIFT); 464 int index = page->index >> (msblk->block_log - PAGE_SHIFT);
473 int file_end = i_size_read(inode) >> msblk->block_log; 465 int file_end = i_size_read(inode) >> msblk->block_log;
466 int expected = index == file_end ?
467 (i_size_read(inode) & (msblk->block_size - 1)) :
468 msblk->block_size;
474 int res; 469 int res;
475 void *pageaddr; 470 void *pageaddr;
476 471
@@ -489,11 +484,11 @@ static int squashfs_readpage(struct file *file, struct page *page)
489 goto error_out; 484 goto error_out;
490 485
491 if (bsize == 0) 486 if (bsize == 0)
492 res = squashfs_readpage_sparse(page, index, file_end); 487 res = squashfs_readpage_sparse(page, expected);
493 else 488 else
494 res = squashfs_readpage_block(page, block, bsize); 489 res = squashfs_readpage_block(page, block, bsize, expected);
495 } else 490 } else
496 res = squashfs_readpage_fragment(page); 491 res = squashfs_readpage_fragment(page, expected);
497 492
498 if (!res) 493 if (!res)
499 return 0; 494 return 0;
diff --git a/fs/squashfs/file_cache.c b/fs/squashfs/file_cache.c
index f2310d2a2019..a9ba8d96776a 100644
--- a/fs/squashfs/file_cache.c
+++ b/fs/squashfs/file_cache.c
@@ -20,7 +20,7 @@
20#include "squashfs.h" 20#include "squashfs.h"
21 21
22/* Read separately compressed datablock and memcopy into page cache */ 22/* Read separately compressed datablock and memcopy into page cache */
23int squashfs_readpage_block(struct page *page, u64 block, int bsize) 23int squashfs_readpage_block(struct page *page, u64 block, int bsize, int expected)
24{ 24{
25 struct inode *i = page->mapping->host; 25 struct inode *i = page->mapping->host;
26 struct squashfs_cache_entry *buffer = squashfs_get_datablock(i->i_sb, 26 struct squashfs_cache_entry *buffer = squashfs_get_datablock(i->i_sb,
@@ -31,7 +31,7 @@ int squashfs_readpage_block(struct page *page, u64 block, int bsize)
31 ERROR("Unable to read page, block %llx, size %x\n", block, 31 ERROR("Unable to read page, block %llx, size %x\n", block,
32 bsize); 32 bsize);
33 else 33 else
34 squashfs_copy_cache(page, buffer, buffer->length, 0); 34 squashfs_copy_cache(page, buffer, expected, 0);
35 35
36 squashfs_cache_put(buffer); 36 squashfs_cache_put(buffer);
37 return res; 37 return res;
diff --git a/fs/squashfs/file_direct.c b/fs/squashfs/file_direct.c
index 096990254a2e..80db1b86a27c 100644
--- a/fs/squashfs/file_direct.c
+++ b/fs/squashfs/file_direct.c
@@ -21,10 +21,11 @@
21#include "page_actor.h" 21#include "page_actor.h"
22 22
23static int squashfs_read_cache(struct page *target_page, u64 block, int bsize, 23static int squashfs_read_cache(struct page *target_page, u64 block, int bsize,
24 int pages, struct page **page); 24 int pages, struct page **page, int bytes);
25 25
26/* Read separately compressed datablock directly into page cache */ 26/* Read separately compressed datablock directly into page cache */
27int squashfs_readpage_block(struct page *target_page, u64 block, int bsize) 27int squashfs_readpage_block(struct page *target_page, u64 block, int bsize,
28 int expected)
28 29
29{ 30{
30 struct inode *inode = target_page->mapping->host; 31 struct inode *inode = target_page->mapping->host;
@@ -83,7 +84,7 @@ int squashfs_readpage_block(struct page *target_page, u64 block, int bsize)
83 * using an intermediate buffer. 84 * using an intermediate buffer.
84 */ 85 */
85 res = squashfs_read_cache(target_page, block, bsize, pages, 86 res = squashfs_read_cache(target_page, block, bsize, pages,
86 page); 87 page, expected);
87 if (res < 0) 88 if (res < 0)
88 goto mark_errored; 89 goto mark_errored;
89 90
@@ -95,6 +96,11 @@ int squashfs_readpage_block(struct page *target_page, u64 block, int bsize)
95 if (res < 0) 96 if (res < 0)
96 goto mark_errored; 97 goto mark_errored;
97 98
99 if (res != expected) {
100 res = -EIO;
101 goto mark_errored;
102 }
103
98 /* Last page may have trailing bytes not filled */ 104 /* Last page may have trailing bytes not filled */
99 bytes = res % PAGE_SIZE; 105 bytes = res % PAGE_SIZE;
100 if (bytes) { 106 if (bytes) {
@@ -138,12 +144,12 @@ out:
138 144
139 145
140static int squashfs_read_cache(struct page *target_page, u64 block, int bsize, 146static int squashfs_read_cache(struct page *target_page, u64 block, int bsize,
141 int pages, struct page **page) 147 int pages, struct page **page, int bytes)
142{ 148{
143 struct inode *i = target_page->mapping->host; 149 struct inode *i = target_page->mapping->host;
144 struct squashfs_cache_entry *buffer = squashfs_get_datablock(i->i_sb, 150 struct squashfs_cache_entry *buffer = squashfs_get_datablock(i->i_sb,
145 block, bsize); 151 block, bsize);
146 int bytes = buffer->length, res = buffer->error, n, offset = 0; 152 int res = buffer->error, n, offset = 0;
147 153
148 if (res) { 154 if (res) {
149 ERROR("Unable to read page, block %llx, size %x\n", block, 155 ERROR("Unable to read page, block %llx, size %x\n", block,
diff --git a/fs/squashfs/squashfs.h b/fs/squashfs/squashfs.h
index d8d43724cf2a..f89f8a74c6ce 100644
--- a/fs/squashfs/squashfs.h
+++ b/fs/squashfs/squashfs.h
@@ -72,7 +72,7 @@ void squashfs_copy_cache(struct page *, struct squashfs_cache_entry *, int,
72 int); 72 int);
73 73
74/* file_xxx.c */ 74/* file_xxx.c */
75extern int squashfs_readpage_block(struct page *, u64, int); 75extern int squashfs_readpage_block(struct page *, u64, int, int);
76 76
77/* id.c */ 77/* id.c */
78extern int squashfs_get_id(struct super_block *, unsigned int, unsigned int *); 78extern int squashfs_get_id(struct super_block *, unsigned int, unsigned int *);