]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.4-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 18 Aug 2025 11:02:21 +0000 (13:02 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 18 Aug 2025 11:02:21 +0000 (13:02 +0200)
added patches:
btrfs-fix-log-tree-replay-failure-due-to-file-with-0-links-and-extents.patch
comedi-fix-race-between-polling-and-detaching.patch
thunderbolt-fix-copy-paste-error-in-match_service_id.patch

queue-5.4/btrfs-fix-log-tree-replay-failure-due-to-file-with-0-links-and-extents.patch [new file with mode: 0644]
queue-5.4/comedi-fix-race-between-polling-and-detaching.patch [new file with mode: 0644]
queue-5.4/series
queue-5.4/thunderbolt-fix-copy-paste-error-in-match_service_id.patch [new file with mode: 0644]

diff --git a/queue-5.4/btrfs-fix-log-tree-replay-failure-due-to-file-with-0-links-and-extents.patch b/queue-5.4/btrfs-fix-log-tree-replay-failure-due-to-file-with-0-links-and-extents.patch
new file mode 100644 (file)
index 0000000..4c7e4e4
--- /dev/null
@@ -0,0 +1,147 @@
+From 0a32e4f0025a74c70dcab4478e9b29c22f5ecf2f Mon Sep 17 00:00:00 2001
+From: Filipe Manana <fdmanana@suse.com>
+Date: Wed, 30 Jul 2025 19:18:37 +0100
+Subject: btrfs: fix log tree replay failure due to file with 0 links and extents
+
+From: Filipe Manana <fdmanana@suse.com>
+
+commit 0a32e4f0025a74c70dcab4478e9b29c22f5ecf2f upstream.
+
+If we log a new inode (not persisted in a past transaction) that has 0
+links and extents, then log another inode with an higher inode number, we
+end up with failing to replay the log tree with -EINVAL. The steps for
+this are:
+
+1) create new file A
+2) write some data to file A
+3) open an fd on file A
+4) unlink file A
+5) fsync file A using the previously open fd
+6) create file B (has higher inode number than file A)
+7) fsync file B
+8) power fail before current transaction commits
+
+Now when attempting to mount the fs, the log replay will fail with
+-ENOENT at replay_one_extent() when attempting to replay the first
+extent of file A. The failure comes when trying to open the inode for
+file A in the subvolume tree, since it doesn't exist.
+
+Before commit 5f61b961599a ("btrfs: fix inode lookup error handling
+during log replay"), the returned error was -EIO instead of -ENOENT,
+since we converted any errors when attempting to read an inode during
+log replay to -EIO.
+
+The reason for this is that the log replay procedure fails to ignore
+the current inode when we are at the stage LOG_WALK_REPLAY_ALL, our
+current inode has 0 links and last inode we processed in the previous
+stage has a non 0 link count. In other words, the issue is that at
+replay_one_extent() we only update wc->ignore_cur_inode if the current
+replay stage is LOG_WALK_REPLAY_INODES.
+
+Fix this by updating wc->ignore_cur_inode whenever we find an inode item
+regardless of the current replay stage. This is a simple solution and easy
+to backport, but later we can do other alternatives like avoid logging
+extents or inode items other than the inode item for inodes with a link
+count of 0.
+
+The problem with the wc->ignore_cur_inode logic has been around since
+commit f2d72f42d5fa ("Btrfs: fix warning when replaying log after fsync
+of a tmpfile") but it only became frequent to hit since the more recent
+commit 5e85262e542d ("btrfs: fix fsync of files with no hard links not
+persisting deletion"), because we stopped skipping inodes with a link
+count of 0 when logging, while before the problem would only be triggered
+if trying to replay a log tree created with an older kernel which has a
+logged inode with 0 links.
+
+A test case for fstests will be submitted soon.
+
+Reported-by: Peter Jung <ptr1337@cachyos.org>
+Link: https://lore.kernel.org/linux-btrfs/fce139db-4458-4788-bb97-c29acf6cb1df@cachyos.org/
+Reported-by: burneddi <burneddi@protonmail.com>
+Link: https://lore.kernel.org/linux-btrfs/lh4W-Lwc0Mbk-QvBhhQyZxf6VbM3E8VtIvU3fPIQgweP_Q1n7wtlUZQc33sYlCKYd-o6rryJQfhHaNAOWWRKxpAXhM8NZPojzsJPyHMf2qY=@protonmail.com/#t
+Reported-by: Russell Haley <yumpusamongus@gmail.com>
+Link: https://lore.kernel.org/linux-btrfs/598ecc75-eb80-41b3-83c2-f2317fbb9864@gmail.com/
+Fixes: f2d72f42d5fa ("Btrfs: fix warning when replaying log after fsync of a tmpfile")
+CC: stable@vger.kernel.org # 5.4+
+Reviewed-by: Boris Burkov <boris@bur.io>
+Signed-off-by: Filipe Manana <fdmanana@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/btrfs/tree-log.c |   48 ++++++++++++++++++++++++++++++------------------
+ 1 file changed, 30 insertions(+), 18 deletions(-)
+
+--- a/fs/btrfs/tree-log.c
++++ b/fs/btrfs/tree-log.c
+@@ -274,8 +274,7 @@ struct walk_control {
+       /*
+        * Ignore any items from the inode currently being processed. Needs
+-       * to be set every time we find a BTRFS_INODE_ITEM_KEY and we are in
+-       * the LOG_WALK_REPLAY_INODES stage.
++       * to be set every time we find a BTRFS_INODE_ITEM_KEY.
+        */
+       bool ignore_cur_inode;
+@@ -2604,23 +2603,30 @@ static int replay_one_buffer(struct btrf
+       nritems = btrfs_header_nritems(eb);
+       for (i = 0; i < nritems; i++) {
+-              btrfs_item_key_to_cpu(eb, &key, i);
++              struct btrfs_inode_item *inode_item;
+-              /* inode keys are done during the first stage */
+-              if (key.type == BTRFS_INODE_ITEM_KEY &&
+-                  wc->stage == LOG_WALK_REPLAY_INODES) {
+-                      struct btrfs_inode_item *inode_item;
+-                      u32 mode;
++              btrfs_item_key_to_cpu(eb, &key, i);
+-                      inode_item = btrfs_item_ptr(eb, i,
+-                                          struct btrfs_inode_item);
++              if (key.type == BTRFS_INODE_ITEM_KEY) {
++                      inode_item = btrfs_item_ptr(eb, i, struct btrfs_inode_item);
+                       /*
+-                       * If we have a tmpfile (O_TMPFILE) that got fsync'ed
+-                       * and never got linked before the fsync, skip it, as
+-                       * replaying it is pointless since it would be deleted
+-                       * later. We skip logging tmpfiles, but it's always
+-                       * possible we are replaying a log created with a kernel
+-                       * that used to log tmpfiles.
++                       * An inode with no links is either:
++                       *
++                       * 1) A tmpfile (O_TMPFILE) that got fsync'ed and never
++                       *    got linked before the fsync, skip it, as replaying
++                       *    it is pointless since it would be deleted later.
++                       *    We skip logging tmpfiles, but it's always possible
++                       *    we are replaying a log created with a kernel that
++                       *    used to log tmpfiles;
++                       *
++                       * 2) A non-tmpfile which got its last link deleted
++                       *    while holding an open fd on it and later got
++                       *    fsynced through that fd. We always log the
++                       *    parent inodes when inode->last_unlink_trans is
++                       *    set to the current transaction, so ignore all the
++                       *    inode items for this inode. We will delete the
++                       *    inode when processing the parent directory with
++                       *    replay_dir_deletes().
+                        */
+                       if (btrfs_inode_nlink(eb, inode_item) == 0) {
+                               wc->ignore_cur_inode = true;
+@@ -2628,8 +2634,14 @@ static int replay_one_buffer(struct btrf
+                       } else {
+                               wc->ignore_cur_inode = false;
+                       }
+-                      ret = replay_xattr_deletes(wc->trans, root, log,
+-                                                 path, key.objectid);
++              }
++
++              /* Inode keys are done during the first stage. */
++              if (key.type == BTRFS_INODE_ITEM_KEY &&
++                  wc->stage == LOG_WALK_REPLAY_INODES) {
++                      u32 mode;
++
++                      ret = replay_xattr_deletes(wc->trans, root, log, path, key.objectid);
+                       if (ret)
+                               break;
+                       mode = btrfs_inode_mode(eb, inode_item);
diff --git a/queue-5.4/comedi-fix-race-between-polling-and-detaching.patch b/queue-5.4/comedi-fix-race-between-polling-and-detaching.patch
new file mode 100644 (file)
index 0000000..122302c
--- /dev/null
@@ -0,0 +1,157 @@
+From 35b6fc51c666fc96355be5cd633ed0fe4ccf68b2 Mon Sep 17 00:00:00 2001
+From: Ian Abbott <abbotti@mev.co.uk>
+Date: Tue, 22 Jul 2025 16:53:16 +0100
+Subject: comedi: fix race between polling and detaching
+
+From: Ian Abbott <abbotti@mev.co.uk>
+
+commit 35b6fc51c666fc96355be5cd633ed0fe4ccf68b2 upstream.
+
+syzbot reports a use-after-free in comedi in the below link, which is
+due to comedi gladly removing the allocated async area even though poll
+requests are still active on the wait_queue_head inside of it. This can
+cause a use-after-free when the poll entries are later triggered or
+removed, as the memory for the wait_queue_head has been freed.  We need
+to check there are no tasks queued on any of the subdevices' wait queues
+before allowing the device to be detached by the `COMEDI_DEVCONFIG`
+ioctl.
+
+Tasks will read-lock `dev->attach_lock` before adding themselves to the
+subdevice wait queue, so fix the problem in the `COMEDI_DEVCONFIG` ioctl
+handler by write-locking `dev->attach_lock` before checking that all of
+the subdevices are safe to be deleted.  This includes testing for any
+sleepers on the subdevices' wait queues.  It remains locked until the
+device has been detached.  This requires the `comedi_device_detach()`
+function to be refactored slightly, moving the bulk of it into new
+function `comedi_device_detach_locked()`.
+
+Note that the refactor of `comedi_device_detach()` results in
+`comedi_device_cancel_all()` now being called while `dev->attach_lock`
+is write-locked, which wasn't the case previously, but that does not
+matter.
+
+Thanks to Jens Axboe for diagnosing the problem and co-developing this
+patch.
+
+Cc: stable <stable@kernel.org>
+Fixes: 2f3fdcd7ce93 ("staging: comedi: add rw_semaphore to protect against device detachment")
+Link: https://lore.kernel.org/all/687bd5fe.a70a0220.693ce.0091.GAE@google.com/
+Reported-by: syzbot+01523a0ae5600aef5895@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=01523a0ae5600aef5895
+Co-developed-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Ian Abbott <abbotti@mev.co.uk>
+Tested-by: Jens Axboe <axboe@kernel.dk>
+Link: https://lore.kernel.org/r/20250722155316.27432-1-abbotti@mev.co.uk
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/staging/comedi/comedi_fops.c     |   33 +++++++++++++++++++++++--------
+ drivers/staging/comedi/comedi_internal.h |    1 
+ drivers/staging/comedi/drivers.c         |   13 +++++++++---
+ 3 files changed, 36 insertions(+), 11 deletions(-)
+
+--- a/drivers/staging/comedi/comedi_fops.c
++++ b/drivers/staging/comedi/comedi_fops.c
+@@ -781,6 +781,7 @@ static int is_device_busy(struct comedi_
+       struct comedi_subdevice *s;
+       int i;
++      lockdep_assert_held_write(&dev->attach_lock);
+       lockdep_assert_held(&dev->mutex);
+       if (!dev->attached)
+               return 0;
+@@ -789,7 +790,16 @@ static int is_device_busy(struct comedi_
+               s = &dev->subdevices[i];
+               if (s->busy)
+                       return 1;
+-              if (s->async && comedi_buf_is_mmapped(s))
++              if (!s->async)
++                      continue;
++              if (comedi_buf_is_mmapped(s))
++                      return 1;
++              /*
++               * There may be tasks still waiting on the subdevice's wait
++               * queue, although they should already be about to be removed
++               * from it since the subdevice has no active async command.
++               */
++              if (wq_has_sleeper(&s->async->wait_head))
+                       return 1;
+       }
+@@ -819,15 +829,22 @@ static int do_devconfig_ioctl(struct com
+               return -EPERM;
+       if (!arg) {
+-              if (is_device_busy(dev))
+-                      return -EBUSY;
+-              if (dev->attached) {
+-                      struct module *driver_module = dev->driver->module;
++              int rc = 0;
+-                      comedi_device_detach(dev);
+-                      module_put(driver_module);
++              if (dev->attached) {
++                      down_write(&dev->attach_lock);
++                      if (is_device_busy(dev)) {
++                              rc = -EBUSY;
++                      } else {
++                              struct module *driver_module =
++                                      dev->driver->module;
++
++                              comedi_device_detach_locked(dev);
++                              module_put(driver_module);
++                      }
++                      up_write(&dev->attach_lock);
+               }
+-              return 0;
++              return rc;
+       }
+       if (copy_from_user(&it, arg, sizeof(it)))
+--- a/drivers/staging/comedi/comedi_internal.h
++++ b/drivers/staging/comedi/comedi_internal.h
+@@ -50,6 +50,7 @@ extern struct mutex comedi_drivers_list_
+ int insn_inval(struct comedi_device *dev, struct comedi_subdevice *s,
+              struct comedi_insn *insn, unsigned int *data);
++void comedi_device_detach_locked(struct comedi_device *dev);
+ void comedi_device_detach(struct comedi_device *dev);
+ int comedi_device_attach(struct comedi_device *dev,
+                        struct comedi_devconfig *it);
+--- a/drivers/staging/comedi/drivers.c
++++ b/drivers/staging/comedi/drivers.c
+@@ -159,7 +159,7 @@ static void comedi_device_detach_cleanup
+       int i;
+       struct comedi_subdevice *s;
+-      lockdep_assert_held(&dev->attach_lock);
++      lockdep_assert_held_write(&dev->attach_lock);
+       lockdep_assert_held(&dev->mutex);
+       if (dev->subdevices) {
+               for (i = 0; i < dev->n_subdevices; i++) {
+@@ -196,16 +196,23 @@ static void comedi_device_detach_cleanup
+       comedi_clear_hw_dev(dev);
+ }
+-void comedi_device_detach(struct comedi_device *dev)
++void comedi_device_detach_locked(struct comedi_device *dev)
+ {
++      lockdep_assert_held_write(&dev->attach_lock);
+       lockdep_assert_held(&dev->mutex);
+       comedi_device_cancel_all(dev);
+-      down_write(&dev->attach_lock);
+       dev->attached = false;
+       dev->detach_count++;
+       if (dev->driver)
+               dev->driver->detach(dev);
+       comedi_device_detach_cleanup(dev);
++}
++
++void comedi_device_detach(struct comedi_device *dev)
++{
++      lockdep_assert_held(&dev->mutex);
++      down_write(&dev->attach_lock);
++      comedi_device_detach_locked(dev);
+       up_write(&dev->attach_lock);
+ }
index 0dacf2231a85c36e1c8580d616aaa02768943f9c..f5a88b08831f56009989b6b944f5f022a9c822f8 100644 (file)
@@ -273,3 +273,6 @@ rtc-ds1307-remove-clear-of-oscillator-stop-flag-osf-.patch
 scsi-lpfc-remove-redundant-assignment-to-avoid-memor.patch
 drm-amdgpu-fix-incorrect-vm-flags-to-map-bo.patch
 misc-rtsx-usb-ensure-mmc-child-device-is-active-when-card-is-present.patch
+comedi-fix-race-between-polling-and-detaching.patch
+thunderbolt-fix-copy-paste-error-in-match_service_id.patch
+btrfs-fix-log-tree-replay-failure-due-to-file-with-0-links-and-extents.patch
diff --git a/queue-5.4/thunderbolt-fix-copy-paste-error-in-match_service_id.patch b/queue-5.4/thunderbolt-fix-copy-paste-error-in-match_service_id.patch
new file mode 100644 (file)
index 0000000..8837576
--- /dev/null
@@ -0,0 +1,32 @@
+From 5cc1f66cb23cccc704e3def27ad31ed479e934a5 Mon Sep 17 00:00:00 2001
+From: Eric Biggers <ebiggers@kernel.org>
+Date: Sun, 20 Jul 2025 22:01:36 -0700
+Subject: thunderbolt: Fix copy+paste error in match_service_id()
+
+From: Eric Biggers <ebiggers@kernel.org>
+
+commit 5cc1f66cb23cccc704e3def27ad31ed479e934a5 upstream.
+
+The second instance of TBSVC_MATCH_PROTOCOL_VERSION seems to have been
+intended to be TBSVC_MATCH_PROTOCOL_REVISION.
+
+Fixes: d1ff70241a27 ("thunderbolt: Add support for XDomain discovery protocol")
+Cc: stable <stable@kernel.org>
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Link: https://lore.kernel.org/r/20250721050136.30004-1-ebiggers@kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/thunderbolt/domain.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/thunderbolt/domain.c
++++ b/drivers/thunderbolt/domain.c
+@@ -38,7 +38,7 @@ static bool match_service_id(const struc
+                       return false;
+       }
+-      if (id->match_flags & TBSVC_MATCH_PROTOCOL_VERSION) {
++      if (id->match_flags & TBSVC_MATCH_PROTOCOL_REVISION) {
+               if (id->protocol_revision != svc->prtcrevs)
+                       return false;
+       }