]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
6.6-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 18 Aug 2025 12:15:35 +0000 (14:15 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 18 Aug 2025 12:15:35 +0000 (14:15 +0200)
added patches:
md-fix-create-on-open-mddev-lifetime-regression.patch
rcu-fix-racy-re-initialization-of-irq_work-causing-hangs.patch

queue-6.6/md-fix-create-on-open-mddev-lifetime-regression.patch [new file with mode: 0644]
queue-6.6/rcu-fix-racy-re-initialization-of-irq_work-causing-hangs.patch [new file with mode: 0644]
queue-6.6/series

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
new file mode 100644 (file)
index 0000000..fc2bb44
--- /dev/null
@@ -0,0 +1,79 @@
+From 1df1fc845d221eb646539836dbf509eb96b41afd Mon Sep 17 00:00:00 2001
+From: Yu Kuai <yukuai3@huawei.com>
+Date: Wed, 30 Jul 2025 15:33:21 +0800
+Subject: md: fix create on open mddev lifetime regression
+
+From: Yu Kuai <yukuai3@huawei.com>
+
+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 <yukuai3@huawei.com>
+Reviewed-by: Paul Menzel <pmenzel@molgen.mpg.de>
+Reviewed-by: Xiao Ni <xni@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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/rcu-fix-racy-re-initialization-of-irq_work-causing-hangs.patch b/queue-6.6/rcu-fix-racy-re-initialization-of-irq_work-causing-hangs.patch
new file mode 100644 (file)
index 0000000..9bd2d7d
--- /dev/null
@@ -0,0 +1,104 @@
+From 61399e0c5410567ef60cb1cda34cca42903842e3 Mon Sep 17 00:00:00 2001
+From: Frederic Weisbecker <frederic@kernel.org>
+Date: Fri, 8 Aug 2025 19:03:22 +0200
+Subject: rcu: Fix racy re-initialization of irq_work causing hangs
+
+From: Frederic Weisbecker <frederic@kernel.org>
+
+commit 61399e0c5410567ef60cb1cda34cca42903842e3 upstream.
+
+RCU re-initializes the deferred QS irq work everytime before attempting
+to queue it. However there are situations where the irq work is
+attempted to be queued even though it is already queued. In that case
+re-initializing messes-up with the irq work queue that is about to be
+handled.
+
+The chances for that to happen are higher when the architecture doesn't
+support self-IPIs and irq work are then all lazy, such as with the
+following sequence:
+
+1) rcu_read_unlock() is called when IRQs are disabled and there is a
+   grace period involving blocked tasks on the node. The irq work
+   is then initialized and queued.
+
+2) The related tasks are unblocked and the CPU quiescent state
+   is reported. rdp->defer_qs_iw_pending is reset to DEFER_QS_IDLE,
+   allowing the irq work to be requeued in the future (note the previous
+   one hasn't fired yet).
+
+3) A new grace period starts and the node has blocked tasks.
+
+4) rcu_read_unlock() is called when IRQs are disabled again. The irq work
+   is re-initialized (but it's queued! and its node is cleared) and
+   requeued. Which means it's requeued to itself.
+
+5) The irq work finally fires with the tick. But since it was requeued
+   to itself, it loops and hangs.
+
+Fix this with initializing the irq work only once before the CPU boots.
+
+Fixes: b41642c87716 ("rcu: Fix rcu_read_unlock() deadloop due to IRQ work")
+Reported-by: kernel test robot <oliver.sang@intel.com>
+Closes: https://lore.kernel.org/oe-lkp/202508071303.c1134cce-lkp@intel.com
+Signed-off-by: Frederic Weisbecker <frederic@kernel.org>
+Reviewed-by: Joel Fernandes <joelagnelf@nvidia.com>
+Signed-off-by: Neeraj Upadhyay (AMD) <neeraj.upadhyay@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/rcu/tree.c        |    2 ++
+ kernel/rcu/tree.h        |    1 +
+ kernel/rcu/tree_plugin.h |    8 ++++++--
+ 3 files changed, 9 insertions(+), 2 deletions(-)
+
+--- a/kernel/rcu/tree.c
++++ b/kernel/rcu/tree.c
+@@ -4427,6 +4427,8 @@ int rcutree_prepare_cpu(unsigned int cpu
+       rdp->rcu_iw_gp_seq = rdp->gp_seq - 1;
+       trace_rcu_grace_period(rcu_state.name, rdp->gp_seq, TPS("cpuonl"));
+       raw_spin_unlock_irqrestore_rcu_node(rnp, flags);
++
++      rcu_preempt_deferred_qs_init(rdp);
+       rcu_spawn_one_boost_kthread(rnp);
+       rcu_spawn_cpu_nocb_kthread(cpu);
+       WRITE_ONCE(rcu_state.n_online_cpus, rcu_state.n_online_cpus + 1);
+--- a/kernel/rcu/tree.h
++++ b/kernel/rcu/tree.h
+@@ -463,6 +463,7 @@ static int rcu_print_task_exp_stall(stru
+ static void rcu_preempt_check_blocked_tasks(struct rcu_node *rnp);
+ static void rcu_flavor_sched_clock_irq(int user);
+ static void dump_blkd_tasks(struct rcu_node *rnp, int ncheck);
++static void rcu_preempt_deferred_qs_init(struct rcu_data *rdp);
+ static void rcu_initiate_boost(struct rcu_node *rnp, unsigned long flags);
+ static void rcu_preempt_boost_start_gp(struct rcu_node *rnp);
+ static bool rcu_is_callbacks_kthread(struct rcu_data *rdp);
+--- a/kernel/rcu/tree_plugin.h
++++ b/kernel/rcu/tree_plugin.h
+@@ -687,8 +687,6 @@ static void rcu_read_unlock_special(stru
+                           cpu_online(rdp->cpu)) {
+                               // Get scheduler to re-evaluate and call hooks.
+                               // If !IRQ_WORK, FQS scan will eventually IPI.
+-                              rdp->defer_qs_iw =
+-                                      IRQ_WORK_INIT_HARD(rcu_preempt_deferred_qs_handler);
+                               rdp->defer_qs_iw_pending = DEFER_QS_PENDING;
+                               irq_work_queue_on(&rdp->defer_qs_iw, rdp->cpu);
+                       }
+@@ -828,6 +826,10 @@ dump_blkd_tasks(struct rcu_node *rnp, in
+       }
+ }
++static void rcu_preempt_deferred_qs_init(struct rcu_data *rdp)
++{
++      rdp->defer_qs_iw = IRQ_WORK_INIT_HARD(rcu_preempt_deferred_qs_handler);
++}
+ #else /* #ifdef CONFIG_PREEMPT_RCU */
+ /*
+@@ -1027,6 +1029,8 @@ dump_blkd_tasks(struct rcu_node *rnp, in
+       WARN_ON_ONCE(!list_empty(&rnp->blkd_tasks));
+ }
++static void rcu_preempt_deferred_qs_init(struct rcu_data *rdp) { }
++
+ #endif /* #else #ifdef CONFIG_PREEMPT_RCU */
+ /*
index c492e2e164520690e4a3c33cc17deb7f1fa4aea8..b4f04d03e987eb356ef178a4fd674dfef506054e 100644 (file)
@@ -329,3 +329,5 @@ 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