]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
6.9-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 19 Jun 2024 07:07:46 +0000 (09:07 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 19 Jun 2024 07:07:46 +0000 (09:07 +0200)
added patches:
btrfs-zoned-fix-use-after-free-due-to-race-with-dev-replace.patch

queue-6.9/btrfs-zoned-fix-use-after-free-due-to-race-with-dev-replace.patch [new file with mode: 0644]
queue-6.9/series

diff --git a/queue-6.9/btrfs-zoned-fix-use-after-free-due-to-race-with-dev-replace.patch b/queue-6.9/btrfs-zoned-fix-use-after-free-due-to-race-with-dev-replace.patch
new file mode 100644 (file)
index 0000000..35cabbf
--- /dev/null
@@ -0,0 +1,107 @@
+From 0090d6e1b210551e63cf43958dc7a1ec942cdde9 Mon Sep 17 00:00:00 2001
+From: Filipe Manana <fdmanana@suse.com>
+Date: Wed, 8 May 2024 11:51:07 +0100
+Subject: btrfs: zoned: fix use-after-free due to race with dev replace
+
+From: Filipe Manana <fdmanana@suse.com>
+
+commit 0090d6e1b210551e63cf43958dc7a1ec942cdde9 upstream.
+
+While loading a zone's info during creation of a block group, we can race
+with a device replace operation and then trigger a use-after-free on the
+device that was just replaced (source device of the replace operation).
+
+This happens because at btrfs_load_zone_info() we extract a device from
+the chunk map into a local variable and then use the device while not
+under the protection of the device replace rwsem. So if there's a device
+replace operation happening when we extract the device and that device
+is the source of the replace operation, we will trigger a use-after-free
+if before we finish using the device the replace operation finishes and
+frees the device.
+
+Fix this by enlarging the critical section under the protection of the
+device replace rwsem so that all uses of the device are done inside the
+critical section.
+
+CC: stable@vger.kernel.org # 6.1.x: 15c12fcc50a1: btrfs: zoned: introduce a zone_info struct in btrfs_load_block_group_zone_info
+CC: stable@vger.kernel.org # 6.1.x: 09a46725cc84: btrfs: zoned: factor out per-zone logic from btrfs_load_block_group_zone_info
+CC: stable@vger.kernel.org # 6.1.x: 9e0e3e74dc69: btrfs: zoned: factor out single bg handling from btrfs_load_block_group_zone_info
+CC: stable@vger.kernel.org # 6.1.x: 87463f7e0250: btrfs: zoned: factor out DUP bg handling from btrfs_load_block_group_zone_info
+CC: stable@vger.kernel.org # 6.1.x
+Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
+Signed-off-by: Filipe Manana <fdmanana@suse.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/btrfs/zoned.c |   13 ++++++++++---
+ 1 file changed, 10 insertions(+), 3 deletions(-)
+
+--- a/fs/btrfs/zoned.c
++++ b/fs/btrfs/zoned.c
+@@ -1290,7 +1290,7 @@ static int btrfs_load_zone_info(struct b
+                               struct btrfs_chunk_map *map)
+ {
+       struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace;
+-      struct btrfs_device *device = map->stripes[zone_idx].dev;
++      struct btrfs_device *device;
+       int dev_replace_is_ongoing = 0;
+       unsigned int nofs_flag;
+       struct blk_zone zone;
+@@ -1298,7 +1298,11 @@ static int btrfs_load_zone_info(struct b
+       info->physical = map->stripes[zone_idx].physical;
++      down_read(&dev_replace->rwsem);
++      device = map->stripes[zone_idx].dev;
++
+       if (!device->bdev) {
++              up_read(&dev_replace->rwsem);
+               info->alloc_offset = WP_MISSING_DEV;
+               return 0;
+       }
+@@ -1308,6 +1312,7 @@ static int btrfs_load_zone_info(struct b
+               __set_bit(zone_idx, active);
+       if (!btrfs_dev_is_sequential(device, info->physical)) {
++              up_read(&dev_replace->rwsem);
+               info->alloc_offset = WP_CONVENTIONAL;
+               return 0;
+       }
+@@ -1315,11 +1320,9 @@ static int btrfs_load_zone_info(struct b
+       /* This zone will be used for allocation, so mark this zone non-empty. */
+       btrfs_dev_clear_zone_empty(device, info->physical);
+-      down_read(&dev_replace->rwsem);
+       dev_replace_is_ongoing = btrfs_dev_replace_is_ongoing(dev_replace);
+       if (dev_replace_is_ongoing && dev_replace->tgtdev != NULL)
+               btrfs_dev_clear_zone_empty(dev_replace->tgtdev, info->physical);
+-      up_read(&dev_replace->rwsem);
+       /*
+        * The group is mapped to a sequential zone. Get the zone write pointer
+@@ -1330,6 +1333,7 @@ static int btrfs_load_zone_info(struct b
+       ret = btrfs_get_dev_zone(device, info->physical, &zone);
+       memalloc_nofs_restore(nofs_flag);
+       if (ret) {
++              up_read(&dev_replace->rwsem);
+               if (ret != -EIO && ret != -EOPNOTSUPP)
+                       return ret;
+               info->alloc_offset = WP_MISSING_DEV;
+@@ -1341,6 +1345,7 @@ static int btrfs_load_zone_info(struct b
+               "zoned: unexpected conventional zone %llu on device %s (devid %llu)",
+                       zone.start << SECTOR_SHIFT, rcu_str_deref(device->name),
+                       device->devid);
++              up_read(&dev_replace->rwsem);
+               return -EIO;
+       }
+@@ -1368,6 +1373,8 @@ static int btrfs_load_zone_info(struct b
+               break;
+       }
++      up_read(&dev_replace->rwsem);
++
+       return 0;
+ }
index 9d6a130387a57f4129be1bf1f3798441dfcf1656..e56e2b02f3aa5bc6a33afe6343dcd621adbf9dea 100644 (file)
@@ -271,3 +271,4 @@ intel_th-pci-add-sapphire-rapids-soc-support.patch
 intel_th-pci-add-meteor-lake-s-support.patch
 intel_th-pci-add-lunar-lake-support.patch
 pmdomain-ti-sci-fix-duplicate-pd-referrals.patch
+btrfs-zoned-fix-use-after-free-due-to-race-with-dev-replace.patch