lkml.org 
[lkml]   [2021]   [Nov]   [15]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.14 167/849] ovl: fix use after free in struct ovl_aio_req
    Date
    From: yangerkun <yangerkun@huawei.com>

    commit 9a254403760041528bc8f69fe2f5e1ef86950991 upstream.

    Example for triggering use after free in a overlay on ext4 setup:

    aio_read
    ovl_read_iter
    vfs_iter_read
    ext4_file_read_iter
    ext4_dio_read_iter
    iomap_dio_rw -> -EIOCBQUEUED
    /*
    * Here IO is completed in a separate thread,
    * ovl_aio_cleanup_handler() frees aio_req which has iocb embedded
    */
    file_accessed(iocb->ki_filp); /**BOOM**/

    Fix by introducing a refcount in ovl_aio_req similarly to aio_kiocb. This
    guarantees that iocb is only freed after vfs_read/write_iter() returns on
    underlying fs.

    Fixes: 2406a307ac7d ("ovl: implement async IO routines")
    Signed-off-by: yangerkun <yangerkun@huawei.com>
    Link: https://lore.kernel.org/r/20210930032228.3199690-3-yangerkun@huawei.com/
    Cc: <stable@vger.kernel.org> # v5.6
    Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    ---
    fs/overlayfs/file.c | 16 ++++++++++++++--
    1 file changed, 14 insertions(+), 2 deletions(-)

    --- a/fs/overlayfs/file.c
    +++ b/fs/overlayfs/file.c
    @@ -17,6 +17,7 @@

    struct ovl_aio_req {
    struct kiocb iocb;
    + refcount_t ref;
    struct kiocb *orig_iocb;
    struct fd fd;
    };
    @@ -252,6 +253,14 @@ static rwf_t ovl_iocb_to_rwf(int ifl)
    return flags;
    }

    +static inline void ovl_aio_put(struct ovl_aio_req *aio_req)
    +{
    + if (refcount_dec_and_test(&aio_req->ref)) {
    + fdput(aio_req->fd);
    + kmem_cache_free(ovl_aio_request_cachep, aio_req);
    + }
    +}
    +
    static void ovl_aio_cleanup_handler(struct ovl_aio_req *aio_req)
    {
    struct kiocb *iocb = &aio_req->iocb;
    @@ -268,8 +277,7 @@ static void ovl_aio_cleanup_handler(stru
    }

    orig_iocb->ki_pos = iocb->ki_pos;
    - fdput(aio_req->fd);
    - kmem_cache_free(ovl_aio_request_cachep, aio_req);
    + ovl_aio_put(aio_req);
    }

    static void ovl_aio_rw_complete(struct kiocb *iocb, long res, long res2)
    @@ -319,7 +327,9 @@ static ssize_t ovl_read_iter(struct kioc
    aio_req->orig_iocb = iocb;
    kiocb_clone(&aio_req->iocb, iocb, real.file);
    aio_req->iocb.ki_complete = ovl_aio_rw_complete;
    + refcount_set(&aio_req->ref, 2);
    ret = vfs_iocb_iter_read(real.file, &aio_req->iocb, iter);
    + ovl_aio_put(aio_req);
    if (ret != -EIOCBQUEUED)
    ovl_aio_cleanup_handler(aio_req);
    }
    @@ -390,7 +400,9 @@ static ssize_t ovl_write_iter(struct kio
    kiocb_clone(&aio_req->iocb, iocb, real.file);
    aio_req->iocb.ki_flags = ifl;
    aio_req->iocb.ki_complete = ovl_aio_rw_complete;
    + refcount_set(&aio_req->ref, 2);
    ret = vfs_iocb_iter_write(real.file, &aio_req->iocb, iter);
    + ovl_aio_put(aio_req);
    if (ret != -EIOCBQUEUED)
    ovl_aio_cleanup_handler(aio_req);
    }

    \
     
     \ /
      Last update: 2021-11-16 02:44    [W:3.008 / U:0.312 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site