Re: [PATCH] block: fix use-after-free in dio_bio_complete

From: Konstantin Khlebnikov
Date: Sat Jan 30 2016 - 11:41:52 EST


On Sat, Jan 30, 2016 at 7:09 PM, Mike Krinkin <krinkin.m.u@xxxxxxxxx> wrote:
> kasan reported the following error when i ran xfstest:
>
> [ 701.826854] ==================================================================
> [ 701.826864] BUG: KASAN: use-after-free in dio_bio_complete+0x41a/0x600 at addr ffff880080b95f94
> [ 701.826870] Read of size 4 by task loop2/3874
> [ 701.826879] page:ffffea000202e540 count:0 mapcount:0 mapping: (null) index:0x0
> [ 701.826890] flags: 0x100000000000000()
> [ 701.826895] page dumped because: kasan: bad access detected
> [ 701.826904] CPU: 3 PID: 3874 Comm: loop2 Tainted: G B W L 4.5.0-rc1-next-20160129 #83
> [ 701.826910] Hardware name: LENOVO 23205NG/23205NG, BIOS G2ET95WW (2.55 ) 07/09/2013
> [ 701.826917] ffff88008fadf800 ffff88008fadf758 ffffffff81ca67bb 0000000041b58ab3
> [ 701.826941] ffffffff830d1e74 ffffffff81ca6724 ffff88008fadf748 ffffffff8161c05c
> [ 701.826963] 0000000000000282 ffff88008fadf800 ffffed0010172bf2 ffffea000202e540
> [ 701.826987] Call Trace:
> [ 701.826997] [<ffffffff81ca67bb>] dump_stack+0x97/0xdc
> [ 701.827005] [<ffffffff81ca6724>] ? _atomic_dec_and_lock+0xc4/0xc4
> [ 701.827014] [<ffffffff8161c05c>] ? __dump_page+0x32c/0x490
> [ 701.827023] [<ffffffff816b0d03>] kasan_report_error+0x5f3/0x8b0
> [ 701.827033] [<ffffffff817c302a>] ? dio_bio_complete+0x41a/0x600
> [ 701.827040] [<ffffffff816b1119>] __asan_report_load4_noabort+0x59/0x80
> [ 701.827048] [<ffffffff817c302a>] ? dio_bio_complete+0x41a/0x600
> [ 701.827053] [<ffffffff817c302a>] dio_bio_complete+0x41a/0x600
> [ 701.827057] [<ffffffff81bd19c8>] ? blk_queue_exit+0x108/0x270
> [ 701.827060] [<ffffffff817c32b0>] dio_bio_end_aio+0xa0/0x4d0
> [ 701.827063] [<ffffffff817c3210>] ? dio_bio_complete+0x600/0x600
> [ 701.827067] [<ffffffff81bd2806>] ? blk_account_io_completion+0x316/0x5d0
> [ 701.827070] [<ffffffff81bafe89>] bio_endio+0x79/0x200
> [ 701.827074] [<ffffffff81bd2c9f>] blk_update_request+0x1df/0xc50
> [ 701.827078] [<ffffffff81c02c27>] blk_mq_end_request+0x57/0x120
> [ 701.827081] [<ffffffff81c03670>] __blk_mq_complete_request+0x310/0x590
> [ 701.827084] [<ffffffff812348d8>] ? set_next_entity+0x2f8/0x2ed0
> [ 701.827088] [<ffffffff8124b34d>] ? put_prev_entity+0x22d/0x2a70
> [ 701.827091] [<ffffffff81c0394b>] blk_mq_complete_request+0x5b/0x80
> [ 701.827094] [<ffffffff821e2a33>] loop_queue_work+0x273/0x19d0
> [ 701.827098] [<ffffffff811f6578>] ? finish_task_switch+0x1c8/0x8e0
> [ 701.827101] [<ffffffff8129d058>] ? trace_hardirqs_on_caller+0x18/0x6c0
> [ 701.827104] [<ffffffff821e27c0>] ? lo_read_simple+0x890/0x890
> [ 701.827108] [<ffffffff8129dd60>] ? debug_check_no_locks_freed+0x350/0x350
> [ 701.827111] [<ffffffff811f63b0>] ? __hrtick_start+0x130/0x130
> [ 701.827115] [<ffffffff82a0c8f6>] ? __schedule+0x936/0x20b0
> [ 701.827118] [<ffffffff811dd6bd>] ? kthread_worker_fn+0x3ed/0x8d0
> [ 701.827121] [<ffffffff811dd4ed>] ? kthread_worker_fn+0x21d/0x8d0
> [ 701.827125] [<ffffffff8129d058>] ? trace_hardirqs_on_caller+0x18/0x6c0
> [ 701.827128] [<ffffffff811dd57f>] kthread_worker_fn+0x2af/0x8d0
> [ 701.827132] [<ffffffff811dd2d0>] ? __init_kthread_worker+0x170/0x170
> [ 701.827135] [<ffffffff82a1ea46>] ? _raw_spin_unlock_irqrestore+0x36/0x60
> [ 701.827138] [<ffffffff811dd2d0>] ? __init_kthread_worker+0x170/0x170
> [ 701.827141] [<ffffffff811dd2d0>] ? __init_kthread_worker+0x170/0x170
> [ 701.827144] [<ffffffff811dd00b>] kthread+0x24b/0x3a0
> [ 701.827148] [<ffffffff811dcdc0>] ? kthread_create_on_node+0x4c0/0x4c0
> [ 701.827151] [<ffffffff8129d70d>] ? trace_hardirqs_on+0xd/0x10
> [ 701.827155] [<ffffffff8116d41d>] ? do_group_exit+0xdd/0x350
> [ 701.827158] [<ffffffff811dcdc0>] ? kthread_create_on_node+0x4c0/0x4c0
> [ 701.827161] [<ffffffff82a1f52f>] ret_from_fork+0x3f/0x70
> [ 701.827165] [<ffffffff811dcdc0>] ? kthread_create_on_node+0x4c0/0x4c0
> [ 701.827167] Memory state around the buggy address:
> [ 701.827170] ffff880080b95e80: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 701.827172] ffff880080b95f00: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 701.827175] >ffff880080b95f80: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 701.827177] ^
> [ 701.827179] ffff880080b96000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 701.827182] ffff880080b96080: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [ 701.827183] ==================================================================
>
> The problem is that bio_check_pages_dirty calls bio_put, so we must
> not access bio fields after bio_check_pages_dirty.
>
> Fixes: 9b81c842355ac96097ba ("block: don't access bio->bi_error after
> bio_put()").
>
> Signed-off-by: Mike Krinkin <krinkin.m.u@xxxxxxxxx>

Just got the same splat.
Ack.

> ---
> fs/direct-io.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/fs/direct-io.c b/fs/direct-io.c
> index 1b2f7ff..d6a9012 100644
> --- a/fs/direct-io.c
> +++ b/fs/direct-io.c
> @@ -472,8 +472,8 @@ static int dio_bio_complete(struct dio *dio, struct bio *bio)
> dio->io_error = -EIO;
>
> if (dio->is_async && dio->rw == READ && dio->should_dirty) {
> - bio_check_pages_dirty(bio); /* transfers ownership */
> err = bio->bi_error;
> + bio_check_pages_dirty(bio); /* transfers ownership */
> } else {
> bio_for_each_segment_all(bvec, bio, i) {
> struct page *page = bvec->bv_page;
> --
> 1.9.1
>