1 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
2 From: Ming Lei <ming.lei@redhat.com>
3 Date: Fri, 10 Sep 2021 14:30:15 +0200
4 Subject: [PATCH] blk-mq: fix kernel panic during iterating over flush request
6 commit c2da19ed50554ce52ecbad3655c98371fe58599f upstream.
8 For fixing use-after-free during iterating over requests, we grabbed
9 request's refcount before calling ->fn in commit 2e315dc07df0 ("blk-mq:
10 grab rq->refcount before calling ->fn in blk_mq_tagset_busy_iter").
11 Turns out this way may cause kernel panic when iterating over one flush
14 1) old flush request's tag is just released, and this tag is reused by
15 one new request, but ->rqs[] isn't updated yet
17 2) the flush request can be re-used for submitting one new flush command,
18 so blk_rq_init() is called at the same time
20 3) meantime blk_mq_queue_tag_busy_iter() is called, and old flush request
21 is retrieved from ->rqs[tag]; when blk_mq_put_rq_ref() is called,
22 flush_rq->end_io may not be updated yet, so NULL pointer dereference
23 is triggered in blk_mq_put_rq_ref().
25 Fix the issue by calling refcount_set(&flush_rq->ref, 1) after
26 flush_rq->end_io is set. So far the only other caller of blk_rq_init() is
27 scsi_ioctl_reset() in which the request doesn't enter block IO stack and
28 the request reference count isn't used, so the change is safe.
30 Fixes: 2e315dc07df0 ("blk-mq: grab rq->refcount before calling ->fn in blk_mq_tagset_busy_iter")
31 Reported-by: "Blank-Burian, Markus, Dr." <blankburian@uni-muenster.de>
32 Tested-by: "Blank-Burian, Markus, Dr." <blankburian@uni-muenster.de>
33 Signed-off-by: Ming Lei <ming.lei@redhat.com>
34 Reviewed-by: Christoph Hellwig <hch@lst.de>
35 Reviewed-by: John Garry <john.garry@huawei.com>
36 Link: https://lore.kernel.org/r/20210811142624.618598-1-ming.lei@redhat.com
37 Signed-off-by: Jens Axboe <axboe@kernel.dk>
38 Cc: Yi Zhang <yi.zhang@redhat.com>
39 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
41 block/blk-core.c | 1 -
42 block/blk-flush.c | 8 ++++++++
43 2 files changed, 8 insertions(+), 1 deletion(-)
45 diff --git a/block/blk-core.c b/block/blk-core.c
46 index 7663a9b94b80..debdf9b0bf30 100644
47 --- a/block/blk-core.c
48 +++ b/block/blk-core.c
49 @@ -121,7 +121,6 @@ void blk_rq_init(struct request_queue *q, struct request *rq)
50 rq->internal_tag = BLK_MQ_NO_TAG;
51 rq->start_time_ns = ktime_get_ns();
53 - refcount_set(&rq->ref, 1);
54 blk_crypto_rq_set_defaults(rq);
56 EXPORT_SYMBOL(blk_rq_init);
57 diff --git a/block/blk-flush.c b/block/blk-flush.c
58 index e89d007dbf6a..8b11ab3b3762 100644
59 --- a/block/blk-flush.c
60 +++ b/block/blk-flush.c
61 @@ -329,6 +329,14 @@ static void blk_kick_flush(struct request_queue *q, struct blk_flush_queue *fq,
62 flush_rq->rq_flags |= RQF_FLUSH_SEQ;
63 flush_rq->rq_disk = first_rq->rq_disk;
64 flush_rq->end_io = flush_end_io;
66 + * Order WRITE ->end_io and WRITE rq->ref, and its pair is the one
67 + * implied in refcount_inc_not_zero() called from
68 + * blk_mq_find_and_get_req(), which orders WRITE/READ flush_rq->ref
69 + * and READ flush_rq->end_io
72 + refcount_set(&flush_rq->ref, 1);
74 blk_flush_queue_rq(flush_rq, false);