Skip to content

Commit 40c00e5

Browse files
jankaragregkh
authored andcommitted
ext4: fix data corruption for mmap writes
commit a056bdaae7a181f7dcc876cfab2f94538e508709 upstream. mpage_submit_page() can race with another process growing i_size and writing data via mmap to the written-back page. As mpage_submit_page() samples i_size too early, it may happen that ext4_bio_write_page() zeroes out too large tail of the page and thus corrupts user data. Fix the problem by sampling i_size only after the page has been write-protected in page tables by clear_page_dirty_for_io() call. Reported-by: Michael Zimmer <michael@swarm64.com> CC: stable@vger.kernel.org Fixes: cb20d51 Signed-off-by: Jan Kara <jack@suse.cz> Signed-off-by: Theodore Ts'o <tytso@mit.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 90fd673 commit 40c00e5

1 file changed

Lines changed: 19 additions & 5 deletions

File tree

fs/ext4/inode.c

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1946,15 +1946,29 @@ static int ext4_writepage(struct page *page,
19461946
static int mpage_submit_page(struct mpage_da_data *mpd, struct page *page)
19471947
{
19481948
int len;
1949-
loff_t size = i_size_read(mpd->inode);
1949+
loff_t size;
19501950
int err;
19511951

19521952
BUG_ON(page->index != mpd->first_page);
1953-
if (page->index == size >> PAGE_CACHE_SHIFT)
1954-
len = size & ~PAGE_CACHE_MASK;
1955-
else
1956-
len = PAGE_CACHE_SIZE;
19571953
clear_page_dirty_for_io(page);
1954+
/*
1955+
* We have to be very careful here! Nothing protects writeback path
1956+
* against i_size changes and the page can be writeably mapped into
1957+
* page tables. So an application can be growing i_size and writing
1958+
* data through mmap while writeback runs. clear_page_dirty_for_io()
1959+
* write-protects our page in page tables and the page cannot get
1960+
* written to again until we release page lock. So only after
1961+
* clear_page_dirty_for_io() we are safe to sample i_size for
1962+
* ext4_bio_write_page() to zero-out tail of the written page. We rely
1963+
* on the barrier provided by TestClearPageDirty in
1964+
* clear_page_dirty_for_io() to make sure i_size is really sampled only
1965+
* after page tables are updated.
1966+
*/
1967+
size = i_size_read(mpd->inode);
1968+
if (page->index == size >> PAGE_SHIFT)
1969+
len = size & ~PAGE_MASK;
1970+
else
1971+
len = PAGE_SIZE;
19581972
err = ext4_bio_write_page(&mpd->io_submit, page, len, mpd->wbc, false);
19591973
if (!err)
19601974
mpd->wbc->nr_to_write--;

0 commit comments

Comments
 (0)