This reverts commit 54a88eb838d37af930c9f19e1930a4fba6789cb5. git bisect shows that commit 54a88eb838d3 ("block: add single bio async direct IO helper") causes the following UAF: BUG: KASAN: use-after-free in io_submit_one+0x496/0x2fe0 fs/aio.c:1882 Write of size 4 at addr ffff888027c338a0 by task syz-executor873/15100 CPU: 2 PID: 15100 Comm: syz-executor873 Not tainted 5.16.0-rc1-syzk #1 Hardware name: Red Hat KVM, BIOS Call Trace: <TASK> __dump_stack lib/dump_stack.c:88 [inline] dump_stack_lvl+0x89/0xb5 lib/dump_stack.c:106 print_address_description.constprop.9+0x28/0x160 mm/kasan/report.c:247 __kasan_report mm/kasan/report.c:433 [inline] kasan_report.cold.14+0x7d/0x117 mm/kasan/report.c:450 check_region_inline mm/kasan/generic.c:183 [inline] kasan_check_range+0x18e/0x1f0 mm/kasan/generic.c:189 __kasan_check_write+0x14/0x20 mm/kasan/shadow.c:37 instrument_atomic_read_write include/linux/instrumented.h:101 [inline] atomic_fetch_sub_release include/linux/atomic/atomic-instrumented.h:167 [inline] __refcount_sub_and_test include/linux/refcount.h:272 [inline] __refcount_dec_and_test include/linux/refcount.h:315 [inline] refcount_dec_and_test include/linux/refcount.h:333 [inline] iocb_put fs/aio.c:1161 [inline] io_submit_one+0x496/0x2fe0 fs/aio.c:1882 __do_sys_io_submit fs/aio.c:1938 [inline] __se_sys_io_submit fs/aio.c:1908 [inline] __x64_sys_io_submit+0x1c7/0x4a0 fs/aio.c:1908 do_syscall_x64 arch/x86/entry/common.c:50 [inline] do_syscall_64+0x3a/0x80 arch/x86/entry/common.c:80 entry_SYSCALL_64_after_hwframe+0x44/0xae Conflicts: block/fops.c Reported-by: syzkaller <syzkaller@xxxxxxxxxxxxxxxx> Signed-off-by: George Kennedy <george.kennedy@xxxxxxxxxx> --- block/fops.c | 86 +++--------------------------------------------------------- 1 file changed, 3 insertions(+), 83 deletions(-) diff --git a/block/fops.c b/block/fops.c index e73167b..88e0401 100644 --- a/block/fops.c +++ b/block/fops.c @@ -282,84 +282,6 @@ static ssize_t __blkdev_direct_IO(struct kiocb *iocb, struct iov_iter *iter, return ret; } -static void blkdev_bio_end_io_async(struct bio *bio) -{ - struct blkdev_dio *dio = container_of(bio, struct blkdev_dio, bio); - struct kiocb *iocb = dio->iocb; - ssize_t ret; - - if (likely(!bio->bi_status)) { - ret = dio->size; - iocb->ki_pos += ret; - } else { - ret = blk_status_to_errno(bio->bi_status); - } - - iocb->ki_complete(iocb, ret); - - if (dio->flags & DIO_SHOULD_DIRTY) { - bio_check_pages_dirty(bio); - } else { - bio_release_pages(bio, false); - bio_put(bio); - } -} - -static ssize_t __blkdev_direct_IO_async(struct kiocb *iocb, - struct iov_iter *iter, - unsigned int nr_pages) -{ - struct block_device *bdev = iocb->ki_filp->private_data; - struct blkdev_dio *dio; - struct bio *bio; - loff_t pos = iocb->ki_pos; - int ret = 0; - - if ((pos | iov_iter_alignment(iter)) & - (bdev_logical_block_size(bdev) - 1)) - return -EINVAL; - - bio = bio_alloc_kiocb(iocb, nr_pages, &blkdev_dio_pool); - dio = container_of(bio, struct blkdev_dio, bio); - dio->flags = 0; - dio->iocb = iocb; - bio_set_dev(bio, bdev); - bio->bi_iter.bi_sector = pos >> SECTOR_SHIFT; - bio->bi_write_hint = iocb->ki_hint; - bio->bi_end_io = blkdev_bio_end_io_async; - bio->bi_ioprio = iocb->ki_ioprio; - - ret = bio_iov_iter_get_pages(bio, iter); - if (unlikely(ret)) { - bio->bi_status = BLK_STS_IOERR; - bio_endio(bio); - return ret; - } - dio->size = bio->bi_iter.bi_size; - - if (iov_iter_rw(iter) == READ) { - bio->bi_opf = REQ_OP_READ; - if (iter_is_iovec(iter)) { - dio->flags |= DIO_SHOULD_DIRTY; - bio_set_pages_dirty(bio); - } - } else { - bio->bi_opf = dio_bio_write_op(iocb); - task_io_account_write(bio->bi_iter.bi_size); - } - - if (iocb->ki_flags & IOCB_HIPRI) { - bio->bi_opf |= REQ_POLLED | REQ_NOWAIT; - submit_bio(bio); - WRITE_ONCE(iocb->private, bio); - } else { - if (iocb->ki_flags & IOCB_NOWAIT) - bio->bi_opf |= REQ_NOWAIT; - submit_bio(bio); - } - return -EIOCBQUEUED; -} - static ssize_t blkdev_direct_IO(struct kiocb *iocb, struct iov_iter *iter) { unsigned int nr_pages; @@ -368,11 +290,9 @@ static ssize_t blkdev_direct_IO(struct kiocb *iocb, struct iov_iter *iter) return 0; nr_pages = bio_iov_vecs_to_alloc(iter, BIO_MAX_VECS + 1); - if (likely(nr_pages <= BIO_MAX_VECS)) { - if (is_sync_kiocb(iocb)) - return __blkdev_direct_IO_simple(iocb, iter, nr_pages); - return __blkdev_direct_IO_async(iocb, iter, nr_pages); - } + if (is_sync_kiocb(iocb) && nr_pages <= BIO_MAX_VECS) + return __blkdev_direct_IO_simple(iocb, iter, nr_pages); + return __blkdev_direct_IO(iocb, iter, bio_max_segs(nr_pages)); } -- 1.8.3.1