Skip to content

Commit 94bacfb

Browse files
committed
ovl: fix use after free in struct ovl_aio_req
jira VULN-6260 cve CVE-2023-1252 commit-author yangerkun <[email protected]> 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 <[email protected]> Link: https://lore.kernel.org/r/[email protected]/ Cc: <[email protected]> # v5.6 Signed-off-by: Miklos Szeredi <[email protected]> (cherry picked from commit 9a25440) Signed-off-by: Marcin Wcisło <[email protected]>
1 parent 23ca0c7 commit 94bacfb

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
@@ -17,6 +17,7 @@
1717

1818
struct ovl_aio_req {
1919
struct kiocb iocb;
20+
refcount_t ref;
2021
struct kiocb *orig_iocb;
2122
struct fd fd;
2223
};
@@ -252,6 +253,14 @@ static rwf_t ovl_iocb_to_rwf(int ifl)
252253
return flags;
253254
}
254255

256+
static inline void ovl_aio_put(struct ovl_aio_req *aio_req)
257+
{
258+
if (refcount_dec_and_test(&aio_req->ref)) {
259+
fdput(aio_req->fd);
260+
kmem_cache_free(ovl_aio_request_cachep, aio_req);
261+
}
262+
}
263+
255264
static void ovl_aio_cleanup_handler(struct ovl_aio_req *aio_req)
256265
{
257266
struct kiocb *iocb = &aio_req->iocb;
@@ -268,8 +277,7 @@ static void ovl_aio_cleanup_handler(struct ovl_aio_req *aio_req)
268277
}
269278

270279
orig_iocb->ki_pos = iocb->ki_pos;
271-
fdput(aio_req->fd);
272-
kmem_cache_free(ovl_aio_request_cachep, aio_req);
280+
ovl_aio_put(aio_req);
273281
}
274282

275283
static void ovl_aio_rw_complete(struct kiocb *iocb, long res)
@@ -313,7 +321,9 @@ static ssize_t ovl_read_iter(struct kiocb *iocb, struct iov_iter *iter)
313321
aio_req->orig_iocb = iocb;
314322
kiocb_clone(&aio_req->iocb, iocb, real.file);
315323
aio_req->iocb.ki_complete = ovl_aio_rw_complete;
324+
refcount_set(&aio_req->ref, 2);
316325
ret = vfs_iocb_iter_read(real.file, &aio_req->iocb, iter);
326+
ovl_aio_put(aio_req);
317327
if (ret != -EIOCBQUEUED)
318328
ovl_aio_cleanup_handler(aio_req);
319329
}
@@ -378,7 +388,9 @@ static ssize_t ovl_write_iter(struct kiocb *iocb, struct iov_iter *iter)
378388
kiocb_clone(&aio_req->iocb, iocb, real.file);
379389
aio_req->iocb.ki_flags = ifl;
380390
aio_req->iocb.ki_complete = ovl_aio_rw_complete;
391+
refcount_set(&aio_req->ref, 2);
381392
ret = vfs_iocb_iter_write(real.file, &aio_req->iocb, iter);
393+
ovl_aio_put(aio_req);
382394
if (ret != -EIOCBQUEUED)
383395
ovl_aio_cleanup_handler(aio_req);
384396
}

0 commit comments

Comments
 (0)