From: Greg Kroah-Hartman Date: Mon, 18 Aug 2025 11:02:30 +0000 (+0200) Subject: 5.10-stable patches X-Git-Tag: v6.12.43~30 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ea50ee4098ad48984f8facce7142e58615cc4ccf;p=thirdparty%2Fkernel%2Fstable-queue.git 5.10-stable patches 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 --- diff --git a/queue-5.10/btrfs-fix-log-tree-replay-failure-due-to-file-with-0-links-and-extents.patch b/queue-5.10/btrfs-fix-log-tree-replay-failure-due-to-file-with-0-links-and-extents.patch new file mode 100644 index 0000000000..3a5addbd49 --- /dev/null +++ b/queue-5.10/btrfs-fix-log-tree-replay-failure-due-to-file-with-0-links-and-extents.patch @@ -0,0 +1,147 @@ +From 0a32e4f0025a74c70dcab4478e9b29c22f5ecf2f Mon Sep 17 00:00:00 2001 +From: Filipe Manana +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 + +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 +Link: https://lore.kernel.org/linux-btrfs/fce139db-4458-4788-bb97-c29acf6cb1df@cachyos.org/ +Reported-by: burneddi +Link: https://lore.kernel.org/linux-btrfs/lh4W-Lwc0Mbk-QvBhhQyZxf6VbM3E8VtIvU3fPIQgweP_Q1n7wtlUZQc33sYlCKYd-o6rryJQfhHaNAOWWRKxpAXhM8NZPojzsJPyHMf2qY=@protonmail.com/#t +Reported-by: Russell Haley +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 +Signed-off-by: Filipe Manana +Signed-off-by: David Sterba +Signed-off-by: Greg Kroah-Hartman +--- + 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 +@@ -272,8 +272,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; + +@@ -2581,23 +2580,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; +@@ -2605,8 +2611,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.10/comedi-fix-race-between-polling-and-detaching.patch b/queue-5.10/comedi-fix-race-between-polling-and-detaching.patch new file mode 100644 index 0000000000..7fbbf0f207 --- /dev/null +++ b/queue-5.10/comedi-fix-race-between-polling-and-detaching.patch @@ -0,0 +1,157 @@ +From 35b6fc51c666fc96355be5cd633ed0fe4ccf68b2 Mon Sep 17 00:00:00 2001 +From: Ian Abbott +Date: Tue, 22 Jul 2025 16:53:16 +0100 +Subject: comedi: fix race between polling and detaching + +From: Ian Abbott + +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 +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 +Signed-off-by: Jens Axboe +Signed-off-by: Ian Abbott +Tested-by: Jens Axboe +Link: https://lore.kernel.org/r/20250722155316.27432-1-abbotti@mev.co.uk +Signed-off-by: Greg Kroah-Hartman +--- + 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 +@@ -783,6 +783,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; +@@ -791,7 +792,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; + } + +@@ -821,15 +831,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); + } + diff --git a/queue-5.10/series b/queue-5.10/series index ebc8cb4611..fe6e9ae953 100644 --- a/queue-5.10/series +++ b/queue-5.10/series @@ -343,3 +343,6 @@ drm-amdgpu-fix-incorrect-vm-flags-to-map-bo.patch usb-core-config-prevent-oob-read-in-ss-endpoint-companion-parsing.patch misc-rtsx-usb-ensure-mmc-child-device-is-active-when-card-is-present.patch usb-typec-ucsi-update-power_supply-on-power-role-change.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.10/thunderbolt-fix-copy-paste-error-in-match_service_id.patch b/queue-5.10/thunderbolt-fix-copy-paste-error-in-match_service_id.patch new file mode 100644 index 0000000000..88375762f1 --- /dev/null +++ b/queue-5.10/thunderbolt-fix-copy-paste-error-in-match_service_id.patch @@ -0,0 +1,32 @@ +From 5cc1f66cb23cccc704e3def27ad31ed479e934a5 Mon Sep 17 00:00:00 2001 +From: Eric Biggers +Date: Sun, 20 Jul 2025 22:01:36 -0700 +Subject: thunderbolt: Fix copy+paste error in match_service_id() + +From: Eric Biggers + +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 +Signed-off-by: Eric Biggers +Link: https://lore.kernel.org/r/20250721050136.30004-1-ebiggers@kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + 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; + }