Forwarded: [PATCH] configfs: unhash dentry before dropping the item

syzbot posted 1 patch 1 week, 4 days ago
Forwarded: [PATCH] configfs: unhash dentry before dropping the item
Posted by syzbot 1 week, 4 days ago
For archival purposes, forwarding an incoming command email to
linux-kernel@vger.kernel.org.

***

Subject: [PATCH] configfs: unhash dentry before dropping the item
Author: jchuang26@m.fudan.edu.cn

#syz test: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git master

Reported-by: syzbot+9e3014263a35700ab49b@syzkaller.appspotmail.com

diff --git a/drivers/md/md.c b/drivers/md/md.c
index 680b34a63..bcc32b83c 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -1393,7 +1393,11 @@ static int super_90_load(struct md_rdev *rdev, struct md_rdev *refdev, int minor
 		goto abort;
 	}
 
-	if (sb->raid_disks <= 0)
+	/*
+	 * sb->disks[] has only MD_SB_DISKS entries.  A larger raid_disks
+	 * count would later make super_90_sync() index past that array.
+	 */
+	if (sb->raid_disks <= 0 || sb->raid_disks > MD_SB_DISKS)
 		goto abort;
 
 	if (md_csum_fold(calc_sb_csum(sb)) != md_csum_fold(sb->sb_csum)) {
@@ -1607,6 +1611,18 @@ static void super_90_sync(struct mddev *mddev, struct md_rdev *rdev)
 	struct md_rdev *rdev2;
 	int next_spare = mddev->raid_disks;
 
+	/*
+	 * A 0.90 superblock has a fixed-size mdp_disk_t array and uses
+	 * raid_disks as both a loop bound and the first spare disk slot.
+	 * Never index sb->disks[] if an invalid raid_disks value reached
+	 * us through any configuration path.
+	 */
+	if (mddev->raid_disks < 0 || mddev->raid_disks > MD_SB_DISKS) {
+		pr_warn("md: %s: invalid raid_disks %d for 0.90 metadata\n",
+			mdname(mddev), mddev->raid_disks);
+		return;
+	}
+
 	/* make rdev->sb match mddev data..
 	 *
 	 * 1/ zero out disks
@@ -4448,8 +4464,19 @@ raid_disks_store(struct mddev *mddev, const char *buf, size_t len)
 		mddev->delta_disks = n - olddisks;
 		mddev->raid_disks = n;
 		mddev->reshape_backwards = (mddev->delta_disks < 0);
-	} else
-		mddev->raid_disks = n;
+	} else {
+		/*
+		 * 0.90 metadata only has room for MD_SB_DISKS descriptors.
+		 * Larger values would make super_90_sync() index beyond
+		 * sb->disks[].
+		 */
+		if ((mddev->persistent && mddev->major_version == 0 &&
+		     n > MD_SB_DISKS) ||
+		    (mddev->max_disks && n > mddev->max_disks))
+			err = -EINVAL;
+		else
+			mddev->raid_disks = n;
+	}
 out_unlock:
 	memalloc_noio_restore(noio_flags);
 	mddev_unlock_and_resume(mddev);
@@ -7926,6 +7953,18 @@ int md_set_array_info(struct mddev *mddev, struct mdu_array_info_s *info)
 		mddev->ctime         = ktime_get_real_seconds();
 		return 0;
 	}
+
+	/*
+	 * Persistent 0.90 metadata stores disks in sb->disks[MD_SB_DISKS].
+	 * A larger raid_disks count would make super_90_sync() index past
+	 * that array; non-persistent arrays have no such on-disk limit.
+	 */
+	if (info->raid_disks < 0 ||
+	    (!info->not_persistent && info->raid_disks > MD_SB_DISKS)) {
+		pr_warn("md: invalid raid_disks %d\n", info->raid_disks);
+		return -EINVAL;
+	}
+
 	mddev->major_version = MD_MAJOR_VERSION;
 	mddev->minor_version = MD_MINOR_VERSION;
 	mddev->patch_version = MD_PATCHLEVEL_VERSION;