lkml.org 
[lkml]   [2017]   [Oct]   [10]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.4 45/47] ext4: fix data corruption for mmap writes
    Date
    4.4-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Jan Kara <jack@suse.cz>

    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: cb20d5188366f04d96d2e07b1240cc92170ade40
    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>

    ---
    fs/ext4/inode.c | 24 +++++++++++++++++++-----
    1 file changed, 19 insertions(+), 5 deletions(-)

    --- a/fs/ext4/inode.c
    +++ b/fs/ext4/inode.c
    @@ -1946,15 +1946,29 @@ static int ext4_writepage(struct page *p
    static int mpage_submit_page(struct mpage_da_data *mpd, struct page *page)
    {
    int len;
    - loff_t size = i_size_read(mpd->inode);
    + loff_t size;
    int err;

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

    \
     
     \ /
      Last update: 2017-10-10 23:08    [W:4.132 / U:0.104 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site