On Wed, Jun 09, 2021 at 09:59:43AM +0100, John Garry wrote: > On 09/06/2021 07:30, Ming Lei wrote: > > Thanks for the fix > > > tagset can't be used after blk_cleanup_queue() is returned because > > freeing tagset usually follows blk_clenup_queue(). Commit d97e594c5166 > > ("blk-mq: Use request queue-wide tags for tagset-wide sbitmap") adds > > check on q->tag_set->flags in blk_mq_exit_sched(), and causes > > use-after-free. > > > > Fixes it by using hctx->flags. > > > > The tagset is a member of the Scsi_Host structure. So it is true that this > memory may be freed before the request_queue is exited? Yeah, please see commit c3e2219216c9 ("block: free sched's request pool in blk_cleanup_queue") > > > Reported-by: syzbot+77ba3d171a25c56756ea@xxxxxxxxxxxxxxxxxxxxxxxxx > > Fixes: d97e594c5166 ("blk-mq: Use request queue-wide tags for tagset-wide sbitmap") > > Cc: John Garry <john.garry@xxxxxxxxxx> > > Signed-off-by: Ming Lei <ming.lei@xxxxxxxxxx> > > --- > > block/blk-mq-sched.c | 4 +++- > > 1 file changed, 3 insertions(+), 1 deletion(-) > > > > diff --git a/block/blk-mq-sched.c b/block/blk-mq-sched.c > > index a9182d2f8ad3..80273245d11a 100644 > > --- a/block/blk-mq-sched.c > > +++ b/block/blk-mq-sched.c > > @@ -680,6 +680,7 @@ void blk_mq_exit_sched(struct request_queue *q, struct elevator_queue *e) > > { > > struct blk_mq_hw_ctx *hctx; > > unsigned int i; > > + unsigned int flags = 0; > > queue_for_each_hw_ctx(q, hctx, i) { > > blk_mq_debugfs_unregister_sched_hctx(hctx); > > @@ -687,12 +688,13 @@ void blk_mq_exit_sched(struct request_queue *q, struct elevator_queue *e) > > e->type->ops.exit_hctx(hctx, i); > > hctx->sched_data = NULL; > > } > > + flags = hctx->flags; > > I know the choice is limited, but it is unfortunate that we must set flags > in a loop Does it matter? > > > } > > blk_mq_debugfs_unregister_sched(q); > > if (e->type->ops.exit_sched) > > e->type->ops.exit_sched(e); > > blk_mq_sched_tags_teardown(q); > > - if (blk_mq_is_sbitmap_shared(q->tag_set->flags)) > > + if (blk_mq_is_sbitmap_shared(flags)) > > blk_mq_exit_sched_shared_sbitmap(q); > > this is > > blk_mq_exit_sched_shared_sbitmap(struct request_queue *queue) > { > sbitmap_queue_free(&queue->sched_bitmap_tags); > .. > } > > And isn't it safe to call sbitmap_queue_free() when > sbitmap_queue_init_node() has not been called? > > I'm just wondering if we can always call blk_mq_exit_sched_shared_sbitmap()? > I know it's not an ideal choice either. So far it may work, not sure if it can in future, I suggest to follow the traditional alloc & free pattern. Thanks, Ming