[PATCH v2] md/raid1: prevent a race between write and stop request

Edward Adam Davis <[email protected]>
Newsgroups gmane.linux.kernel,gmane.linux.raid
Message-ID <[email protected]>
A race condition exists between write and stop requests, leading to a
null-ptr-deref in [1].

CPU0				CPU1
====				====
md_submit_bio()
md_handle_request()		do_md_stop()
raid1_make_request()		 __md_stop()
raid1_write_request()		   mddev->private = NULL
wait_barrier()
conf->nr_pending //trigger [1]

The intervention of a stop request causes inconsistencies in the state
of mddev members (such as private and pers) while a write request is
executing; the mddev lock is used to synchronize write and stop requests,
thereby ensuring consistent mddev state throughout the execution of the
write request.

Additionally, when a write operation reaches the RAID1 layer, if a stop
request acquires the mddev lock first and releases mddev->private, the
bio is terminated and the write request exits.
	
[1]
KASAN: null-ptr-deref in range [0x0000000000000120-0x0000000000000127]
RIP: 0010:_wait_barrier+0x8d/0x700 drivers/md/raid1.c:1066
Call Trace:
 wait_barrier drivers/md/raid1.c:1154 [inline]
 raid1_write_request drivers/md/raid1.c:1506 [inline]
 raid1_make_request+0x484/0x31a0 drivers/md/raid1.c:1696
 md_handle_request+0x824/0x1230 drivers/md/md.c:417
 md_submit_bio+0x1e9/0x350 drivers/md/md.c:458
 __submit_bio block/blk-core.c:681 [inline]
 __submit_bio+0x20e/0x3d0 block/blk-core.c:670
 __submit_bio_noacct block/blk-core.c:724 [inline]
 submit_bio_noacct_nocheck+0x736/0xc00 block/blk-core.c:792
 submit_bio_noacct+0xc93/0x2130 block/blk-core.c:925
 bio_await+0x1fa/0x240 block/bio.c:1580
 submit_bio_wait+0x19/0x60 block/bio.c:1598
 __blkdev_direct_IO_simple+0x4cb/0x8c0 block/fops.c:98
 blkdev_direct_IO+0xbee/0x2030 block/fops.c:429
 blkdev_direct_write block/fops.c:699 [inline]
 blkdev_write_iter+0x703/0xd30 block/fops.c:767
 new_sync_write fs/read_write.c:595 [inline]
 vfs_write+0x6af/0x1050 fs/read_write.c:687

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Reported-by: [email protected]
Closes: https://syzkaller.appspot.com/bug?extid=3fe892ea5fc292e1353f
Tested-by: [email protected]
Signed-off-by: Edward Adam Davis <[email protected]>
---
v1 -> v2: typo in comments

 drivers/md/raid1.c | 28 +++++++++++++++++++++++++++-
 1 file changed, 27 insertions(+), 1 deletion(-)

diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index f0646fb24371..3b9f1fa65e65 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -1674,6 +1674,7 @@ static bool raid1_write_request(struct mddev *mddev, struct bio *bio,
 static bool raid1_make_request(struct mddev *mddev, struct bio *bio)
 {
 	sector_t sectors;
+	blk_status_t status;
 
 	if (unlikely(bio->bi_opf & REQ_PREFLUSH)
 	    && md_flush_request(mddev, bio))
@@ -1692,11 +1693,36 @@ static bool raid1_make_request(struct mddev *mddev, struct bio *bio)
 	if (bio_data_dir(bio) == READ)
 		raid1_read_request(mddev, bio, sectors, NULL);
 	else {
+		int err;
+
 		md_write_start(mddev, bio);
-		if (!raid1_write_request(mddev, bio, sectors))
+		err = mddev_lock(mddev);
+
+		if (err < 0) {
+			md_write_end(mddev);
+			status = BLK_STS_IOERR;
+			goto done;
+		}
+
+		if (!mddev->private) {
+			mddev_unlock(mddev);
+			md_write_end(mddev);
+			status = BLK_STS_OFFLINE;
+			goto done;
+		}
+
+		err = raid1_write_request(mddev, bio, sectors);
+		mddev_unlock(mddev);
+
+		if (!err)
 			md_write_end(mddev);
 	}
+out:
 	return true;
+done:
+	bio->bi_status = status;
+	bio_endio(bio);
+	goto out;
 }
 
 static void raid1_status(struct seq_file *seq, struct mddev *mddev)
-- 
2.43.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.