When a zisofs block is smaller than a page, the empty-block path in zisofs_uncompress_block() zeroes the rest of the page and returns that length. zisofs_fill_pages() then advances past the page without reading the remaining blocks, returning zeros instead of their contents. For example, with 64 KiB pages and 32 KiB zisofs blocks, an empty first block should zero only the first half of the page. Instead, it zeroes the entire page and returns 64 KiB, so the second block is never read. Commit 68d4d3e78150 ("isofs: fix out-of-bounds page array access on empty zisofs block") accounted for poffset but left this older problem in place. It was pointed out by Sashiko while reviewing a 5.10 backport. Limit the zeroed range and returned length to one uncompressed block and the available output space. Only mark a folio uptodate when the range reaches its end. zisofs_fill_pages() already zeroes the tail and marks the partially filled folio uptodate at EOF. Fixes: 59bc055211b8 ("zisofs: Implement reading of compressed files when PAGE_CACHE_SIZE > compress block size") Cc: stable@vger.kernel.org Link: https://sashiko.dev/#/patchset/20261105083209.922-1-mdmitrichenko%40astralinux.ru Signed-off-by: Mikhail Dmitrichenko --- fs/isofs/compress.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/fs/isofs/compress.c b/fs/isofs/compress.c index 2d23abaeb874..c471007a76ed 100644 --- a/fs/isofs/compress.c +++ b/fs/isofs/compress.c @@ -64,16 +64,24 @@ static loff_t zisofs_uncompress_block(struct inode *inode, loff_t block_start, } /* Empty block? */ if (block_size == 0) { - for ( i = 0 ; i < pcount ; i++ ) { + unsigned int bytes = min_t(loff_t, 1U << zisofs_block_shift, + (((loff_t)pcount) << PAGE_SHIFT) - poffset); + unsigned int remaining = bytes; + + for (i = 0; i < pcount; i++) { unsigned int off = i ? 0 : poffset; + unsigned int len = min_t(unsigned int, remaining, + PAGE_SIZE - off); struct folio *folio = folios[i]; + remaining -= len; if (!folio) continue; - folio_zero_range(folio, off, folio_size(folio) - off); - folio_mark_uptodate(folio); + folio_zero_range(folio, off, len); + if (off + len == folio_size(folio)) + folio_mark_uptodate(folio); } - return (((loff_t)pcount) << PAGE_SHIFT) - poffset; + return bytes; } /* Because zlib is not thread-safe, do all the I/O at the top. */ -- 2.43.0