md/raid10: fix null-ptr-deref of mreplace in raid10_sync_request
authorLi Nan <linan122@huawei.com>
Sat, 27 May 2023 07:22:15 +0000 (15:22 +0800)
committerSong Liu <song@kernel.org>
Tue, 13 Jun 2023 22:25:42 +0000 (15:25 -0700)
There are two check of 'mreplace' in raid10_sync_request(). In the first
check, 'need_replace' will be set and 'mreplace' will be used later if
no-Faulty 'mreplace' exists, In the second check, 'mreplace' will be
set to NULL if it is Faulty, but 'need_replace' will not be changed
accordingly. null-ptr-deref occurs if Faulty is set between two check.

Fix it by merging two checks into one. And replace 'need_replace' with
'mreplace' because their values are always the same.

Fixes: ee37d7314a32 ("md/raid10: Fix raid10 replace hang when new added disk faulty")
Signed-off-by: Li Nan <linan122@huawei.com>
Reviewed-by: Yu Kuai <yukuai3@huawei.com>
Signed-off-by: Song Liu <song@kernel.org>
Link: https://lore.kernel.org/r/20230527072218.2365857-2-linan666@huaweicloud.com
drivers/md/raid10.c

index 0ae7e52..5155228 100644 (file)
@@ -3441,7 +3441,6 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
                        int must_sync;
                        int any_working;
                        int need_recover = 0;
-                       int need_replace = 0;
                        struct raid10_info *mirror = &conf->mirrors[i];
                        struct md_rdev *mrdev, *mreplace;
 
@@ -3453,11 +3452,10 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
                            !test_bit(Faulty, &mrdev->flags) &&
                            !test_bit(In_sync, &mrdev->flags))
                                need_recover = 1;
-                       if (mreplace != NULL &&
-                           !test_bit(Faulty, &mreplace->flags))
-                               need_replace = 1;
+                       if (mreplace && test_bit(Faulty, &mreplace->flags))
+                               mreplace = NULL;
 
-                       if (!need_recover && !need_replace) {
+                       if (!need_recover && !mreplace) {
                                rcu_read_unlock();
                                continue;
                        }
@@ -3473,8 +3471,6 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
                                rcu_read_unlock();
                                continue;
                        }
-                       if (mreplace && test_bit(Faulty, &mreplace->flags))
-                               mreplace = NULL;
                        /* Unless we are doing a full sync, or a replacement
                         * we only need to recover the block if it is set in
                         * the bitmap
@@ -3597,11 +3593,11 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
                                bio = r10_bio->devs[1].repl_bio;
                                if (bio)
                                        bio->bi_end_io = NULL;
-                               /* Note: if need_replace, then bio
+                               /* Note: if replace is not NULL, then bio
                                 * cannot be NULL as r10buf_pool_alloc will
                                 * have allocated it.
                                 */
-                               if (!need_replace)
+                               if (!mreplace)
                                        break;
                                bio->bi_next = biolist;
                                biolist = bio;