mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-06 02:50:43 +00:00
ovl: fix use after free in struct ovl_aio_req
commit9a25440376
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:2406a307ac
("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>
This commit is contained in:
parent
af7d25d785
commit
4fd9f0509a
1 changed files with 14 additions and 2 deletions
|
@ -17,6 +17,7 @@
|
|||
|
||||
struct ovl_aio_req {
|
||||
struct kiocb iocb;
|
||||
refcount_t ref;
|
||||
struct kiocb *orig_iocb;
|
||||
struct fd fd;
|
||||
};
|
||||
|
@ -257,6 +258,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;
|
||||
|
@ -273,8 +282,7 @@ static void ovl_aio_cleanup_handler(struct ovl_aio_req *aio_req)
|
|||
}
|
||||
|
||||
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)
|
||||
|
@ -324,7 +332,9 @@ static ssize_t ovl_read_iter(struct kiocb *iocb, struct iov_iter *iter)
|
|||
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);
|
||||
}
|
||||
|
@ -395,7 +405,9 @@ static ssize_t ovl_write_iter(struct kiocb *iocb, struct iov_iter *iter)
|
|||
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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue