]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
6.12-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 12 Mar 2026 20:08:29 +0000 (21:08 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 12 Mar 2026 20:08:29 +0000 (21:08 +0100)
added patches:
ata-libata-cancel-pending-work-after-clearing-deferred_qc.patch
ata-libata-core-fix-cancellation-of-a-port-deferred-qc-work.patch
ata-libata-eh-correctly-handle-deferred-qc-timeouts.patch
ext4-fix-potential-null-deref-in-ext4_mb_init.patch

queue-6.12/ata-libata-cancel-pending-work-after-clearing-deferred_qc.patch [new file with mode: 0644]
queue-6.12/ata-libata-core-fix-cancellation-of-a-port-deferred-qc-work.patch [new file with mode: 0644]
queue-6.12/ata-libata-eh-correctly-handle-deferred-qc-timeouts.patch [new file with mode: 0644]
queue-6.12/ext4-fix-potential-null-deref-in-ext4_mb_init.patch [new file with mode: 0644]
queue-6.12/series

diff --git a/queue-6.12/ata-libata-cancel-pending-work-after-clearing-deferred_qc.patch b/queue-6.12/ata-libata-cancel-pending-work-after-clearing-deferred_qc.patch
new file mode 100644 (file)
index 0000000..18dbdde
--- /dev/null
@@ -0,0 +1,84 @@
+From aac9b27f7c1f2b2cf7f50a9ca633ecbbcaf22af9 Mon Sep 17 00:00:00 2001
+From: Niklas Cassel <cassel@kernel.org>
+Date: Tue, 3 Mar 2026 11:03:42 +0100
+Subject: ata: libata: cancel pending work after clearing deferred_qc
+
+From: Niklas Cassel <cassel@kernel.org>
+
+commit aac9b27f7c1f2b2cf7f50a9ca633ecbbcaf22af9 upstream.
+
+Syzbot reported a WARN_ON() in ata_scsi_deferred_qc_work(), caused by
+ap->ops->qc_defer() returning non-zero before issuing the deferred qc.
+
+ata_scsi_schedule_deferred_qc() is called during each command completion.
+This function will check if there is a deferred QC, and if
+ap->ops->qc_defer() returns zero, meaning that it is possible to queue the
+deferred qc at this time (without being deferred), then it will queue the
+work which will issue the deferred qc.
+
+Once the work get to run, which can potentially be a very long time after
+the work was scheduled, there is a WARN_ON() if ap->ops->qc_defer() returns
+non-zero.
+
+While we hold the ap->lock both when assigning and clearing deferred_qc,
+and the work itself holds the ap->lock, the code currently does not cancel
+the work after clearing the deferred qc.
+
+This means that the following scenario can happen:
+1) One or several NCQ commands are queued.
+2) A non-NCQ command is queued, gets stored in ap->deferred_qc.
+3) Last NCQ command gets completed, work is queued to issue the deferred
+   qc.
+4) Timeout or error happens, ap->deferred_qc is cleared. The queued work is
+   currently NOT canceled.
+5) Port is reset.
+6) One or several NCQ commands are queued.
+7) A non-NCQ command is queued, gets stored in ap->deferred_qc.
+8) Work is finally run. Yet at this time, there is still NCQ commands in
+   flight.
+
+The work in 8) really belongs to the non-NCQ command in 2), not to the
+non-NCQ command in 7). The reason why the work is executed when it is not
+supposed to, is because it was never canceled when ap->deferred_qc was
+cleared in 4). Thus, ensure that we always cancel the work after clearing
+ap->deferred_qc.
+
+Another potential fix would have been to let ata_scsi_deferred_qc_work() do
+nothing if ap->ops->qc_defer() returns non-zero. However, canceling the
+work when clearing ap->deferred_qc seems slightly more logical, as we hold
+the ap->lock when clearing ap->deferred_qc, so we know that the work cannot
+be holding the lock. (The function could be waiting for the lock, but that
+is okay since it will do nothing if ap->deferred_qc is not set.)
+
+Reported-by: syzbot+bcaf842a1e8ead8dfb89@syzkaller.appspotmail.com
+Fixes: 0ea84089dbf6 ("ata: libata-scsi: avoid Non-NCQ command starvation")
+Fixes: eddb98ad9364 ("ata: libata-eh: correctly handle deferred qc timeouts")
+Reviewed-by: Igor Pylypiv <ipylypiv@google.com>
+Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
+Signed-off-by: Niklas Cassel <cassel@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/ata/libata-eh.c   |    1 +
+ drivers/ata/libata-scsi.c |    1 +
+ 2 files changed, 2 insertions(+)
+
+--- a/drivers/ata/libata-eh.c
++++ b/drivers/ata/libata-eh.c
+@@ -661,6 +661,7 @@ void ata_scsi_cmd_error_handler(struct S
+                        */
+                       WARN_ON_ONCE(qc->flags & ATA_QCFLAG_ACTIVE);
+                       ap->deferred_qc = NULL;
++                      cancel_work(&ap->deferred_qc_work);
+                       set_host_byte(scmd, DID_TIME_OUT);
+                       scsi_eh_finish_cmd(scmd, &ap->eh_done_q);
+               } else if (i < ATA_MAX_QUEUE) {
+--- a/drivers/ata/libata-scsi.c
++++ b/drivers/ata/libata-scsi.c
+@@ -1712,6 +1712,7 @@ void ata_scsi_requeue_deferred_qc(struct
+       scmd = qc->scsicmd;
+       ap->deferred_qc = NULL;
++      cancel_work(&ap->deferred_qc_work);
+       ata_qc_free(qc);
+       scmd->result = (DID_SOFT_ERROR << 16);
+       scsi_done(scmd);
diff --git a/queue-6.12/ata-libata-core-fix-cancellation-of-a-port-deferred-qc-work.patch b/queue-6.12/ata-libata-core-fix-cancellation-of-a-port-deferred-qc-work.patch
new file mode 100644 (file)
index 0000000..10e59f9
--- /dev/null
@@ -0,0 +1,49 @@
+From 55db009926634b20955bd8abbee921adbc8d2cb4 Mon Sep 17 00:00:00 2001
+From: Damien Le Moal <dlemoal@kernel.org>
+Date: Fri, 20 Feb 2026 12:09:12 +0900
+Subject: ata: libata-core: fix cancellation of a port deferred qc work
+
+From: Damien Le Moal <dlemoal@kernel.org>
+
+commit 55db009926634b20955bd8abbee921adbc8d2cb4 upstream.
+
+cancel_work_sync() is a sleeping function so it cannot be called with
+the spin lock of a port being held. Move the call to this function in
+ata_port_detach() after EH completes, with the port lock released,
+together with other work cancellation calls.
+
+Fixes: 0ea84089dbf6 ("ata: libata-scsi: avoid Non-NCQ command starvation")
+Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
+Reviewed-by: Hannes Reinecke <hare@suse.de>
+Reviewed-by: Igor Pylypiv <ipylypiv@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/ata/libata-core.c |    8 +++-----
+ 1 file changed, 3 insertions(+), 5 deletions(-)
+
+--- a/drivers/ata/libata-core.c
++++ b/drivers/ata/libata-core.c
+@@ -6132,10 +6132,6 @@ static void ata_port_detach(struct ata_p
+               }
+       }
+-      /* Make sure the deferred qc work finished. */
+-      cancel_work_sync(&ap->deferred_qc_work);
+-      WARN_ON(ap->deferred_qc);
+-
+       /* Tell EH to disable all devices */
+       ap->pflags |= ATA_PFLAG_UNLOADING;
+       ata_port_schedule_eh(ap);
+@@ -6146,9 +6142,11 @@ static void ata_port_detach(struct ata_p
+       /* wait till EH commits suicide */
+       ata_port_wait_eh(ap);
+-      /* it better be dead now */
++      /* It better be dead now and not have any remaining deferred qc. */
+       WARN_ON(!(ap->pflags & ATA_PFLAG_UNLOADED));
++      WARN_ON(ap->deferred_qc);
++      cancel_work_sync(&ap->deferred_qc_work);
+       cancel_delayed_work_sync(&ap->hotplug_task);
+       cancel_delayed_work_sync(&ap->scsi_rescan_task);
diff --git a/queue-6.12/ata-libata-eh-correctly-handle-deferred-qc-timeouts.patch b/queue-6.12/ata-libata-eh-correctly-handle-deferred-qc-timeouts.patch
new file mode 100644 (file)
index 0000000..76aa4c7
--- /dev/null
@@ -0,0 +1,84 @@
+From eddb98ad9364b4e778768785d46cfab04ce52100 Mon Sep 17 00:00:00 2001
+From: Damien Le Moal <dlemoal@kernel.org>
+Date: Fri, 20 Feb 2026 13:43:00 +0900
+Subject: ata: libata-eh: correctly handle deferred qc timeouts
+
+From: Damien Le Moal <dlemoal@kernel.org>
+
+commit eddb98ad9364b4e778768785d46cfab04ce52100 upstream.
+
+A deferred qc may timeout while waiting for the device queue to drain
+to be submitted. In such case, since the qc is not active,
+ata_scsi_cmd_error_handler() ends up calling scsi_eh_finish_cmd(),
+which frees the qc. But as the port deferred_qc field still references
+this finished/freed qc, the deferred qc work may eventually attempt to
+call ata_qc_issue() against this invalid qc, leading to errors such as
+reported by UBSAN (syzbot run):
+
+UBSAN: shift-out-of-bounds in drivers/ata/libata-core.c:5166:24
+shift exponent 4210818301 is too large for 64-bit type 'long long unsigned int'
+...
+Call Trace:
+ <TASK>
+ __dump_stack lib/dump_stack.c:94 [inline]
+ dump_stack_lvl+0x100/0x190 lib/dump_stack.c:120
+ ubsan_epilogue+0xa/0x30 lib/ubsan.c:233
+ __ubsan_handle_shift_out_of_bounds+0x279/0x2a0 lib/ubsan.c:494
+ ata_qc_issue.cold+0x38/0x9f drivers/ata/libata-core.c:5166
+ ata_scsi_deferred_qc_work+0x154/0x1f0 drivers/ata/libata-scsi.c:1679
+ process_one_work+0x9d7/0x1920 kernel/workqueue.c:3275
+ process_scheduled_works kernel/workqueue.c:3358 [inline]
+ worker_thread+0x5da/0xe40 kernel/workqueue.c:3439
+ kthread+0x370/0x450 kernel/kthread.c:467
+ ret_from_fork+0x754/0xd80 arch/x86/kernel/process.c:158
+ ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
+ </TASK>
+
+Fix this by checking if the qc of a timed out SCSI command is a deferred
+one, and in such case, clear the port deferred_qc field and finish the
+SCSI command with DID_TIME_OUT.
+
+Reported-by: syzbot+1f77b8ca15336fff21ff@syzkaller.appspotmail.com
+Fixes: 0ea84089dbf6 ("ata: libata-scsi: avoid Non-NCQ command starvation")
+Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
+Reviewed-by: Hannes Reinecke <hare@suse.de>
+Reviewed-by: Igor Pylypiv <ipylypiv@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/ata/libata-eh.c |   22 +++++++++++++++++++---
+ 1 file changed, 19 insertions(+), 3 deletions(-)
+
+--- a/drivers/ata/libata-eh.c
++++ b/drivers/ata/libata-eh.c
+@@ -642,12 +642,28 @@ void ata_scsi_cmd_error_handler(struct S
+               set_host_byte(scmd, DID_OK);
+               ata_qc_for_each_raw(ap, qc, i) {
+-                      if (qc->flags & ATA_QCFLAG_ACTIVE &&
+-                          qc->scsicmd == scmd)
++                      if (qc->scsicmd != scmd)
++                              continue;
++                      if ((qc->flags & ATA_QCFLAG_ACTIVE) ||
++                          qc == ap->deferred_qc)
+                               break;
+               }
+-              if (i < ATA_MAX_QUEUE) {
++              if (qc == ap->deferred_qc) {
++                      /*
++                       * This is a deferred command that timed out while
++                       * waiting for the command queue to drain. Since the qc
++                       * is not active yet (deferred_qc is still set, so the
++                       * deferred qc work has not issued the command yet),
++                       * simply signal the timeout by finishing the SCSI
++                       * command and clear the deferred qc to prevent the
++                       * deferred qc work from issuing this qc.
++                       */
++                      WARN_ON_ONCE(qc->flags & ATA_QCFLAG_ACTIVE);
++                      ap->deferred_qc = NULL;
++                      set_host_byte(scmd, DID_TIME_OUT);
++                      scsi_eh_finish_cmd(scmd, &ap->eh_done_q);
++              } else if (i < ATA_MAX_QUEUE) {
+                       /* the scmd has an associated qc */
+                       if (!(qc->flags & ATA_QCFLAG_EH)) {
+                               /* which hasn't failed yet, timeout */
diff --git a/queue-6.12/ext4-fix-potential-null-deref-in-ext4_mb_init.patch b/queue-6.12/ext4-fix-potential-null-deref-in-ext4_mb_init.patch
new file mode 100644 (file)
index 0000000..e5aef3d
--- /dev/null
@@ -0,0 +1,81 @@
+From 3c3fac6bc0a9c00dbe65d8dc0d3a282afe4d3188 Mon Sep 17 00:00:00 2001
+From: Baokun Li <libaokun1@huawei.com>
+Date: Mon, 25 Aug 2025 11:38:30 +0800
+Subject: ext4: fix potential null deref in ext4_mb_init()
+
+From: Baokun Li <libaokun1@huawei.com>
+
+commit 3c3fac6bc0a9c00dbe65d8dc0d3a282afe4d3188 upstream.
+
+In ext4_mb_init(), ext4_mb_avg_fragment_size_destroy() may be called
+when sbi->s_mb_avg_fragment_size remains uninitialized (e.g., if groupinfo
+slab cache allocation fails). Since ext4_mb_avg_fragment_size_destroy()
+lacks null pointer checking, this leads to a null pointer dereference.
+
+==================================================================
+EXT4-fs: no memory for groupinfo slab cache
+BUG: kernel NULL pointer dereference, address: 0000000000000000
+PGD 0 P4D 0
+Oops: Oops: 0002 [#1] SMP PTI
+CPU:2 UID: 0 PID: 87 Comm:mount Not tainted 6.17.0-rc2 #1134 PREEMPT(none)
+RIP: 0010:_raw_spin_lock_irqsave+0x1b/0x40
+Call Trace:
+ <TASK>
+ xa_destroy+0x61/0x130
+ ext4_mb_init+0x483/0x540
+ __ext4_fill_super+0x116d/0x17b0
+ ext4_fill_super+0xd3/0x280
+ get_tree_bdev_flags+0x132/0x1d0
+ vfs_get_tree+0x29/0xd0
+ do_new_mount+0x197/0x300
+ __x64_sys_mount+0x116/0x150
+ do_syscall_64+0x50/0x1c0
+ entry_SYSCALL_64_after_hwframe+0x76/0x7e
+==================================================================
+
+Therefore, add necessary null check to ext4_mb_avg_fragment_size_destroy()
+to prevent this issue. The same fix is also applied to
+ext4_mb_largest_free_orders_destroy().
+
+Reported-by: syzbot+1713b1aa266195b916c2@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=1713b1aa266195b916c2
+Cc: stable@kernel.org
+Fixes: f7eaacbb4e54 ("ext4: convert free groups order lists to xarrays")
+Signed-off-by: Baokun Li <libaokun1@huawei.com>
+Reviewed-by: Zhang Yi <yi.zhang@huawei.com>
+Reviewed-by: Ritesh Harjani (IBM) <ritesh.list@gmail.com>
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/ext4/mballoc.c |   10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/fs/ext4/mballoc.c
++++ b/fs/ext4/mballoc.c
+@@ -3678,16 +3678,26 @@ static void ext4_discard_work(struct wor
+ static inline void ext4_mb_avg_fragment_size_destroy(struct ext4_sb_info *sbi)
+ {
++      if (!sbi->s_mb_avg_fragment_size)
++              return;
++
+       for (int i = 0; i < MB_NUM_ORDERS(sbi->s_sb); i++)
+               xa_destroy(&sbi->s_mb_avg_fragment_size[i]);
++
+       kfree(sbi->s_mb_avg_fragment_size);
++      sbi->s_mb_avg_fragment_size = NULL;
+ }
+ static inline void ext4_mb_largest_free_orders_destroy(struct ext4_sb_info *sbi)
+ {
++      if (!sbi->s_mb_largest_free_orders)
++              return;
++
+       for (int i = 0; i < MB_NUM_ORDERS(sbi->s_sb); i++)
+               xa_destroy(&sbi->s_mb_largest_free_orders[i]);
++
+       kfree(sbi->s_mb_largest_free_orders);
++      sbi->s_mb_largest_free_orders = NULL;
+ }
+ int ext4_mb_init(struct super_block *sb)
index 9d4feddaf54de331d0e3235dadd78e07ff80d0ef..a209b1c19dad810c0673bea83233ca2505e4ec6b 100644 (file)
@@ -258,3 +258,7 @@ apparmor-fix-unprivileged-local-user-can-do-privileged-policy-management.patch
 apparmor-fix-differential-encoding-verification.patch
 apparmor-fix-race-on-rawdata-dereference.patch
 apparmor-fix-race-between-freeing-data-and-fs-accessing-it.patch
+ext4-fix-potential-null-deref-in-ext4_mb_init.patch
+ata-libata-core-fix-cancellation-of-a-port-deferred-qc-work.patch
+ata-libata-eh-correctly-handle-deferred-qc-timeouts.patch
+ata-libata-cancel-pending-work-after-clearing-deferred_qc.patch