aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2011-09-10 03:21:23 -0400
committerNeilBrown <neilb@suse.de>2011-09-10 03:21:23 -0400
commit079fa166a2874985ae58b2e21e26e1cbc91127d4 (patch)
tree39f67f9078465bd67c29216b35370a78907e4f3b
parent19d5f834d6aff7efb1c9353523865c5bce869470 (diff)
md/raid1,10: Remove use-after-free bug in make_request.
A single request to RAID1 or RAID10 might result in multiple requests if there are known bad blocks that need to be avoided. To detect if we need to submit another write request we test: if (sectors_handled < (bio->bi_size >> 9)) { However this is after we call **_write_done() so the 'bio' no longer belongs to us - the writes could have completed and the bio freed. So move the **_write_done call until after the test against bio->bi_size. This addresses https://bugzilla.kernel.org/show_bug.cgi?id=41862 Reported-by: Bruno Wolff III <bruno@wolff.to> Tested-by: Bruno Wolff III <bruno@wolff.to> Signed-off-by: NeilBrown <neilb@suse.de>
-rw-r--r--drivers/md/raid1.c14
-rw-r--r--drivers/md/raid10.c13
2 files changed, 17 insertions, 10 deletions
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 32323f0afd8..f4622dd8fc5 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -1099,12 +1099,11 @@ read_again:
1099 bio_list_add(&conf->pending_bio_list, mbio); 1099 bio_list_add(&conf->pending_bio_list, mbio);
1100 spin_unlock_irqrestore(&conf->device_lock, flags); 1100 spin_unlock_irqrestore(&conf->device_lock, flags);
1101 } 1101 }
1102 r1_bio_write_done(r1_bio); 1102 /* Mustn't call r1_bio_write_done before this next test,
1103 1103 * as it could result in the bio being freed.
1104 /* In case raid1d snuck in to freeze_array */ 1104 */
1105 wake_up(&conf->wait_barrier);
1106
1107 if (sectors_handled < (bio->bi_size >> 9)) { 1105 if (sectors_handled < (bio->bi_size >> 9)) {
1106 r1_bio_write_done(r1_bio);
1108 /* We need another r1_bio. It has already been counted 1107 /* We need another r1_bio. It has already been counted
1109 * in bio->bi_phys_segments 1108 * in bio->bi_phys_segments
1110 */ 1109 */
@@ -1117,6 +1116,11 @@ read_again:
1117 goto retry_write; 1116 goto retry_write;
1118 } 1117 }
1119 1118
1119 r1_bio_write_done(r1_bio);
1120
1121 /* In case raid1d snuck in to freeze_array */
1122 wake_up(&conf->wait_barrier);
1123
1120 if (do_sync || !bitmap || !plugged) 1124 if (do_sync || !bitmap || !plugged)
1121 md_wakeup_thread(mddev->thread); 1125 md_wakeup_thread(mddev->thread);
1122 1126
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index f6873fc8e5e..d7a8468ddea 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -1132,13 +1132,12 @@ retry_write:
1132 spin_unlock_irqrestore(&conf->device_lock, flags); 1132 spin_unlock_irqrestore(&conf->device_lock, flags);
1133 } 1133 }
1134 1134
1135 /* Remove the bias on 'remaining' */ 1135 /* Don't remove the bias on 'remaining' (one_write_done) until
1136 one_write_done(r10_bio); 1136 * after checking if we need to go around again.
1137 1137 */
1138 /* In case raid10d snuck in to freeze_array */
1139 wake_up(&conf->wait_barrier);
1140 1138
1141 if (sectors_handled < (bio->bi_size >> 9)) { 1139 if (sectors_handled < (bio->bi_size >> 9)) {
1140 one_write_done(r10_bio);
1142 /* We need another r10_bio. It has already been counted 1141 /* We need another r10_bio. It has already been counted
1143 * in bio->bi_phys_segments. 1142 * in bio->bi_phys_segments.
1144 */ 1143 */
@@ -1152,6 +1151,10 @@ retry_write:
1152 r10_bio->state = 0; 1151 r10_bio->state = 0;
1153 goto retry_write; 1152 goto retry_write;
1154 } 1153 }
1154 one_write_done(r10_bio);
1155
1156 /* In case raid10d snuck in to freeze_array */
1157 wake_up(&conf->wait_barrier);
1155 1158
1156 if (do_sync || !mddev->bitmap || !plugged) 1159 if (do_sync || !mddev->bitmap || !plugged)
1157 md_wakeup_thread(mddev->thread); 1160 md_wakeup_thread(mddev->thread);