Skip to content

Commit b033dc8

Browse files
committed
ovl: fix use after free in struct ovl_aio_req
jira VULN-3964 cve CVE-2023-1252 commit-author yangerkun <yangerkun@huawei.com> commit 9a25440 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: 2406a30 ("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> (cherry picked from commit 9a25440) Signed-off-by: Marcin Wcisło <marcin.wcislo@conclusive.pl>
1 parent 68b3ca9 commit b033dc8

File tree

1 file changed

+14
-2
lines changed

1 file changed

+14
-2
lines changed

fs/overlayfs/file.c

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
struct ovl_aio_req {
2222
struct kiocb iocb;
23+
refcount_t ref;
2324
struct kiocb *orig_iocb;
2425
struct fd fd;
2526
};
@@ -255,6 +256,14 @@ static rwf_t ovl_iocb_to_rwf(int ifl)
255256
return flags;
256257
}
257258

259+
static inline void ovl_aio_put(struct ovl_aio_req *aio_req)
260+
{
261+
if (refcount_dec_and_test(&aio_req->ref)) {
262+
fdput(aio_req->fd);
263+
kmem_cache_free(ovl_aio_request_cachep, aio_req);
264+
}
265+
}
266+
258267
static void ovl_aio_cleanup_handler(struct ovl_aio_req *aio_req)
259268
{
260269
struct kiocb *iocb = &aio_req->iocb;
@@ -271,8 +280,7 @@ static void ovl_aio_cleanup_handler(struct ovl_aio_req *aio_req)
271280
}
272281

273282
orig_iocb->ki_pos = iocb->ki_pos;
274-
fdput(aio_req->fd);
275-
kmem_cache_free(ovl_aio_request_cachep, aio_req);
283+
ovl_aio_put(aio_req);
276284
}
277285

278286
static void ovl_aio_rw_complete(struct kiocb *iocb, long res, long res2)
@@ -316,7 +324,9 @@ static ssize_t ovl_read_iter(struct kiocb *iocb, struct iov_iter *iter)
316324
aio_req->orig_iocb = iocb;
317325
kiocb_clone(&aio_req->iocb, iocb, real.file);
318326
aio_req->iocb.ki_complete = ovl_aio_rw_complete;
327+
refcount_set(&aio_req->ref, 2);
319328
ret = vfs_iocb_iter_read(real.file, &aio_req->iocb, iter);
329+
ovl_aio_put(aio_req);
320330
if (ret != -EIOCBQUEUED)
321331
ovl_aio_cleanup_handler(aio_req);
322332
}
@@ -381,7 +391,9 @@ static ssize_t ovl_write_iter(struct kiocb *iocb, struct iov_iter *iter)
381391
kiocb_clone(&aio_req->iocb, iocb, real.file);
382392
aio_req->iocb.ki_flags = ifl;
383393
aio_req->iocb.ki_complete = ovl_aio_rw_complete;
394+
refcount_set(&aio_req->ref, 2);
384395
ret = vfs_iocb_iter_write(real.file, &aio_req->iocb, iter);
396+
ovl_aio_put(aio_req);
385397
if (ret != -EIOCBQUEUED)
386398
ovl_aio_cleanup_handler(aio_req);
387399
}

0 commit comments

Comments
 (0)