Skip to content

Commit a3f94cb

Browse files
ploughertorvalds
authored andcommitted
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 <[email protected]> Tested-by: Willy Tarreau <[email protected]> Cc: Анатолий Тросиненко <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 71755ee commit a3f94cb

File tree

4 files changed

+24
-23
lines changed

4 files changed

+24
-23
lines changed

fs/squashfs/file.c

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -431,10 +431,9 @@ void squashfs_copy_cache(struct page *page, struct squashfs_cache_entry *buffer,
431431
}
432432

433433
/* Read datablock stored packed inside a fragment (tail-end packed block) */
434-
static int squashfs_readpage_fragment(struct page *page)
434+
static int squashfs_readpage_fragment(struct page *page, int expected)
435435
{
436436
struct inode *inode = page->mapping->host;
437-
struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
438437
struct squashfs_cache_entry *buffer = squashfs_get_fragment(inode->i_sb,
439438
squashfs_i(inode)->fragment_block,
440439
squashfs_i(inode)->fragment_size);
@@ -445,23 +444,16 @@ static int squashfs_readpage_fragment(struct page *page)
445444
squashfs_i(inode)->fragment_block,
446445
squashfs_i(inode)->fragment_size);
447446
else
448-
squashfs_copy_cache(page, buffer, i_size_read(inode) &
449-
(msblk->block_size - 1),
447+
squashfs_copy_cache(page, buffer, expected,
450448
squashfs_i(inode)->fragment_offset);
451449

452450
squashfs_cache_put(buffer);
453451
return res;
454452
}
455453

456-
static int squashfs_readpage_sparse(struct page *page, int index, int file_end)
454+
static int squashfs_readpage_sparse(struct page *page, int expected)
457455
{
458-
struct inode *inode = page->mapping->host;
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);
456+
squashfs_copy_cache(page, NULL, expected, 0);
465457
return 0;
466458
}
467459

@@ -471,6 +463,9 @@ static int squashfs_readpage(struct file *file, struct page *page)
471463
struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
472464
int index = page->index >> (msblk->block_log - PAGE_SHIFT);
473465
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;
474469
int res;
475470
void *pageaddr;
476471

@@ -489,11 +484,11 @@ static int squashfs_readpage(struct file *file, struct page *page)
489484
goto error_out;
490485

491486
if (bsize == 0)
492-
res = squashfs_readpage_sparse(page, index, file_end);
487+
res = squashfs_readpage_sparse(page, expected);
493488
else
494-
res = squashfs_readpage_block(page, block, bsize);
489+
res = squashfs_readpage_block(page, block, bsize, expected);
495490
} else
496-
res = squashfs_readpage_fragment(page);
491+
res = squashfs_readpage_fragment(page, expected);
497492

498493
if (!res)
499494
return 0;

fs/squashfs/file_cache.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
#include "squashfs.h"
2121

2222
/* Read separately compressed datablock and memcopy into page cache */
23-
int squashfs_readpage_block(struct page *page, u64 block, int bsize)
23+
int squashfs_readpage_block(struct page *page, u64 block, int bsize, int expected)
2424
{
2525
struct inode *i = page->mapping->host;
2626
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)
3131
ERROR("Unable to read page, block %llx, size %x\n", block,
3232
bsize);
3333
else
34-
squashfs_copy_cache(page, buffer, buffer->length, 0);
34+
squashfs_copy_cache(page, buffer, expected, 0);
3535

3636
squashfs_cache_put(buffer);
3737
return res;

fs/squashfs/file_direct.c

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,11 @@
2121
#include "page_actor.h"
2222

2323
static 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);
2525

2626
/* Read separately compressed datablock directly into page cache */
27-
int squashfs_readpage_block(struct page *target_page, u64 block, int bsize)
27+
int squashfs_readpage_block(struct page *target_page, u64 block, int bsize,
28+
int expected)
2829

2930
{
3031
struct inode *inode = target_page->mapping->host;
@@ -83,7 +84,7 @@ int squashfs_readpage_block(struct page *target_page, u64 block, int bsize)
8384
* using an intermediate buffer.
8485
*/
8586
res = squashfs_read_cache(target_page, block, bsize, pages,
86-
page);
87+
page, expected);
8788
if (res < 0)
8889
goto mark_errored;
8990

@@ -95,6 +96,11 @@ int squashfs_readpage_block(struct page *target_page, u64 block, int bsize)
9596
if (res < 0)
9697
goto mark_errored;
9798

99+
if (res != expected) {
100+
res = -EIO;
101+
goto mark_errored;
102+
}
103+
98104
/* Last page may have trailing bytes not filled */
99105
bytes = res % PAGE_SIZE;
100106
if (bytes) {
@@ -138,12 +144,12 @@ int squashfs_readpage_block(struct page *target_page, u64 block, int bsize)
138144

139145

140146
static 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)
142148
{
143149
struct inode *i = target_page->mapping->host;
144150
struct squashfs_cache_entry *buffer = squashfs_get_datablock(i->i_sb,
145151
block, bsize);
146-
int bytes = buffer->length, res = buffer->error, n, offset = 0;
152+
int res = buffer->error, n, offset = 0;
147153

148154
if (res) {
149155
ERROR("Unable to read page, block %llx, size %x\n", block,

fs/squashfs/squashfs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ void squashfs_copy_cache(struct page *, struct squashfs_cache_entry *, int,
7272
int);
7373

7474
/* file_xxx.c */
75-
extern int squashfs_readpage_block(struct page *, u64, int);
75+
extern int squashfs_readpage_block(struct page *, u64, int, int);
7676

7777
/* id.c */
7878
extern int squashfs_get_id(struct super_block *, unsigned int, unsigned int *);

0 commit comments

Comments
 (0)