A failed table load can leave a mapped device in a state where its
queue has already been initialized or its disk has been removed, while
md->type is still DM_TYPE_NONE. A later table load then calls
blk_mq_init_allocated_queue() on the same queue. If del_gendisk() exited
the old hardware contexts, blk_mq_exit_hctx() dereferences their cleared
flush queue pointer.

Reject setup attempts after queue initialization or disk removal. A
failed request queue initialization still leaves md->tag_set NULL and
can be retried. Set the request-based disk operations only after that
initialization succeeds, so an unsuccessful attempt cannot leave a
bio-based retry with request-based operations.

Reported-by: [email protected]
Closes: https://syzkaller.appspot.com/bug?extid=5307e3bcacec2ce4c2f0
Signed-off-by: Kirtikumar Anandrao Ramchandani <[email protected]>
---
Changes in v2:
- Resend as plain text after the previous mail client reformatted the diff.

 drivers/md/dm.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 1881d86..2f3f1ec 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -2606,13 +2606,17 @@ int dm_setup_md_queue(struct mapped_device
*md, struct dm_table *t)

        WARN_ON_ONCE(type == DM_TYPE_NONE);

+       /* A failed setup may have left the queue initialized or the disk dead. 
*/
+       if (md->tag_set || test_bit(GD_DEAD, &md->disk->state))
+               return -ENODEV;
+
        if (type == DM_TYPE_REQUEST_BASED) {
-               md->disk->fops = &dm_rq_blk_dops;
                r = dm_mq_init_request_queue(md, t);
                if (r) {
                        DMERR("Cannot initialize queue for request-based dm 
mapped device");
                        return r;
                }
+               md->disk->fops = &dm_rq_blk_dops;
        }

        r = dm_calculate_queue_limits(t, &limits);

base-commit: 05441d697f7f9a927264f4058cbbc6a03dfcac9d

Reply via email to