blk-mq: fix NULL dereference on q->elevator in blk_mq_elv_switch_none
authorMing Lei <ming.lei@redhat.com>
Fri, 16 Jun 2023 13:23:54 +0000 (21:23 +0800)
committerJens Axboe <axboe@kernel.dk>
Fri, 16 Jun 2023 16:12:25 +0000 (10:12 -0600)
After grabbing q->sysfs_lock, q->elevator may become NULL because of
elevator switch.

Fix the NULL dereference on q->elevator by checking it with lock.

Reported-by: Guangwu Zhang <guazhang@redhat.com>
Signed-off-by: Ming Lei <ming.lei@redhat.com>
Link: https://lore.kernel.org/r/20230616132354.415109-1-ming.lei@redhat.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
block/blk-mq.c

index 24dc8fe0a9d280ddcedf6307e4939ef42159cc24..16c524e37123315610af5094baf5c2f53ed601e7 100644 (file)
@@ -4604,9 +4604,6 @@ static bool blk_mq_elv_switch_none(struct list_head *head,
 {
        struct blk_mq_qe_pair *qe;
 
-       if (!q->elevator)
-               return true;
-
        qe = kmalloc(sizeof(*qe), GFP_NOIO | __GFP_NOWARN | __GFP_NORETRY);
        if (!qe)
                return false;
@@ -4614,6 +4611,12 @@ static bool blk_mq_elv_switch_none(struct list_head *head,
        /* q->elevator needs protection from ->sysfs_lock */
        mutex_lock(&q->sysfs_lock);
 
+       /* the check has to be done with holding sysfs_lock */
+       if (!q->elevator) {
+               kfree(qe);
+               goto unlock;
+       }
+
        INIT_LIST_HEAD(&qe->node);
        qe->q = q;
        qe->type = q->elevator->type;
@@ -4621,6 +4624,7 @@ static bool blk_mq_elv_switch_none(struct list_head *head,
        __elevator_get(qe->type);
        list_add(&qe->node, head);
        elevator_disable(q);
+unlock:
        mutex_unlock(&q->sysfs_lock);
 
        return true;