lkml.org 
[lkml]   [2022]   [Jan]   [31]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.16 027/200] udf: Fix NULL ptr deref when converting from inline format
    Date
    From: Jan Kara <jack@suse.cz>

    commit 7fc3b7c2981bbd1047916ade327beccb90994eee upstream.

    udf_expand_file_adinicb() calls directly ->writepage to write data
    expanded into a page. This however misses to setup inode for writeback
    properly and so we can crash on inode->i_wb dereference when submitting
    page for IO like:

    BUG: kernel NULL pointer dereference, address: 0000000000000158
    #PF: supervisor read access in kernel mode
    ...
    <TASK>
    __folio_start_writeback+0x2ac/0x350
    __block_write_full_page+0x37d/0x490
    udf_expand_file_adinicb+0x255/0x400 [udf]
    udf_file_write_iter+0xbe/0x1b0 [udf]
    new_sync_write+0x125/0x1c0
    vfs_write+0x28e/0x400

    Fix the problem by marking the page dirty and going through the standard
    writeback path to write the page. Strictly speaking we would not even
    have to write the page but we want to catch e.g. ENOSPC errors early.

    Reported-by: butt3rflyh4ck <butterflyhuangxx@gmail.com>
    CC: stable@vger.kernel.org
    Fixes: 52ebea749aae ("writeback: make backing_dev_info host cgroup-specific bdi_writebacks")
    Reviewed-by: Christoph Hellwig <hch@lst.de>
    Signed-off-by: Jan Kara <jack@suse.cz>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    ---
    fs/udf/inode.c | 8 +++-----
    1 file changed, 3 insertions(+), 5 deletions(-)

    --- a/fs/udf/inode.c
    +++ b/fs/udf/inode.c
    @@ -258,10 +258,6 @@ int udf_expand_file_adinicb(struct inode
    char *kaddr;
    struct udf_inode_info *iinfo = UDF_I(inode);
    int err;
    - struct writeback_control udf_wbc = {
    - .sync_mode = WB_SYNC_NONE,
    - .nr_to_write = 1,
    - };

    WARN_ON_ONCE(!inode_is_locked(inode));
    if (!iinfo->i_lenAlloc) {
    @@ -305,8 +301,10 @@ int udf_expand_file_adinicb(struct inode
    iinfo->i_alloc_type = ICBTAG_FLAG_AD_LONG;
    /* from now on we have normal address_space methods */
    inode->i_data.a_ops = &udf_aops;
    + set_page_dirty(page);
    + unlock_page(page);
    up_write(&iinfo->i_data_sem);
    - err = inode->i_data.a_ops->writepage(page, &udf_wbc);
    + err = filemap_fdatawrite(inode->i_mapping);
    if (err) {
    /* Restore everything back so that we don't lose data... */
    lock_page(page);

    \
     
     \ /
      Last update: 2022-01-31 13:09    [W:4.025 / U:0.188 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site