From: Greg Kroah-Hartman Date: Tue, 19 Aug 2025 06:49:49 +0000 (+0200) Subject: drop some md patches X-Git-Tag: v6.12.43~6 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=d72bdd48fba2a8f462a9fa54dbab26595f7995a4;p=thirdparty%2Fkernel%2Fstable-queue.git drop some md patches --- diff --git a/queue-6.12/md-call-del_gendisk-in-control-path.patch b/queue-6.12/md-call-del_gendisk-in-control-path.patch deleted file mode 100644 index 5ed439be1a..0000000000 --- a/queue-6.12/md-call-del_gendisk-in-control-path.patch +++ /dev/null @@ -1,188 +0,0 @@ -From ff0b64256d28c7fe0d141fbd210bef93233a6461 Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Wed, 11 Jun 2025 15:31:06 +0800 -Subject: md: call del_gendisk in control path - -From: Xiao Ni - -[ Upstream commit 9e59d609763f70a992a8f3808dabcce60f14eb5c ] - -Now del_gendisk and put_disk are called asynchronously in workqueue work. -The asynchronous way has a problem that the device node can still exist -after mdadm --stop command returns in a short window. So udev rule can -open this device node and create the struct mddev in kernel again. So put -del_gendisk in control path and still leave put_disk in md_kobj_release -to avoid uaf of gendisk. - -Function del_gendisk can't be called with reconfig_mutex. If it's called -with reconfig mutex, a deadlock can happen. del_gendisk waits all sysfs -files access to finish and sysfs file access waits reconfig mutex. So -put del_gendisk after releasing reconfig mutex. - -But there is still a window that sysfs can be accessed between mddev_unlock -and del_gendisk. So some actions (add disk, change level, .e.g) can happen -which lead unexpected results. MD_DELETED is used to resolve this problem. -MD_DELETED is set before releasing reconfig mutex and it should be checked -for these sysfs access which need reconfig mutex. For sysfs access which -don't need reconfig mutex, del_gendisk will wait them to finish. - -But it doesn't need to do this in function mddev_lock_nointr. There are -ten places that call it. -* Five of them are in dm raid which we don't need to care. MD_DELETED is -only used for md raid. -* stop_sync_thread, md_do_sync and md_start_sync are related sync request, -and it needs to wait sync thread to finish before stopping an array. -* md_ioctl: md_open is called before md_ioctl, so ->openers is added. It -will fail to stop the array. So it doesn't need to check MD_DELETED here -* md_set_readonly: -It needs to call mddev_set_closing_and_sync_blockdev when setting readonly -or read_auto. So it will fail to stop the array too because MD_CLOSING is -already set. - -Reviewed-by: Yu Kuai -Signed-off-by: Xiao Ni -Link: https://lore.kernel.org/linux-raid/20250611073108.25463-2-xni@redhat.com -Signed-off-by: Yu Kuai -Signed-off-by: Sasha Levin ---- - drivers/md/md.c | 33 +++++++++++++++++++++++---------- - drivers/md/md.h | 26 ++++++++++++++++++++++++-- - 2 files changed, 47 insertions(+), 12 deletions(-) - -diff --git a/drivers/md/md.c b/drivers/md/md.c -index 4b3291723670..91cece996250 100644 ---- a/drivers/md/md.c -+++ b/drivers/md/md.c -@@ -619,9 +619,6 @@ static void __mddev_put(struct mddev *mddev) - mddev->ctime || mddev->hold_active) - return; - -- /* Array is not configured at all, and not held active, so destroy it */ -- set_bit(MD_DELETED, &mddev->flags); -- - /* - * Call queue_work inside the spinlock so that flush_workqueue() after - * mddev_find will succeed in waiting for the work to be done. -@@ -856,6 +853,16 @@ void mddev_unlock(struct mddev *mddev) - kobject_del(&rdev->kobj); - export_rdev(rdev, mddev); - } -+ -+ /* Call del_gendisk after release reconfig_mutex to avoid -+ * deadlock (e.g. call del_gendisk under the lock and an -+ * access to sysfs files waits the lock) -+ * And MD_DELETED is only used for md raid which is set in -+ * do_md_stop. dm raid only uses md_stop to stop. So dm raid -+ * doesn't need to check MD_DELETED when getting reconfig lock -+ */ -+ if (test_bit(MD_DELETED, &mddev->flags)) -+ del_gendisk(mddev->gendisk); - } - EXPORT_SYMBOL_GPL(mddev_unlock); - -@@ -5720,19 +5727,30 @@ md_attr_store(struct kobject *kobj, struct attribute *attr, - struct md_sysfs_entry *entry = container_of(attr, struct md_sysfs_entry, attr); - struct mddev *mddev = container_of(kobj, struct mddev, kobj); - ssize_t rv; -+ struct kernfs_node *kn = NULL; - - if (!entry->store) - return -EIO; - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; -+ -+ if (entry->store == array_state_store && cmd_match(page, "clear")) -+ kn = sysfs_break_active_protection(kobj, attr); -+ - spin_lock(&all_mddevs_lock); - if (!mddev_get(mddev)) { - spin_unlock(&all_mddevs_lock); -+ if (kn) -+ sysfs_unbreak_active_protection(kn); - return -EBUSY; - } - spin_unlock(&all_mddevs_lock); - rv = entry->store(mddev, page, length); - mddev_put(mddev); -+ -+ if (kn) -+ sysfs_unbreak_active_protection(kn); -+ - return rv; - } - -@@ -5740,12 +5758,6 @@ static void md_kobj_release(struct kobject *ko) - { - struct mddev *mddev = container_of(ko, struct mddev, kobj); - -- if (mddev->sysfs_state) -- sysfs_put(mddev->sysfs_state); -- if (mddev->sysfs_level) -- sysfs_put(mddev->sysfs_level); -- -- del_gendisk(mddev->gendisk); - put_disk(mddev->gendisk); - } - -@@ -6601,8 +6613,9 @@ static int do_md_stop(struct mddev *mddev, int mode) - mddev->bitmap_info.offset = 0; - - export_array(mddev); -- - md_clean(mddev); -+ set_bit(MD_DELETED, &mddev->flags); -+ - if (mddev->hold_active == UNTIL_STOP) - mddev->hold_active = 0; - } -diff --git a/drivers/md/md.h b/drivers/md/md.h -index 8826dce9717d..cf06a9de6f19 100644 ---- a/drivers/md/md.h -+++ b/drivers/md/md.h -@@ -669,11 +669,26 @@ static inline bool reshape_interrupted(struct mddev *mddev) - - static inline int __must_check mddev_lock(struct mddev *mddev) - { -- return mutex_lock_interruptible(&mddev->reconfig_mutex); -+ int ret; -+ -+ ret = mutex_lock_interruptible(&mddev->reconfig_mutex); -+ -+ /* MD_DELETED is set in do_md_stop with reconfig_mutex. -+ * So check it here. -+ */ -+ if (!ret && test_bit(MD_DELETED, &mddev->flags)) { -+ ret = -ENODEV; -+ mutex_unlock(&mddev->reconfig_mutex); -+ } -+ -+ return ret; - } - - /* Sometimes we need to take the lock in a situation where - * failure due to interrupts is not acceptable. -+ * It doesn't need to check MD_DELETED here, the owner which -+ * holds the lock here can't be stopped. And all paths can't -+ * call this function after do_md_stop. - */ - static inline void mddev_lock_nointr(struct mddev *mddev) - { -@@ -682,7 +697,14 @@ static inline void mddev_lock_nointr(struct mddev *mddev) - - static inline int mddev_trylock(struct mddev *mddev) - { -- return mutex_trylock(&mddev->reconfig_mutex); -+ int ret; -+ -+ ret = mutex_trylock(&mddev->reconfig_mutex); -+ if (!ret && test_bit(MD_DELETED, &mddev->flags)) { -+ ret = -ENODEV; -+ mutex_unlock(&mddev->reconfig_mutex); -+ } -+ return ret; - } - extern void mddev_unlock(struct mddev *mddev); - --- -2.39.5 - diff --git a/queue-6.12/md-don-t-clear-md_closing-until-mddev-is-freed.patch b/queue-6.12/md-don-t-clear-md_closing-until-mddev-is-freed.patch deleted file mode 100644 index fbb03d10e7..0000000000 --- a/queue-6.12/md-don-t-clear-md_closing-until-mddev-is-freed.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 880e342d560e6fd3280ec8a359395bcc2f4e1f04 Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Wed, 11 Jun 2025 15:31:07 +0800 -Subject: md: Don't clear MD_CLOSING until mddev is freed - -From: Xiao Ni - -[ Upstream commit 5f286f33553d600e6c2fb5a23dd6afcf99b3ebac ] - -UNTIL_STOP is used to avoid mddev is freed on the last close before adding -disks to mddev. And it should be cleared when stopping an array which is -mentioned in commit efeb53c0e572 ("md: Allow md devices to be created by -name."). So reset ->hold_active to 0 in md_clean. - -And MD_CLOSING should be kept until mddev is freed to avoid reopen. - -Reviewed-by: Yu Kuai -Signed-off-by: Xiao Ni -Link: https://lore.kernel.org/linux-raid/20250611073108.25463-3-xni@redhat.com -Signed-off-by: Yu Kuai -Signed-off-by: Sasha Levin ---- - drivers/md/md.c | 16 ++++------------ - 1 file changed, 4 insertions(+), 12 deletions(-) - -diff --git a/drivers/md/md.c b/drivers/md/md.c -index 91cece996250..6b5b69a7a3f0 100644 ---- a/drivers/md/md.c -+++ b/drivers/md/md.c -@@ -6380,15 +6380,10 @@ static void md_clean(struct mddev *mddev) - mddev->persistent = 0; - mddev->level = LEVEL_NONE; - mddev->clevel[0] = 0; -- /* -- * Don't clear MD_CLOSING, or mddev can be opened again. -- * 'hold_active != 0' means mddev is still in the creation -- * process and will be used later. -- */ -- if (mddev->hold_active) -- mddev->flags = 0; -- else -- mddev->flags &= BIT_ULL_MASK(MD_CLOSING); -+ /* if UNTIL_STOP is set, it's cleared here */ -+ mddev->hold_active = 0; -+ /* Don't clear MD_CLOSING, or mddev can be opened again. */ -+ mddev->flags &= BIT_ULL_MASK(MD_CLOSING); - mddev->sb_flags = 0; - mddev->ro = MD_RDWR; - mddev->metadata_type[0] = 0; -@@ -6615,9 +6610,6 @@ static int do_md_stop(struct mddev *mddev, int mode) - export_array(mddev); - md_clean(mddev); - set_bit(MD_DELETED, &mddev->flags); -- -- if (mddev->hold_active == UNTIL_STOP) -- mddev->hold_active = 0; - } - md_new_event(); - sysfs_notify_dirent_safe(mddev->sysfs_state); --- -2.39.5 - diff --git a/queue-6.12/md-fix-create-on-open-mddev-lifetime-regression.patch b/queue-6.12/md-fix-create-on-open-mddev-lifetime-regression.patch deleted file mode 100644 index 14ab8500ea..0000000000 --- a/queue-6.12/md-fix-create-on-open-mddev-lifetime-regression.patch +++ /dev/null @@ -1,79 +0,0 @@ -From 1df1fc845d221eb646539836dbf509eb96b41afd Mon Sep 17 00:00:00 2001 -From: Yu Kuai -Date: Wed, 30 Jul 2025 15:33:21 +0800 -Subject: md: fix create on open mddev lifetime regression - -From: Yu Kuai - -commit 1df1fc845d221eb646539836dbf509eb96b41afd upstream. - -Commit 9e59d609763f ("md: call del_gendisk in control path") moves -setting MD_DELETED from __mddev_put() to do_md_stop(), however, for the -case create on open, mddev can be freed without do_md_stop(): - -1) open - -md_probe - md_alloc_and_put - md_alloc - mddev_alloc - atomic_set(&mddev->active, 1); - mddev->hold_active = UNTIL_IOCTL - mddev_put - atomic_dec_and_test(&mddev->active) - if (mddev->hold_active) - -> active is 0, hold_active is set -md_open - mddev_get - atomic_inc(&mddev->active); - -2) ioctl that is not STOP_ARRAY, for example, GET_ARRAY_INFO: - -md_ioctl - mddev->hold_active = 0 - -3) close - -md_release - mddev_put(mddev); - atomic_dec_and_lock(&mddev->active, &all_mddevs_lock) - __mddev_put - -> hold_active is cleared, mddev will be freed - queue_work(md_misc_wq, &mddev->del_work) - -Now that MD_DELETED is not set, before mddev is freed by -mddev_delayed_delete(), md_open can still succeed and break mddev -lifetime, causing mddev->kobj refcount underflow or mddev uaf -problem. - -Fix this problem by setting MD_DELETED before queuing del_work. - -Reported-by: syzbot+9921e319bd6168140b40@syzkaller.appspotmail.com -Closes: https://lore.kernel.org/all/68894408.a00a0220.26d0e1.0012.GAE@google.com/ -Reported-by: syzbot+fa3a12519f0d3fd4ec16@syzkaller.appspotmail.com -Closes: https://lore.kernel.org/all/68894408.a00a0220.26d0e1.0013.GAE@google.com/ -Fixes: 9e59d609763f ("md: call del_gendisk in control path") -Link: https://lore.kernel.org/linux-raid/20250730073321.2583158-1-yukuai1@huaweicloud.com -Signed-off-by: Yu Kuai -Reviewed-by: Paul Menzel -Reviewed-by: Xiao Ni -Signed-off-by: Greg Kroah-Hartman ---- - drivers/md/md.c | 6 ++++++ - 1 file changed, 6 insertions(+) - ---- a/drivers/md/md.c -+++ b/drivers/md/md.c -@@ -620,6 +620,12 @@ static void __mddev_put(struct mddev *md - return; - - /* -+ * If array is freed by stopping array, MD_DELETED is set by -+ * do_md_stop(), MD_DELETED is still set here in case mddev is freed -+ * directly by closing a mddev that is created by create_on_open. -+ */ -+ set_bit(MD_DELETED, &mddev->flags); -+ /* - * Call queue_work inside the spinlock so that flush_workqueue() after - * mddev_find will succeed in waiting for the work to be done. - */ diff --git a/queue-6.12/series b/queue-6.12/series index 047afb62c1..646d12e35a 100644 --- a/queue-6.12/series +++ b/queue-6.12/series @@ -75,7 +75,6 @@ md-raid10-set-chunk_sectors-limit.patch nvme-tcp-log-tls-handshake-failures-at-error-level.patch gfs2-validate-i_depth-for-exhash-directories.patch gfs2-set-.migrate_folio-in-gfs2_-rgrp-meta-_aops.patch -md-call-del_gendisk-in-control-path.patch loop-avoid-updating-block-size-under-exclusive-owner.patch udf-verify-partition-map-count.patch drbd-add-missing-kref_get-in-handle_write_conflicts.patch @@ -86,7 +85,6 @@ ata-ahci-disable-dipm-if-host-lacks-support.patch ata-libata-sata-disallow-changing-lpm-state-if-not-s.patch fs-ntfs3-add-sanity-check-for-file-name.patch fs-ntfs3-correctly-create-symlink-for-relative-path.patch -md-don-t-clear-md_closing-until-mddev-is-freed.patch pidfs-raise-sb_i_nodev-and-sb_i_noexec.patch ext2-handle-fiemap-on-empty-files-to-prevent-einval.patch fix-locking-in-efi_secret_unlink.patch @@ -437,7 +435,6 @@ ata-libata-sata-add-link_power_management_supported-sysfs-attribute.patch io_uring-rw-cast-rw-flags-assignment-to-rwf_t.patch firmware-arm_scmi-convert-to-system_sleep_pm_ops.patch drm-amd-display-allow-dcn301-to-clear-update-flags.patch -md-fix-create-on-open-mddev-lifetime-regression.patch rcu-fix-racy-re-initialization-of-irq_work-causing-hangs.patch dm-split-write-bios-on-zone-boundaries-when-zone-append-is-not-emulated.patch pci-honor-max-link-speed-when-determining-supported-speeds.patch diff --git a/queue-6.15/md-call-del_gendisk-in-control-path.patch b/queue-6.15/md-call-del_gendisk-in-control-path.patch deleted file mode 100644 index e8fbacbc19..0000000000 --- a/queue-6.15/md-call-del_gendisk-in-control-path.patch +++ /dev/null @@ -1,188 +0,0 @@ -From b47c5676ac28d0b0ce7e97be53bba3c761ab7552 Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Wed, 11 Jun 2025 15:31:06 +0800 -Subject: md: call del_gendisk in control path - -From: Xiao Ni - -[ Upstream commit 9e59d609763f70a992a8f3808dabcce60f14eb5c ] - -Now del_gendisk and put_disk are called asynchronously in workqueue work. -The asynchronous way has a problem that the device node can still exist -after mdadm --stop command returns in a short window. So udev rule can -open this device node and create the struct mddev in kernel again. So put -del_gendisk in control path and still leave put_disk in md_kobj_release -to avoid uaf of gendisk. - -Function del_gendisk can't be called with reconfig_mutex. If it's called -with reconfig mutex, a deadlock can happen. del_gendisk waits all sysfs -files access to finish and sysfs file access waits reconfig mutex. So -put del_gendisk after releasing reconfig mutex. - -But there is still a window that sysfs can be accessed between mddev_unlock -and del_gendisk. So some actions (add disk, change level, .e.g) can happen -which lead unexpected results. MD_DELETED is used to resolve this problem. -MD_DELETED is set before releasing reconfig mutex and it should be checked -for these sysfs access which need reconfig mutex. For sysfs access which -don't need reconfig mutex, del_gendisk will wait them to finish. - -But it doesn't need to do this in function mddev_lock_nointr. There are -ten places that call it. -* Five of them are in dm raid which we don't need to care. MD_DELETED is -only used for md raid. -* stop_sync_thread, md_do_sync and md_start_sync are related sync request, -and it needs to wait sync thread to finish before stopping an array. -* md_ioctl: md_open is called before md_ioctl, so ->openers is added. It -will fail to stop the array. So it doesn't need to check MD_DELETED here -* md_set_readonly: -It needs to call mddev_set_closing_and_sync_blockdev when setting readonly -or read_auto. So it will fail to stop the array too because MD_CLOSING is -already set. - -Reviewed-by: Yu Kuai -Signed-off-by: Xiao Ni -Link: https://lore.kernel.org/linux-raid/20250611073108.25463-2-xni@redhat.com -Signed-off-by: Yu Kuai -Signed-off-by: Sasha Levin ---- - drivers/md/md.c | 33 +++++++++++++++++++++++---------- - drivers/md/md.h | 26 ++++++++++++++++++++++++-- - 2 files changed, 47 insertions(+), 12 deletions(-) - -diff --git a/drivers/md/md.c b/drivers/md/md.c -index 47f3253c4757..aa053bb818bc 100644 ---- a/drivers/md/md.c -+++ b/drivers/md/md.c -@@ -613,9 +613,6 @@ static void __mddev_put(struct mddev *mddev) - mddev->ctime || mddev->hold_active) - return; - -- /* Array is not configured at all, and not held active, so destroy it */ -- set_bit(MD_DELETED, &mddev->flags); -- - /* - * Call queue_work inside the spinlock so that flush_workqueue() after - * mddev_find will succeed in waiting for the work to be done. -@@ -850,6 +847,16 @@ void mddev_unlock(struct mddev *mddev) - kobject_del(&rdev->kobj); - export_rdev(rdev, mddev); - } -+ -+ /* Call del_gendisk after release reconfig_mutex to avoid -+ * deadlock (e.g. call del_gendisk under the lock and an -+ * access to sysfs files waits the lock) -+ * And MD_DELETED is only used for md raid which is set in -+ * do_md_stop. dm raid only uses md_stop to stop. So dm raid -+ * doesn't need to check MD_DELETED when getting reconfig lock -+ */ -+ if (test_bit(MD_DELETED, &mddev->flags)) -+ del_gendisk(mddev->gendisk); - } - EXPORT_SYMBOL_GPL(mddev_unlock); - -@@ -5721,19 +5728,30 @@ md_attr_store(struct kobject *kobj, struct attribute *attr, - struct md_sysfs_entry *entry = container_of(attr, struct md_sysfs_entry, attr); - struct mddev *mddev = container_of(kobj, struct mddev, kobj); - ssize_t rv; -+ struct kernfs_node *kn = NULL; - - if (!entry->store) - return -EIO; - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; -+ -+ if (entry->store == array_state_store && cmd_match(page, "clear")) -+ kn = sysfs_break_active_protection(kobj, attr); -+ - spin_lock(&all_mddevs_lock); - if (!mddev_get(mddev)) { - spin_unlock(&all_mddevs_lock); -+ if (kn) -+ sysfs_unbreak_active_protection(kn); - return -EBUSY; - } - spin_unlock(&all_mddevs_lock); - rv = entry->store(mddev, page, length); - mddev_put(mddev); -+ -+ if (kn) -+ sysfs_unbreak_active_protection(kn); -+ - return rv; - } - -@@ -5741,12 +5759,6 @@ static void md_kobj_release(struct kobject *ko) - { - struct mddev *mddev = container_of(ko, struct mddev, kobj); - -- if (mddev->sysfs_state) -- sysfs_put(mddev->sysfs_state); -- if (mddev->sysfs_level) -- sysfs_put(mddev->sysfs_level); -- -- del_gendisk(mddev->gendisk); - put_disk(mddev->gendisk); - } - -@@ -6593,8 +6605,9 @@ static int do_md_stop(struct mddev *mddev, int mode) - mddev->bitmap_info.offset = 0; - - export_array(mddev); -- - md_clean(mddev); -+ set_bit(MD_DELETED, &mddev->flags); -+ - if (mddev->hold_active == UNTIL_STOP) - mddev->hold_active = 0; - } -diff --git a/drivers/md/md.h b/drivers/md/md.h -index 1cf00a04bcdd..b851fc0dc085 100644 ---- a/drivers/md/md.h -+++ b/drivers/md/md.h -@@ -697,11 +697,26 @@ static inline bool reshape_interrupted(struct mddev *mddev) - - static inline int __must_check mddev_lock(struct mddev *mddev) - { -- return mutex_lock_interruptible(&mddev->reconfig_mutex); -+ int ret; -+ -+ ret = mutex_lock_interruptible(&mddev->reconfig_mutex); -+ -+ /* MD_DELETED is set in do_md_stop with reconfig_mutex. -+ * So check it here. -+ */ -+ if (!ret && test_bit(MD_DELETED, &mddev->flags)) { -+ ret = -ENODEV; -+ mutex_unlock(&mddev->reconfig_mutex); -+ } -+ -+ return ret; - } - - /* Sometimes we need to take the lock in a situation where - * failure due to interrupts is not acceptable. -+ * It doesn't need to check MD_DELETED here, the owner which -+ * holds the lock here can't be stopped. And all paths can't -+ * call this function after do_md_stop. - */ - static inline void mddev_lock_nointr(struct mddev *mddev) - { -@@ -710,7 +725,14 @@ static inline void mddev_lock_nointr(struct mddev *mddev) - - static inline int mddev_trylock(struct mddev *mddev) - { -- return mutex_trylock(&mddev->reconfig_mutex); -+ int ret; -+ -+ ret = mutex_trylock(&mddev->reconfig_mutex); -+ if (!ret && test_bit(MD_DELETED, &mddev->flags)) { -+ ret = -ENODEV; -+ mutex_unlock(&mddev->reconfig_mutex); -+ } -+ return ret; - } - extern void mddev_unlock(struct mddev *mddev); - --- -2.39.5 - diff --git a/queue-6.15/md-don-t-clear-md_closing-until-mddev-is-freed.patch b/queue-6.15/md-don-t-clear-md_closing-until-mddev-is-freed.patch deleted file mode 100644 index c52f896ee8..0000000000 --- a/queue-6.15/md-don-t-clear-md_closing-until-mddev-is-freed.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 5f84794f063aaab62d86317011de7cc392c66111 Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Wed, 11 Jun 2025 15:31:07 +0800 -Subject: md: Don't clear MD_CLOSING until mddev is freed - -From: Xiao Ni - -[ Upstream commit 5f286f33553d600e6c2fb5a23dd6afcf99b3ebac ] - -UNTIL_STOP is used to avoid mddev is freed on the last close before adding -disks to mddev. And it should be cleared when stopping an array which is -mentioned in commit efeb53c0e572 ("md: Allow md devices to be created by -name."). So reset ->hold_active to 0 in md_clean. - -And MD_CLOSING should be kept until mddev is freed to avoid reopen. - -Reviewed-by: Yu Kuai -Signed-off-by: Xiao Ni -Link: https://lore.kernel.org/linux-raid/20250611073108.25463-3-xni@redhat.com -Signed-off-by: Yu Kuai -Signed-off-by: Sasha Levin ---- - drivers/md/md.c | 16 ++++------------ - 1 file changed, 4 insertions(+), 12 deletions(-) - -diff --git a/drivers/md/md.c b/drivers/md/md.c -index aa053bb818bc..13a6287e7415 100644 ---- a/drivers/md/md.c -+++ b/drivers/md/md.c -@@ -6372,15 +6372,10 @@ static void md_clean(struct mddev *mddev) - mddev->persistent = 0; - mddev->level = LEVEL_NONE; - mddev->clevel[0] = 0; -- /* -- * Don't clear MD_CLOSING, or mddev can be opened again. -- * 'hold_active != 0' means mddev is still in the creation -- * process and will be used later. -- */ -- if (mddev->hold_active) -- mddev->flags = 0; -- else -- mddev->flags &= BIT_ULL_MASK(MD_CLOSING); -+ /* if UNTIL_STOP is set, it's cleared here */ -+ mddev->hold_active = 0; -+ /* Don't clear MD_CLOSING, or mddev can be opened again. */ -+ mddev->flags &= BIT_ULL_MASK(MD_CLOSING); - mddev->sb_flags = 0; - mddev->ro = MD_RDWR; - mddev->metadata_type[0] = 0; -@@ -6607,9 +6602,6 @@ static int do_md_stop(struct mddev *mddev, int mode) - export_array(mddev); - md_clean(mddev); - set_bit(MD_DELETED, &mddev->flags); -- -- if (mddev->hold_active == UNTIL_STOP) -- mddev->hold_active = 0; - } - md_new_event(); - sysfs_notify_dirent_safe(mddev->sysfs_state); --- -2.39.5 - diff --git a/queue-6.15/md-fix-create-on-open-mddev-lifetime-regression.patch b/queue-6.15/md-fix-create-on-open-mddev-lifetime-regression.patch deleted file mode 100644 index 936540f413..0000000000 --- a/queue-6.15/md-fix-create-on-open-mddev-lifetime-regression.patch +++ /dev/null @@ -1,79 +0,0 @@ -From 1df1fc845d221eb646539836dbf509eb96b41afd Mon Sep 17 00:00:00 2001 -From: Yu Kuai -Date: Wed, 30 Jul 2025 15:33:21 +0800 -Subject: md: fix create on open mddev lifetime regression - -From: Yu Kuai - -commit 1df1fc845d221eb646539836dbf509eb96b41afd upstream. - -Commit 9e59d609763f ("md: call del_gendisk in control path") moves -setting MD_DELETED from __mddev_put() to do_md_stop(), however, for the -case create on open, mddev can be freed without do_md_stop(): - -1) open - -md_probe - md_alloc_and_put - md_alloc - mddev_alloc - atomic_set(&mddev->active, 1); - mddev->hold_active = UNTIL_IOCTL - mddev_put - atomic_dec_and_test(&mddev->active) - if (mddev->hold_active) - -> active is 0, hold_active is set -md_open - mddev_get - atomic_inc(&mddev->active); - -2) ioctl that is not STOP_ARRAY, for example, GET_ARRAY_INFO: - -md_ioctl - mddev->hold_active = 0 - -3) close - -md_release - mddev_put(mddev); - atomic_dec_and_lock(&mddev->active, &all_mddevs_lock) - __mddev_put - -> hold_active is cleared, mddev will be freed - queue_work(md_misc_wq, &mddev->del_work) - -Now that MD_DELETED is not set, before mddev is freed by -mddev_delayed_delete(), md_open can still succeed and break mddev -lifetime, causing mddev->kobj refcount underflow or mddev uaf -problem. - -Fix this problem by setting MD_DELETED before queuing del_work. - -Reported-by: syzbot+9921e319bd6168140b40@syzkaller.appspotmail.com -Closes: https://lore.kernel.org/all/68894408.a00a0220.26d0e1.0012.GAE@google.com/ -Reported-by: syzbot+fa3a12519f0d3fd4ec16@syzkaller.appspotmail.com -Closes: https://lore.kernel.org/all/68894408.a00a0220.26d0e1.0013.GAE@google.com/ -Fixes: 9e59d609763f ("md: call del_gendisk in control path") -Link: https://lore.kernel.org/linux-raid/20250730073321.2583158-1-yukuai1@huaweicloud.com -Signed-off-by: Yu Kuai -Reviewed-by: Paul Menzel -Reviewed-by: Xiao Ni -Signed-off-by: Greg Kroah-Hartman ---- - drivers/md/md.c | 6 ++++++ - 1 file changed, 6 insertions(+) - ---- a/drivers/md/md.c -+++ b/drivers/md/md.c -@@ -614,6 +614,12 @@ static void __mddev_put(struct mddev *md - return; - - /* -+ * If array is freed by stopping array, MD_DELETED is set by -+ * do_md_stop(), MD_DELETED is still set here in case mddev is freed -+ * directly by closing a mddev that is created by create_on_open. -+ */ -+ set_bit(MD_DELETED, &mddev->flags); -+ /* - * Call queue_work inside the spinlock so that flush_workqueue() after - * mddev_find will succeed in waiting for the work to be done. - */ diff --git a/queue-6.15/series b/queue-6.15/series index 5780a34167..916adbf597 100644 --- a/queue-6.15/series +++ b/queue-6.15/series @@ -91,7 +91,6 @@ md-raid10-set-chunk_sectors-limit.patch nvme-tcp-log-tls-handshake-failures-at-error-level.patch gfs2-validate-i_depth-for-exhash-directories.patch gfs2-set-.migrate_folio-in-gfs2_-rgrp-meta-_aops.patch -md-call-del_gendisk-in-control-path.patch loop-avoid-updating-block-size-under-exclusive-owner.patch udf-verify-partition-map-count.patch drbd-add-missing-kref_get-in-handle_write_conflicts.patch @@ -102,7 +101,6 @@ ata-ahci-disable-dipm-if-host-lacks-support.patch ata-libata-sata-disallow-changing-lpm-state-if-not-s.patch fs-ntfs3-add-sanity-check-for-file-name.patch fs-ntfs3-correctly-create-symlink-for-relative-path.patch -md-don-t-clear-md_closing-until-mddev-is-freed.patch pidfs-raise-sb_i_nodev-and-sb_i_noexec.patch landlock-opened-file-never-has-a-negative-dentry.patch ext2-handle-fiemap-on-empty-files-to-prevent-einval.patch @@ -509,6 +507,5 @@ ata-libata-sata-add-link_power_management_supported-sysfs-attribute.patch io_uring-rw-cast-rw-flags-assignment-to-rwf_t.patch firmware-arm_scmi-convert-to-system_sleep_pm_ops.patch drm-amd-display-allow-dcn301-to-clear-update-flags.patch -md-fix-create-on-open-mddev-lifetime-regression.patch rcu-fix-racy-re-initialization-of-irq_work-causing-hangs.patch dm-split-write-bios-on-zone-boundaries-when-zone-append-is-not-emulated.patch diff --git a/queue-6.16/md-call-del_gendisk-in-control-path.patch b/queue-6.16/md-call-del_gendisk-in-control-path.patch deleted file mode 100644 index db436776b9..0000000000 --- a/queue-6.16/md-call-del_gendisk-in-control-path.patch +++ /dev/null @@ -1,188 +0,0 @@ -From bbd219cd5c5f8380c07ab02a591bd0c557d43c86 Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Wed, 11 Jun 2025 15:31:06 +0800 -Subject: md: call del_gendisk in control path - -From: Xiao Ni - -[ Upstream commit 9e59d609763f70a992a8f3808dabcce60f14eb5c ] - -Now del_gendisk and put_disk are called asynchronously in workqueue work. -The asynchronous way has a problem that the device node can still exist -after mdadm --stop command returns in a short window. So udev rule can -open this device node and create the struct mddev in kernel again. So put -del_gendisk in control path and still leave put_disk in md_kobj_release -to avoid uaf of gendisk. - -Function del_gendisk can't be called with reconfig_mutex. If it's called -with reconfig mutex, a deadlock can happen. del_gendisk waits all sysfs -files access to finish and sysfs file access waits reconfig mutex. So -put del_gendisk after releasing reconfig mutex. - -But there is still a window that sysfs can be accessed between mddev_unlock -and del_gendisk. So some actions (add disk, change level, .e.g) can happen -which lead unexpected results. MD_DELETED is used to resolve this problem. -MD_DELETED is set before releasing reconfig mutex and it should be checked -for these sysfs access which need reconfig mutex. For sysfs access which -don't need reconfig mutex, del_gendisk will wait them to finish. - -But it doesn't need to do this in function mddev_lock_nointr. There are -ten places that call it. -* Five of them are in dm raid which we don't need to care. MD_DELETED is -only used for md raid. -* stop_sync_thread, md_do_sync and md_start_sync are related sync request, -and it needs to wait sync thread to finish before stopping an array. -* md_ioctl: md_open is called before md_ioctl, so ->openers is added. It -will fail to stop the array. So it doesn't need to check MD_DELETED here -* md_set_readonly: -It needs to call mddev_set_closing_and_sync_blockdev when setting readonly -or read_auto. So it will fail to stop the array too because MD_CLOSING is -already set. - -Reviewed-by: Yu Kuai -Signed-off-by: Xiao Ni -Link: https://lore.kernel.org/linux-raid/20250611073108.25463-2-xni@redhat.com -Signed-off-by: Yu Kuai -Signed-off-by: Sasha Levin ---- - drivers/md/md.c | 33 +++++++++++++++++++++++---------- - drivers/md/md.h | 26 ++++++++++++++++++++++++-- - 2 files changed, 47 insertions(+), 12 deletions(-) - -diff --git a/drivers/md/md.c b/drivers/md/md.c -index 10670c62b09e..c16c7feb6034 100644 ---- a/drivers/md/md.c -+++ b/drivers/md/md.c -@@ -636,9 +636,6 @@ static void __mddev_put(struct mddev *mddev) - mddev->ctime || mddev->hold_active) - return; - -- /* Array is not configured at all, and not held active, so destroy it */ -- set_bit(MD_DELETED, &mddev->flags); -- - /* - * Call queue_work inside the spinlock so that flush_workqueue() after - * mddev_find will succeed in waiting for the work to be done. -@@ -873,6 +870,16 @@ void mddev_unlock(struct mddev *mddev) - kobject_del(&rdev->kobj); - export_rdev(rdev, mddev); - } -+ -+ /* Call del_gendisk after release reconfig_mutex to avoid -+ * deadlock (e.g. call del_gendisk under the lock and an -+ * access to sysfs files waits the lock) -+ * And MD_DELETED is only used for md raid which is set in -+ * do_md_stop. dm raid only uses md_stop to stop. So dm raid -+ * doesn't need to check MD_DELETED when getting reconfig lock -+ */ -+ if (test_bit(MD_DELETED, &mddev->flags)) -+ del_gendisk(mddev->gendisk); - } - EXPORT_SYMBOL_GPL(mddev_unlock); - -@@ -5774,19 +5781,30 @@ md_attr_store(struct kobject *kobj, struct attribute *attr, - struct md_sysfs_entry *entry = container_of(attr, struct md_sysfs_entry, attr); - struct mddev *mddev = container_of(kobj, struct mddev, kobj); - ssize_t rv; -+ struct kernfs_node *kn = NULL; - - if (!entry->store) - return -EIO; - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; -+ -+ if (entry->store == array_state_store && cmd_match(page, "clear")) -+ kn = sysfs_break_active_protection(kobj, attr); -+ - spin_lock(&all_mddevs_lock); - if (!mddev_get(mddev)) { - spin_unlock(&all_mddevs_lock); -+ if (kn) -+ sysfs_unbreak_active_protection(kn); - return -EBUSY; - } - spin_unlock(&all_mddevs_lock); - rv = entry->store(mddev, page, length); - mddev_put(mddev); -+ -+ if (kn) -+ sysfs_unbreak_active_protection(kn); -+ - return rv; - } - -@@ -5794,12 +5812,6 @@ static void md_kobj_release(struct kobject *ko) - { - struct mddev *mddev = container_of(ko, struct mddev, kobj); - -- if (mddev->sysfs_state) -- sysfs_put(mddev->sysfs_state); -- if (mddev->sysfs_level) -- sysfs_put(mddev->sysfs_level); -- -- del_gendisk(mddev->gendisk); - put_disk(mddev->gendisk); - } - -@@ -6646,8 +6658,9 @@ static int do_md_stop(struct mddev *mddev, int mode) - mddev->bitmap_info.offset = 0; - - export_array(mddev); -- - md_clean(mddev); -+ set_bit(MD_DELETED, &mddev->flags); -+ - if (mddev->hold_active == UNTIL_STOP) - mddev->hold_active = 0; - } -diff --git a/drivers/md/md.h b/drivers/md/md.h -index d45a9e6ead80..67b365621507 100644 ---- a/drivers/md/md.h -+++ b/drivers/md/md.h -@@ -700,11 +700,26 @@ static inline bool reshape_interrupted(struct mddev *mddev) - - static inline int __must_check mddev_lock(struct mddev *mddev) - { -- return mutex_lock_interruptible(&mddev->reconfig_mutex); -+ int ret; -+ -+ ret = mutex_lock_interruptible(&mddev->reconfig_mutex); -+ -+ /* MD_DELETED is set in do_md_stop with reconfig_mutex. -+ * So check it here. -+ */ -+ if (!ret && test_bit(MD_DELETED, &mddev->flags)) { -+ ret = -ENODEV; -+ mutex_unlock(&mddev->reconfig_mutex); -+ } -+ -+ return ret; - } - - /* Sometimes we need to take the lock in a situation where - * failure due to interrupts is not acceptable. -+ * It doesn't need to check MD_DELETED here, the owner which -+ * holds the lock here can't be stopped. And all paths can't -+ * call this function after do_md_stop. - */ - static inline void mddev_lock_nointr(struct mddev *mddev) - { -@@ -713,7 +728,14 @@ static inline void mddev_lock_nointr(struct mddev *mddev) - - static inline int mddev_trylock(struct mddev *mddev) - { -- return mutex_trylock(&mddev->reconfig_mutex); -+ int ret; -+ -+ ret = mutex_trylock(&mddev->reconfig_mutex); -+ if (!ret && test_bit(MD_DELETED, &mddev->flags)) { -+ ret = -ENODEV; -+ mutex_unlock(&mddev->reconfig_mutex); -+ } -+ return ret; - } - extern void mddev_unlock(struct mddev *mddev); - --- -2.39.5 - diff --git a/queue-6.16/md-don-t-clear-md_closing-until-mddev-is-freed.patch b/queue-6.16/md-don-t-clear-md_closing-until-mddev-is-freed.patch deleted file mode 100644 index 073d159968..0000000000 --- a/queue-6.16/md-don-t-clear-md_closing-until-mddev-is-freed.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 2c6366ab6d14425f251da6bccb6f1dde7ed2459a Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Wed, 11 Jun 2025 15:31:07 +0800 -Subject: md: Don't clear MD_CLOSING until mddev is freed - -From: Xiao Ni - -[ Upstream commit 5f286f33553d600e6c2fb5a23dd6afcf99b3ebac ] - -UNTIL_STOP is used to avoid mddev is freed on the last close before adding -disks to mddev. And it should be cleared when stopping an array which is -mentioned in commit efeb53c0e572 ("md: Allow md devices to be created by -name."). So reset ->hold_active to 0 in md_clean. - -And MD_CLOSING should be kept until mddev is freed to avoid reopen. - -Reviewed-by: Yu Kuai -Signed-off-by: Xiao Ni -Link: https://lore.kernel.org/linux-raid/20250611073108.25463-3-xni@redhat.com -Signed-off-by: Yu Kuai -Signed-off-by: Sasha Levin ---- - drivers/md/md.c | 16 ++++------------ - 1 file changed, 4 insertions(+), 12 deletions(-) - -diff --git a/drivers/md/md.c b/drivers/md/md.c -index c16c7feb6034..81d786a3851b 100644 ---- a/drivers/md/md.c -+++ b/drivers/md/md.c -@@ -6425,15 +6425,10 @@ static void md_clean(struct mddev *mddev) - mddev->persistent = 0; - mddev->level = LEVEL_NONE; - mddev->clevel[0] = 0; -- /* -- * Don't clear MD_CLOSING, or mddev can be opened again. -- * 'hold_active != 0' means mddev is still in the creation -- * process and will be used later. -- */ -- if (mddev->hold_active) -- mddev->flags = 0; -- else -- mddev->flags &= BIT_ULL_MASK(MD_CLOSING); -+ /* if UNTIL_STOP is set, it's cleared here */ -+ mddev->hold_active = 0; -+ /* Don't clear MD_CLOSING, or mddev can be opened again. */ -+ mddev->flags &= BIT_ULL_MASK(MD_CLOSING); - mddev->sb_flags = 0; - mddev->ro = MD_RDWR; - mddev->metadata_type[0] = 0; -@@ -6660,9 +6655,6 @@ static int do_md_stop(struct mddev *mddev, int mode) - export_array(mddev); - md_clean(mddev); - set_bit(MD_DELETED, &mddev->flags); -- -- if (mddev->hold_active == UNTIL_STOP) -- mddev->hold_active = 0; - } - md_new_event(); - sysfs_notify_dirent_safe(mddev->sysfs_state); --- -2.39.5 - diff --git a/queue-6.16/md-fix-create-on-open-mddev-lifetime-regression.patch b/queue-6.16/md-fix-create-on-open-mddev-lifetime-regression.patch deleted file mode 100644 index eb499b46c9..0000000000 --- a/queue-6.16/md-fix-create-on-open-mddev-lifetime-regression.patch +++ /dev/null @@ -1,79 +0,0 @@ -From 1df1fc845d221eb646539836dbf509eb96b41afd Mon Sep 17 00:00:00 2001 -From: Yu Kuai -Date: Wed, 30 Jul 2025 15:33:21 +0800 -Subject: md: fix create on open mddev lifetime regression - -From: Yu Kuai - -commit 1df1fc845d221eb646539836dbf509eb96b41afd upstream. - -Commit 9e59d609763f ("md: call del_gendisk in control path") moves -setting MD_DELETED from __mddev_put() to do_md_stop(), however, for the -case create on open, mddev can be freed without do_md_stop(): - -1) open - -md_probe - md_alloc_and_put - md_alloc - mddev_alloc - atomic_set(&mddev->active, 1); - mddev->hold_active = UNTIL_IOCTL - mddev_put - atomic_dec_and_test(&mddev->active) - if (mddev->hold_active) - -> active is 0, hold_active is set -md_open - mddev_get - atomic_inc(&mddev->active); - -2) ioctl that is not STOP_ARRAY, for example, GET_ARRAY_INFO: - -md_ioctl - mddev->hold_active = 0 - -3) close - -md_release - mddev_put(mddev); - atomic_dec_and_lock(&mddev->active, &all_mddevs_lock) - __mddev_put - -> hold_active is cleared, mddev will be freed - queue_work(md_misc_wq, &mddev->del_work) - -Now that MD_DELETED is not set, before mddev is freed by -mddev_delayed_delete(), md_open can still succeed and break mddev -lifetime, causing mddev->kobj refcount underflow or mddev uaf -problem. - -Fix this problem by setting MD_DELETED before queuing del_work. - -Reported-by: syzbot+9921e319bd6168140b40@syzkaller.appspotmail.com -Closes: https://lore.kernel.org/all/68894408.a00a0220.26d0e1.0012.GAE@google.com/ -Reported-by: syzbot+fa3a12519f0d3fd4ec16@syzkaller.appspotmail.com -Closes: https://lore.kernel.org/all/68894408.a00a0220.26d0e1.0013.GAE@google.com/ -Fixes: 9e59d609763f ("md: call del_gendisk in control path") -Link: https://lore.kernel.org/linux-raid/20250730073321.2583158-1-yukuai1@huaweicloud.com -Signed-off-by: Yu Kuai -Reviewed-by: Paul Menzel -Reviewed-by: Xiao Ni -Signed-off-by: Greg Kroah-Hartman ---- - drivers/md/md.c | 6 ++++++ - 1 file changed, 6 insertions(+) - ---- a/drivers/md/md.c -+++ b/drivers/md/md.c -@@ -637,6 +637,12 @@ static void __mddev_put(struct mddev *md - return; - - /* -+ * If array is freed by stopping array, MD_DELETED is set by -+ * do_md_stop(), MD_DELETED is still set here in case mddev is freed -+ * directly by closing a mddev that is created by create_on_open. -+ */ -+ set_bit(MD_DELETED, &mddev->flags); -+ /* - * Call queue_work inside the spinlock so that flush_workqueue() after - * mddev_find will succeed in waiting for the work to be done. - */ diff --git a/queue-6.16/series b/queue-6.16/series index 5e3e991ac4..b0ee6fe052 100644 --- a/queue-6.16/series +++ b/queue-6.16/series @@ -103,7 +103,6 @@ md-raid10-set-chunk_sectors-limit.patch nvme-tcp-log-tls-handshake-failures-at-error-level.patch gfs2-validate-i_depth-for-exhash-directories.patch gfs2-set-.migrate_folio-in-gfs2_-rgrp-meta-_aops.patch -md-call-del_gendisk-in-control-path.patch loop-avoid-updating-block-size-under-exclusive-owner.patch udf-verify-partition-map-count.patch drbd-add-missing-kref_get-in-handle_write_conflicts.patch @@ -114,7 +113,6 @@ ata-ahci-disable-dipm-if-host-lacks-support.patch ata-libata-sata-disallow-changing-lpm-state-if-not-s.patch fs-ntfs3-add-sanity-check-for-file-name.patch fs-ntfs3-correctly-create-symlink-for-relative-path.patch -md-don-t-clear-md_closing-until-mddev-is-freed.patch pidfs-raise-sb_i_nodev-and-sb_i_noexec.patch landlock-opened-file-never-has-a-negative-dentry.patch ext2-handle-fiemap-on-empty-files-to-prevent-einval.patch @@ -561,7 +559,6 @@ ata-libata-sata-add-link_power_management_supported-sysfs-attribute.patch io_uring-rw-cast-rw-flags-assignment-to-rwf_t.patch firmware-arm_scmi-convert-to-system_sleep_pm_ops.patch drm-amd-display-allow-dcn301-to-clear-update-flags.patch -md-fix-create-on-open-mddev-lifetime-regression.patch rcu-fix-racy-re-initialization-of-irq_work-causing-hangs.patch irqchip-mvebu-gicp-use-resource_size-for-ioremap.patch dm-split-write-bios-on-zone-boundaries-when-zone-append-is-not-emulated.patch diff --git a/queue-6.6/md-call-del_gendisk-in-control-path.patch b/queue-6.6/md-call-del_gendisk-in-control-path.patch deleted file mode 100644 index 2ed17b8aaf..0000000000 --- a/queue-6.6/md-call-del_gendisk-in-control-path.patch +++ /dev/null @@ -1,188 +0,0 @@ -From fa738623105e2dd4865274dc8525856feaec3ae9 Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Wed, 11 Jun 2025 15:31:06 +0800 -Subject: md: call del_gendisk in control path - -From: Xiao Ni - -[ Upstream commit 9e59d609763f70a992a8f3808dabcce60f14eb5c ] - -Now del_gendisk and put_disk are called asynchronously in workqueue work. -The asynchronous way has a problem that the device node can still exist -after mdadm --stop command returns in a short window. So udev rule can -open this device node and create the struct mddev in kernel again. So put -del_gendisk in control path and still leave put_disk in md_kobj_release -to avoid uaf of gendisk. - -Function del_gendisk can't be called with reconfig_mutex. If it's called -with reconfig mutex, a deadlock can happen. del_gendisk waits all sysfs -files access to finish and sysfs file access waits reconfig mutex. So -put del_gendisk after releasing reconfig mutex. - -But there is still a window that sysfs can be accessed between mddev_unlock -and del_gendisk. So some actions (add disk, change level, .e.g) can happen -which lead unexpected results. MD_DELETED is used to resolve this problem. -MD_DELETED is set before releasing reconfig mutex and it should be checked -for these sysfs access which need reconfig mutex. For sysfs access which -don't need reconfig mutex, del_gendisk will wait them to finish. - -But it doesn't need to do this in function mddev_lock_nointr. There are -ten places that call it. -* Five of them are in dm raid which we don't need to care. MD_DELETED is -only used for md raid. -* stop_sync_thread, md_do_sync and md_start_sync are related sync request, -and it needs to wait sync thread to finish before stopping an array. -* md_ioctl: md_open is called before md_ioctl, so ->openers is added. It -will fail to stop the array. So it doesn't need to check MD_DELETED here -* md_set_readonly: -It needs to call mddev_set_closing_and_sync_blockdev when setting readonly -or read_auto. So it will fail to stop the array too because MD_CLOSING is -already set. - -Reviewed-by: Yu Kuai -Signed-off-by: Xiao Ni -Link: https://lore.kernel.org/linux-raid/20250611073108.25463-2-xni@redhat.com -Signed-off-by: Yu Kuai -Signed-off-by: Sasha Levin ---- - drivers/md/md.c | 33 +++++++++++++++++++++++---------- - drivers/md/md.h | 26 ++++++++++++++++++++++++-- - 2 files changed, 47 insertions(+), 12 deletions(-) - -diff --git a/drivers/md/md.c b/drivers/md/md.c -index b086cbf24086..8e3939c0d2ed 100644 ---- a/drivers/md/md.c -+++ b/drivers/md/md.c -@@ -639,9 +639,6 @@ static void __mddev_put(struct mddev *mddev) - mddev->ctime || mddev->hold_active) - return; - -- /* Array is not configured at all, and not held active, so destroy it */ -- set_bit(MD_DELETED, &mddev->flags); -- - /* - * Call queue_work inside the spinlock so that flush_workqueue() after - * mddev_find will succeed in waiting for the work to be done. -@@ -837,6 +834,16 @@ void mddev_unlock(struct mddev *mddev) - kobject_del(&rdev->kobj); - export_rdev(rdev, mddev); - } -+ -+ /* Call del_gendisk after release reconfig_mutex to avoid -+ * deadlock (e.g. call del_gendisk under the lock and an -+ * access to sysfs files waits the lock) -+ * And MD_DELETED is only used for md raid which is set in -+ * do_md_stop. dm raid only uses md_stop to stop. So dm raid -+ * doesn't need to check MD_DELETED when getting reconfig lock -+ */ -+ if (test_bit(MD_DELETED, &mddev->flags)) -+ del_gendisk(mddev->gendisk); - } - EXPORT_SYMBOL_GPL(mddev_unlock); - -@@ -5616,19 +5623,30 @@ md_attr_store(struct kobject *kobj, struct attribute *attr, - struct md_sysfs_entry *entry = container_of(attr, struct md_sysfs_entry, attr); - struct mddev *mddev = container_of(kobj, struct mddev, kobj); - ssize_t rv; -+ struct kernfs_node *kn = NULL; - - if (!entry->store) - return -EIO; - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; -+ -+ if (entry->store == array_state_store && cmd_match(page, "clear")) -+ kn = sysfs_break_active_protection(kobj, attr); -+ - spin_lock(&all_mddevs_lock); - if (!mddev_get(mddev)) { - spin_unlock(&all_mddevs_lock); -+ if (kn) -+ sysfs_unbreak_active_protection(kn); - return -EBUSY; - } - spin_unlock(&all_mddevs_lock); - rv = entry->store(mddev, page, length); - mddev_put(mddev); -+ -+ if (kn) -+ sysfs_unbreak_active_protection(kn); -+ - return rv; - } - -@@ -5636,12 +5654,6 @@ static void md_kobj_release(struct kobject *ko) - { - struct mddev *mddev = container_of(ko, struct mddev, kobj); - -- if (mddev->sysfs_state) -- sysfs_put(mddev->sysfs_state); -- if (mddev->sysfs_level) -- sysfs_put(mddev->sysfs_level); -- -- del_gendisk(mddev->gendisk); - put_disk(mddev->gendisk); - } - -@@ -6531,8 +6543,9 @@ static int do_md_stop(struct mddev *mddev, int mode, - mddev->bitmap_info.offset = 0; - - export_array(mddev); -- - md_clean(mddev); -+ set_bit(MD_DELETED, &mddev->flags); -+ - if (mddev->hold_active == UNTIL_STOP) - mddev->hold_active = 0; - } -diff --git a/drivers/md/md.h b/drivers/md/md.h -index 46995558d3bd..0a7c9122db50 100644 ---- a/drivers/md/md.h -+++ b/drivers/md/md.h -@@ -589,11 +589,26 @@ static inline bool is_md_suspended(struct mddev *mddev) - - static inline int __must_check mddev_lock(struct mddev *mddev) - { -- return mutex_lock_interruptible(&mddev->reconfig_mutex); -+ int ret; -+ -+ ret = mutex_lock_interruptible(&mddev->reconfig_mutex); -+ -+ /* MD_DELETED is set in do_md_stop with reconfig_mutex. -+ * So check it here. -+ */ -+ if (!ret && test_bit(MD_DELETED, &mddev->flags)) { -+ ret = -ENODEV; -+ mutex_unlock(&mddev->reconfig_mutex); -+ } -+ -+ return ret; - } - - /* Sometimes we need to take the lock in a situation where - * failure due to interrupts is not acceptable. -+ * It doesn't need to check MD_DELETED here, the owner which -+ * holds the lock here can't be stopped. And all paths can't -+ * call this function after do_md_stop. - */ - static inline void mddev_lock_nointr(struct mddev *mddev) - { -@@ -602,7 +617,14 @@ static inline void mddev_lock_nointr(struct mddev *mddev) - - static inline int mddev_trylock(struct mddev *mddev) - { -- return mutex_trylock(&mddev->reconfig_mutex); -+ int ret; -+ -+ ret = mutex_trylock(&mddev->reconfig_mutex); -+ if (!ret && test_bit(MD_DELETED, &mddev->flags)) { -+ ret = -ENODEV; -+ mutex_unlock(&mddev->reconfig_mutex); -+ } -+ return ret; - } - extern void mddev_unlock(struct mddev *mddev); - --- -2.39.5 - diff --git a/queue-6.6/md-don-t-clear-md_closing-until-mddev-is-freed.patch b/queue-6.6/md-don-t-clear-md_closing-until-mddev-is-freed.patch deleted file mode 100644 index e14b19a2df..0000000000 --- a/queue-6.6/md-don-t-clear-md_closing-until-mddev-is-freed.patch +++ /dev/null @@ -1,62 +0,0 @@ -From c365a20552d7d7a9eb03cbefd91176c004e24340 Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Wed, 11 Jun 2025 15:31:07 +0800 -Subject: md: Don't clear MD_CLOSING until mddev is freed - -From: Xiao Ni - -[ Upstream commit 5f286f33553d600e6c2fb5a23dd6afcf99b3ebac ] - -UNTIL_STOP is used to avoid mddev is freed on the last close before adding -disks to mddev. And it should be cleared when stopping an array which is -mentioned in commit efeb53c0e572 ("md: Allow md devices to be created by -name."). So reset ->hold_active to 0 in md_clean. - -And MD_CLOSING should be kept until mddev is freed to avoid reopen. - -Reviewed-by: Yu Kuai -Signed-off-by: Xiao Ni -Link: https://lore.kernel.org/linux-raid/20250611073108.25463-3-xni@redhat.com -Signed-off-by: Yu Kuai -Signed-off-by: Sasha Levin ---- - drivers/md/md.c | 16 ++++------------ - 1 file changed, 4 insertions(+), 12 deletions(-) - -diff --git a/drivers/md/md.c b/drivers/md/md.c -index 8e3939c0d2ed..6a3b5b131111 100644 ---- a/drivers/md/md.c -+++ b/drivers/md/md.c -@@ -6265,15 +6265,10 @@ static void md_clean(struct mddev *mddev) - mddev->persistent = 0; - mddev->level = LEVEL_NONE; - mddev->clevel[0] = 0; -- /* -- * Don't clear MD_CLOSING, or mddev can be opened again. -- * 'hold_active != 0' means mddev is still in the creation -- * process and will be used later. -- */ -- if (mddev->hold_active) -- mddev->flags = 0; -- else -- mddev->flags &= BIT_ULL_MASK(MD_CLOSING); -+ /* if UNTIL_STOP is set, it's cleared here */ -+ mddev->hold_active = 0; -+ /* Don't clear MD_CLOSING, or mddev can be opened again. */ -+ mddev->flags &= BIT_ULL_MASK(MD_CLOSING); - mddev->sb_flags = 0; - mddev->ro = MD_RDWR; - mddev->metadata_type[0] = 0; -@@ -6545,9 +6540,6 @@ static int do_md_stop(struct mddev *mddev, int mode, - export_array(mddev); - md_clean(mddev); - set_bit(MD_DELETED, &mddev->flags); -- -- if (mddev->hold_active == UNTIL_STOP) -- mddev->hold_active = 0; - } - md_new_event(); - sysfs_notify_dirent_safe(mddev->sysfs_state); --- -2.39.5 - diff --git a/queue-6.6/md-fix-create-on-open-mddev-lifetime-regression.patch b/queue-6.6/md-fix-create-on-open-mddev-lifetime-regression.patch deleted file mode 100644 index fc2bb441aa..0000000000 --- a/queue-6.6/md-fix-create-on-open-mddev-lifetime-regression.patch +++ /dev/null @@ -1,79 +0,0 @@ -From 1df1fc845d221eb646539836dbf509eb96b41afd Mon Sep 17 00:00:00 2001 -From: Yu Kuai -Date: Wed, 30 Jul 2025 15:33:21 +0800 -Subject: md: fix create on open mddev lifetime regression - -From: Yu Kuai - -commit 1df1fc845d221eb646539836dbf509eb96b41afd upstream. - -Commit 9e59d609763f ("md: call del_gendisk in control path") moves -setting MD_DELETED from __mddev_put() to do_md_stop(), however, for the -case create on open, mddev can be freed without do_md_stop(): - -1) open - -md_probe - md_alloc_and_put - md_alloc - mddev_alloc - atomic_set(&mddev->active, 1); - mddev->hold_active = UNTIL_IOCTL - mddev_put - atomic_dec_and_test(&mddev->active) - if (mddev->hold_active) - -> active is 0, hold_active is set -md_open - mddev_get - atomic_inc(&mddev->active); - -2) ioctl that is not STOP_ARRAY, for example, GET_ARRAY_INFO: - -md_ioctl - mddev->hold_active = 0 - -3) close - -md_release - mddev_put(mddev); - atomic_dec_and_lock(&mddev->active, &all_mddevs_lock) - __mddev_put - -> hold_active is cleared, mddev will be freed - queue_work(md_misc_wq, &mddev->del_work) - -Now that MD_DELETED is not set, before mddev is freed by -mddev_delayed_delete(), md_open can still succeed and break mddev -lifetime, causing mddev->kobj refcount underflow or mddev uaf -problem. - -Fix this problem by setting MD_DELETED before queuing del_work. - -Reported-by: syzbot+9921e319bd6168140b40@syzkaller.appspotmail.com -Closes: https://lore.kernel.org/all/68894408.a00a0220.26d0e1.0012.GAE@google.com/ -Reported-by: syzbot+fa3a12519f0d3fd4ec16@syzkaller.appspotmail.com -Closes: https://lore.kernel.org/all/68894408.a00a0220.26d0e1.0013.GAE@google.com/ -Fixes: 9e59d609763f ("md: call del_gendisk in control path") -Link: https://lore.kernel.org/linux-raid/20250730073321.2583158-1-yukuai1@huaweicloud.com -Signed-off-by: Yu Kuai -Reviewed-by: Paul Menzel -Reviewed-by: Xiao Ni -Signed-off-by: Greg Kroah-Hartman ---- - drivers/md/md.c | 6 ++++++ - 1 file changed, 6 insertions(+) - ---- a/drivers/md/md.c -+++ b/drivers/md/md.c -@@ -640,6 +640,12 @@ static void __mddev_put(struct mddev *md - return; - - /* -+ * If array is freed by stopping array, MD_DELETED is set by -+ * do_md_stop(), MD_DELETED is still set here in case mddev is freed -+ * directly by closing a mddev that is created by create_on_open. -+ */ -+ set_bit(MD_DELETED, &mddev->flags); -+ /* - * Call queue_work inside the spinlock so that flush_workqueue() after - * mddev_find will succeed in waiting for the work to be done. - */ diff --git a/queue-6.6/series b/queue-6.6/series index b4f04d03e9..e96ee69f3d 100644 --- a/queue-6.6/series +++ b/queue-6.6/series @@ -68,7 +68,6 @@ arm64-handle-kcov-__init-vs-inline-mismatches.patch smb-server-avoid-deadlock-when-linking-with-replacei.patch nvme-pci-try-function-level-reset-on-init-failure.patch gfs2-set-.migrate_folio-in-gfs2_-rgrp-meta-_aops.patch -md-call-del_gendisk-in-control-path.patch loop-avoid-updating-block-size-under-exclusive-owner.patch udf-verify-partition-map-count.patch drbd-add-missing-kref_get-in-handle_write_conflicts.patch @@ -77,7 +76,6 @@ better-lockdep-annotations-for-simple_recursive_remo.patch ata-libata-sata-disallow-changing-lpm-state-if-not-s.patch fs-ntfs3-add-sanity-check-for-file-name.patch fs-ntfs3-correctly-create-symlink-for-relative-path.patch -md-don-t-clear-md_closing-until-mddev-is-freed.patch ext2-handle-fiemap-on-empty-files-to-prevent-einval.patch fix-locking-in-efi_secret_unlink.patch securityfs-don-t-pin-dentries-twice-once-is-enough.patch @@ -329,5 +327,4 @@ tools-nolibc-fix-spelling-of-fd_setbitmask-in-fd_-macros.patch rdma-siw-fix-the-sendmsg-byte-count-in-siw_tcp_sendpages.patch hid-magicmouse-avoid-setting-up-battery-timer-when-not-needed.patch hid-apple-avoid-setting-up-battery-timer-for-devices-without-battery.patch -md-fix-create-on-open-mddev-lifetime-regression.patch rcu-fix-racy-re-initialization-of-irq_work-causing-hangs.patch