aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Sandeen <sandeen@redhat.com>2018-12-21 11:42:50 -0500
committerDarrick J. Wong <darrick.wong@oracle.com>2018-12-21 11:42:50 -0500
commit3cc31fa65d85610574c0f6a474e89f4c419923d5 (patch)
tree879ff2132f5bb4fff6bcf39af0a77881e6ac1e4e
parent7566ec393f4161572ba6f11ad5171fd5d59b0fbd (diff)
iomap: don't search past page end in iomap_is_partially_uptodate
iomap_is_partially_uptodate() is intended to check wither blocks within the selected range of a not-uptodate page are uptodate; if the range we care about is up to date, it's an optimization. However, the iomap implementation continues to check all blocks up to from+count, which is beyond the page, and can even be well beyond the iop->uptodate bitmap. I think the worst that will happen is that we may eventually find a zero bit and return "not partially uptodate" when it would have otherwise returned true, and skip the optimization. Still, it's clearly an invalid memory access that must be fixed. So: fix this by limiting the search to within the page as is done in the non-iomap variant, block_is_partially_uptodate(). Zorro noticed thiswhen KASAN went off for 512 byte blocks on a 64k page system: BUG: KASAN: slab-out-of-bounds in iomap_is_partially_uptodate+0x1a0/0x1e0 Read of size 8 at addr ffff800120c3a318 by task fsstress/22337 Reported-by: Zorro Lang <zlang@redhat.com> Signed-off-by: Eric Sandeen <sandeen@redhat.com> Signed-off-by: Eric Sandeen <sandeen@sandeen.net> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
-rw-r--r--fs/iomap.c17
1 files changed, 15 insertions, 2 deletions
diff --git a/fs/iomap.c b/fs/iomap.c
index 5bc172f3dfe8..fba8fdb734e0 100644
--- a/fs/iomap.c
+++ b/fs/iomap.c
@@ -499,16 +499,29 @@ done:
499} 499}
500EXPORT_SYMBOL_GPL(iomap_readpages); 500EXPORT_SYMBOL_GPL(iomap_readpages);
501 501
502/*
503 * iomap_is_partially_uptodate checks whether blocks within a page are
504 * uptodate or not.
505 *
506 * Returns true if all blocks which correspond to a file portion
507 * we want to read within the page are uptodate.
508 */
502int 509int
503iomap_is_partially_uptodate(struct page *page, unsigned long from, 510iomap_is_partially_uptodate(struct page *page, unsigned long from,
504 unsigned long count) 511 unsigned long count)
505{ 512{
506 struct iomap_page *iop = to_iomap_page(page); 513 struct iomap_page *iop = to_iomap_page(page);
507 struct inode *inode = page->mapping->host; 514 struct inode *inode = page->mapping->host;
508 unsigned first = from >> inode->i_blkbits; 515 unsigned len, first, last;
509 unsigned last = (from + count - 1) >> inode->i_blkbits;
510 unsigned i; 516 unsigned i;
511 517
518 /* Limit range to one page */
519 len = min_t(unsigned, PAGE_SIZE - from, count);
520
521 /* First and last blocks in range within page */
522 first = from >> inode->i_blkbits;
523 last = (from + len - 1) >> inode->i_blkbits;
524
512 if (iop) { 525 if (iop) {
513 for (i = first; i <= last; i++) 526 for (i = first; i <= last; i++)
514 if (!test_bit(i, iop->uptodate)) 527 if (!test_bit(i, iop->uptodate))