md/raid5-cache: fix null-ptr-deref for r5l_flush_stripe_to_raid()
authorYu Kuai <yukuai3@huawei.com>
Tue, 8 Aug 2023 10:49:12 +0000 (18:49 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 13 Sep 2023 07:42:44 +0000 (09:42 +0200)
[ Upstream commit 0d0bd28c500173bfca78aa840f8f36d261ef1765 ]

r5l_flush_stripe_to_raid() will check if the list 'flushing_ios' is
empty, and then submit 'flush_bio', however, r5l_log_flush_endio()
is clearing the list first and then clear the bio, which will cause
null-ptr-deref:

T1: submit flush io
raid5d
 handle_active_stripes
  r5l_flush_stripe_to_raid
   // list is empty
   // add 'io_end_ios' to the list
   bio_init
   submit_bio
   // io1

T2: io1 is done
r5l_log_flush_endio
 list_splice_tail_init
 // clear the list
T3: submit new flush io
...
r5l_flush_stripe_to_raid
 // list is empty
 // add 'io_end_ios' to the list
 bio_init
 bio_uninit
 // clear bio->bi_blkg
 submit_bio
 // null-ptr-deref

Fix this problem by clearing bio before clearing the list in
r5l_log_flush_endio().

Fixes: 0dd00cba99c3 ("raid5-cache: fully initialize flush_bio when needed")
Reported-and-tested-by: Corey Hickey <bugfood-ml@fatooh.org>
Closes: https://lore.kernel.org/all/cddd7213-3dfd-4ab7-a3ac-edd54d74a626@fatooh.org/
Signed-off-by: Yu Kuai <yukuai3@huawei.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Song Liu <song@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/md/raid5-cache.c

index 477e3ae17545a587b068bf4cbabce085a78e0b2f..eb66d0bfe39d2e75f5d55d2745e56bbb46b39808 100644 (file)
@@ -1260,14 +1260,13 @@ static void r5l_log_flush_endio(struct bio *bio)
 
        if (bio->bi_status)
                md_error(log->rdev->mddev, log->rdev);
+       bio_uninit(bio);
 
        spin_lock_irqsave(&log->io_list_lock, flags);
        list_for_each_entry(io, &log->flushing_ios, log_sibling)
                r5l_io_run_stripes(io);
        list_splice_tail_init(&log->flushing_ios, &log->finished_ios);
        spin_unlock_irqrestore(&log->io_list_lock, flags);
-
-       bio_uninit(bio);
 }
 
 /*