]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.14-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 4 Jan 2023 14:01:49 +0000 (15:01 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 4 Jan 2023 14:01:49 +0000 (15:01 +0100)
added patches:
dm-cache-fix-abba-deadlock-between-shrink_slab-and-dm_cache_metadata_abort.patch
dm-cache-fix-uaf-in-destroy.patch
dm-cache-set-needs_check-flag-after-aborting-metadata.patch
dm-thin-fix-uaf-in-run_timer_softirq.patch
dm-thin-use-last-transaction-s-pmd-root-when-commit-failed.patch

queue-4.14/dm-cache-fix-abba-deadlock-between-shrink_slab-and-dm_cache_metadata_abort.patch [new file with mode: 0644]
queue-4.14/dm-cache-fix-uaf-in-destroy.patch [new file with mode: 0644]
queue-4.14/dm-cache-set-needs_check-flag-after-aborting-metadata.patch [new file with mode: 0644]
queue-4.14/dm-thin-fix-uaf-in-run_timer_softirq.patch [new file with mode: 0644]
queue-4.14/dm-thin-use-last-transaction-s-pmd-root-when-commit-failed.patch [new file with mode: 0644]
queue-4.14/series

diff --git a/queue-4.14/dm-cache-fix-abba-deadlock-between-shrink_slab-and-dm_cache_metadata_abort.patch b/queue-4.14/dm-cache-fix-abba-deadlock-between-shrink_slab-and-dm_cache_metadata_abort.patch
new file mode 100644 (file)
index 0000000..e08d415
--- /dev/null
@@ -0,0 +1,114 @@
+From 352b837a5541690d4f843819028cf2b8be83d424 Mon Sep 17 00:00:00 2001
+From: Mike Snitzer <snitzer@kernel.org>
+Date: Wed, 30 Nov 2022 13:26:32 -0500
+Subject: dm cache: Fix ABBA deadlock between shrink_slab and dm_cache_metadata_abort
+
+From: Mike Snitzer <snitzer@kernel.org>
+
+commit 352b837a5541690d4f843819028cf2b8be83d424 upstream.
+
+Same ABBA deadlock pattern fixed in commit 4b60f452ec51 ("dm thin: Fix
+ABBA deadlock between shrink_slab and dm_pool_abort_metadata") to
+DM-cache's metadata.
+
+Reported-by: Zhihao Cheng <chengzhihao1@huawei.com>
+Cc: stable@vger.kernel.org
+Fixes: 028ae9f76f29 ("dm cache: add fail io mode and needs_check flag")
+Signed-off-by: Mike Snitzer <snitzer@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/md/dm-cache-metadata.c |   54 +++++++++++++++++++++++++++++++++++------
+ 1 file changed, 47 insertions(+), 7 deletions(-)
+
+--- a/drivers/md/dm-cache-metadata.c
++++ b/drivers/md/dm-cache-metadata.c
+@@ -550,11 +550,13 @@ static int __create_persistent_data_obje
+       return r;
+ }
+-static void __destroy_persistent_data_objects(struct dm_cache_metadata *cmd)
++static void __destroy_persistent_data_objects(struct dm_cache_metadata *cmd,
++                                            bool destroy_bm)
+ {
+       dm_sm_destroy(cmd->metadata_sm);
+       dm_tm_destroy(cmd->tm);
+-      dm_block_manager_destroy(cmd->bm);
++      if (destroy_bm)
++              dm_block_manager_destroy(cmd->bm);
+ }
+ typedef unsigned long (*flags_mutator)(unsigned long);
+@@ -825,7 +827,7 @@ static struct dm_cache_metadata *lookup_
+               cmd2 = lookup(bdev);
+               if (cmd2) {
+                       mutex_unlock(&table_lock);
+-                      __destroy_persistent_data_objects(cmd);
++                      __destroy_persistent_data_objects(cmd, true);
+                       kfree(cmd);
+                       return cmd2;
+               }
+@@ -873,7 +875,7 @@ void dm_cache_metadata_close(struct dm_c
+               mutex_unlock(&table_lock);
+               if (!cmd->fail_io)
+-                      __destroy_persistent_data_objects(cmd);
++                      __destroy_persistent_data_objects(cmd, true);
+               kfree(cmd);
+       }
+ }
+@@ -1807,14 +1809,52 @@ int dm_cache_metadata_needs_check(struct
+ int dm_cache_metadata_abort(struct dm_cache_metadata *cmd)
+ {
+-      int r;
++      int r = -EINVAL;
++      struct dm_block_manager *old_bm = NULL, *new_bm = NULL;
++
++      /* fail_io is double-checked with cmd->root_lock held below */
++      if (unlikely(cmd->fail_io))
++              return r;
++
++      /*
++       * Replacement block manager (new_bm) is created and old_bm destroyed outside of
++       * cmd root_lock to avoid ABBA deadlock that would result (due to life-cycle of
++       * shrinker associated with the block manager's bufio client vs cmd root_lock).
++       * - must take shrinker_rwsem without holding cmd->root_lock
++       */
++      new_bm = dm_block_manager_create(cmd->bdev, DM_CACHE_METADATA_BLOCK_SIZE << SECTOR_SHIFT,
++                                       CACHE_MAX_CONCURRENT_LOCKS);
+       WRITE_LOCK(cmd);
+-      __destroy_persistent_data_objects(cmd);
+-      r = __create_persistent_data_objects(cmd, false);
++      if (cmd->fail_io) {
++              WRITE_UNLOCK(cmd);
++              goto out;
++      }
++
++      __destroy_persistent_data_objects(cmd, false);
++      old_bm = cmd->bm;
++      if (IS_ERR(new_bm)) {
++              DMERR("could not create block manager during abort");
++              cmd->bm = NULL;
++              r = PTR_ERR(new_bm);
++              goto out_unlock;
++      }
++
++      cmd->bm = new_bm;
++      r = __open_or_format_metadata(cmd, false);
++      if (r) {
++              cmd->bm = NULL;
++              goto out_unlock;
++      }
++      new_bm = NULL;
++out_unlock:
+       if (r)
+               cmd->fail_io = true;
+       WRITE_UNLOCK(cmd);
++      dm_block_manager_destroy(old_bm);
++out:
++      if (new_bm && !IS_ERR(new_bm))
++              dm_block_manager_destroy(new_bm);
+       return r;
+ }
diff --git a/queue-4.14/dm-cache-fix-uaf-in-destroy.patch b/queue-4.14/dm-cache-fix-uaf-in-destroy.patch
new file mode 100644 (file)
index 0000000..08edae0
--- /dev/null
@@ -0,0 +1,33 @@
+From 6a459d8edbdbe7b24db42a5a9f21e6aa9e00c2aa Mon Sep 17 00:00:00 2001
+From: Luo Meng <luomeng12@huawei.com>
+Date: Tue, 29 Nov 2022 10:48:49 +0800
+Subject: dm cache: Fix UAF in destroy()
+
+From: Luo Meng <luomeng12@huawei.com>
+
+commit 6a459d8edbdbe7b24db42a5a9f21e6aa9e00c2aa upstream.
+
+Dm_cache also has the same UAF problem when dm_resume()
+and dm_destroy() are concurrent.
+
+Therefore, cancelling timer again in destroy().
+
+Cc: stable@vger.kernel.org
+Fixes: c6b4fcbad044e ("dm: add cache target")
+Signed-off-by: Luo Meng <luomeng12@huawei.com>
+Signed-off-by: Mike Snitzer <snitzer@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/md/dm-cache-target.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/md/dm-cache-target.c
++++ b/drivers/md/dm-cache-target.c
+@@ -2034,6 +2034,7 @@ static void destroy(struct cache *cache)
+       if (cache->prison)
+               dm_bio_prison_destroy_v2(cache->prison);
++      cancel_delayed_work_sync(&cache->waker);
+       if (cache->wq)
+               destroy_workqueue(cache->wq);
diff --git a/queue-4.14/dm-cache-set-needs_check-flag-after-aborting-metadata.patch b/queue-4.14/dm-cache-set-needs_check-flag-after-aborting-metadata.patch
new file mode 100644 (file)
index 0000000..fe9c6fe
--- /dev/null
@@ -0,0 +1,47 @@
+From 6b9973861cb2e96dcd0bb0f1baddc5c034207c5c Mon Sep 17 00:00:00 2001
+From: Mike Snitzer <snitzer@kernel.org>
+Date: Wed, 30 Nov 2022 14:02:47 -0500
+Subject: dm cache: set needs_check flag after aborting metadata
+
+From: Mike Snitzer <snitzer@kernel.org>
+
+commit 6b9973861cb2e96dcd0bb0f1baddc5c034207c5c upstream.
+
+Otherwise the commit that will be aborted will be associated with the
+metadata objects that will be torn down.  Must write needs_check flag
+to metadata with a reset block manager.
+
+Found through code-inspection (and compared against dm-thin.c).
+
+Cc: stable@vger.kernel.org
+Fixes: 028ae9f76f29 ("dm cache: add fail io mode and needs_check flag")
+Signed-off-by: Mike Snitzer <snitzer@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/md/dm-cache-target.c |   10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+--- a/drivers/md/dm-cache-target.c
++++ b/drivers/md/dm-cache-target.c
+@@ -1019,16 +1019,16 @@ static void abort_transaction(struct cac
+       if (get_cache_mode(cache) >= CM_READ_ONLY)
+               return;
+-      if (dm_cache_metadata_set_needs_check(cache->cmd)) {
+-              DMERR("%s: failed to set 'needs_check' flag in metadata", dev_name);
+-              set_cache_mode(cache, CM_FAIL);
+-      }
+-
+       DMERR_LIMIT("%s: aborting current metadata transaction", dev_name);
+       if (dm_cache_metadata_abort(cache->cmd)) {
+               DMERR("%s: failed to abort metadata transaction", dev_name);
+               set_cache_mode(cache, CM_FAIL);
+       }
++
++      if (dm_cache_metadata_set_needs_check(cache->cmd)) {
++              DMERR("%s: failed to set 'needs_check' flag in metadata", dev_name);
++              set_cache_mode(cache, CM_FAIL);
++      }
+ }
+ static void metadata_operation_failed(struct cache *cache, const char *op, int r)
diff --git a/queue-4.14/dm-thin-fix-uaf-in-run_timer_softirq.patch b/queue-4.14/dm-thin-fix-uaf-in-run_timer_softirq.patch
new file mode 100644 (file)
index 0000000..995784c
--- /dev/null
@@ -0,0 +1,100 @@
+From 88430ebcbc0ec637b710b947738839848c20feff Mon Sep 17 00:00:00 2001
+From: Luo Meng <luomeng12@huawei.com>
+Date: Tue, 29 Nov 2022 10:48:47 +0800
+Subject: dm thin: Fix UAF in run_timer_softirq()
+
+From: Luo Meng <luomeng12@huawei.com>
+
+commit 88430ebcbc0ec637b710b947738839848c20feff upstream.
+
+When dm_resume() and dm_destroy() are concurrent, it will
+lead to UAF, as follows:
+
+ BUG: KASAN: use-after-free in __run_timers+0x173/0x710
+ Write of size 8 at addr ffff88816d9490f0 by task swapper/0/0
+<snip>
+ Call Trace:
+  <IRQ>
+  dump_stack_lvl+0x73/0x9f
+  print_report.cold+0x132/0xaa2
+  _raw_spin_lock_irqsave+0xcd/0x160
+  __run_timers+0x173/0x710
+  kasan_report+0xad/0x110
+  __run_timers+0x173/0x710
+  __asan_store8+0x9c/0x140
+  __run_timers+0x173/0x710
+  call_timer_fn+0x310/0x310
+  pvclock_clocksource_read+0xfa/0x250
+  kvm_clock_read+0x2c/0x70
+  kvm_clock_get_cycles+0xd/0x20
+  ktime_get+0x5c/0x110
+  lapic_next_event+0x38/0x50
+  clockevents_program_event+0xf1/0x1e0
+  run_timer_softirq+0x49/0x90
+  __do_softirq+0x16e/0x62c
+  __irq_exit_rcu+0x1fa/0x270
+  irq_exit_rcu+0x12/0x20
+  sysvec_apic_timer_interrupt+0x8e/0xc0
+
+One of the concurrency UAF can be shown as below:
+
+        use                                  free
+do_resume                           |
+  __find_device_hash_cell           |
+    dm_get                          |
+      atomic_inc(&md->holders)      |
+                                    | dm_destroy
+                                    |   __dm_destroy
+                                    |     if (!dm_suspended_md(md))
+                                    |     atomic_read(&md->holders)
+                                    |     msleep(1)
+  dm_resume                         |
+    __dm_resume                     |
+      dm_table_resume_targets       |
+        pool_resume                 |
+          do_waker  #add delay work |
+  dm_put                            |
+    atomic_dec(&md->holders)        |
+                                    |     dm_table_destroy
+                                    |       pool_dtr
+                                    |         __pool_dec
+                                    |           __pool_destroy
+                                    |             destroy_workqueue
+                                    |             kfree(pool) # free pool
+        time out
+__do_softirq
+  run_timer_softirq # pool has already been freed
+
+This can be easily reproduced using:
+  1. create thin-pool
+  2. dmsetup suspend pool
+  3. dmsetup resume pool
+  4. dmsetup remove_all # Concurrent with 3
+
+The root cause of this UAF bug is that dm_resume() adds timer after
+dm_destroy() skips cancelling the timer because of suspend status.
+After timeout, it will call run_timer_softirq(), however pool has
+already been freed. The concurrency UAF bug will happen.
+
+Therefore, cancelling timer again in __pool_destroy().
+
+Cc: stable@vger.kernel.org
+Fixes: 991d9fa02da0d ("dm: add thin provisioning target")
+Signed-off-by: Luo Meng <luomeng12@huawei.com>
+Signed-off-by: Mike Snitzer <snitzer@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/md/dm-thin.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/md/dm-thin.c
++++ b/drivers/md/dm-thin.c
+@@ -2932,6 +2932,8 @@ static void __pool_destroy(struct pool *
+       dm_bio_prison_destroy(pool->prison);
+       dm_kcopyd_client_destroy(pool->copier);
++      cancel_delayed_work_sync(&pool->waker);
++      cancel_delayed_work_sync(&pool->no_space_timeout);
+       if (pool->wq)
+               destroy_workqueue(pool->wq);
diff --git a/queue-4.14/dm-thin-use-last-transaction-s-pmd-root-when-commit-failed.patch b/queue-4.14/dm-thin-use-last-transaction-s-pmd-root-when-commit-failed.patch
new file mode 100644 (file)
index 0000000..53f2e1a
--- /dev/null
@@ -0,0 +1,84 @@
+From 7991dbff6849f67e823b7cc0c15e5a90b0549b9f Mon Sep 17 00:00:00 2001
+From: Zhihao Cheng <chengzhihao1@huawei.com>
+Date: Thu, 8 Dec 2022 22:28:02 +0800
+Subject: dm thin: Use last transaction's pmd->root when commit failed
+
+From: Zhihao Cheng <chengzhihao1@huawei.com>
+
+commit 7991dbff6849f67e823b7cc0c15e5a90b0549b9f upstream.
+
+Recently we found a softlock up problem in dm thin pool btree lookup
+code due to corrupted metadata:
+
+ Kernel panic - not syncing: softlockup: hung tasks
+ CPU: 7 PID: 2669225 Comm: kworker/u16:3
+ Hardware name: QEMU Standard PC (i440FX + PIIX, 1996)
+ Workqueue: dm-thin do_worker [dm_thin_pool]
+ Call Trace:
+   <IRQ>
+   dump_stack+0x9c/0xd3
+   panic+0x35d/0x6b9
+   watchdog_timer_fn.cold+0x16/0x25
+   __run_hrtimer+0xa2/0x2d0
+   </IRQ>
+   RIP: 0010:__relink_lru+0x102/0x220 [dm_bufio]
+   __bufio_new+0x11f/0x4f0 [dm_bufio]
+   new_read+0xa3/0x1e0 [dm_bufio]
+   dm_bm_read_lock+0x33/0xd0 [dm_persistent_data]
+   ro_step+0x63/0x100 [dm_persistent_data]
+   btree_lookup_raw.constprop.0+0x44/0x220 [dm_persistent_data]
+   dm_btree_lookup+0x16f/0x210 [dm_persistent_data]
+   dm_thin_find_block+0x12c/0x210 [dm_thin_pool]
+   __process_bio_read_only+0xc5/0x400 [dm_thin_pool]
+   process_thin_deferred_bios+0x1a4/0x4a0 [dm_thin_pool]
+   process_one_work+0x3c5/0x730
+
+Following process may generate a broken btree mixed with fresh and
+stale btree nodes, which could get dm thin trapped in an infinite loop
+while looking up data block:
+ Transaction 1: pmd->root = A, A->B->C   // One path in btree
+                pmd->root = X, X->Y->Z   // Copy-up
+ Transaction 2: X,Z is updated on disk, Y write failed.
+                // Commit failed, dm thin becomes read-only.
+                process_bio_read_only
+                dm_thin_find_block
+                 __find_block
+                  dm_btree_lookup(pmd->root)
+The pmd->root points to a broken btree, Y may contain stale node
+pointing to any block, for example X, which gets dm thin trapped into
+a dead loop while looking up Z.
+
+Fix this by setting pmd->root in __open_metadata(), so that dm thin
+will use the last transaction's pmd->root if commit failed.
+
+Fetch a reproducer in [Link].
+
+Linke: https://bugzilla.kernel.org/show_bug.cgi?id=216790
+Cc: stable@vger.kernel.org
+Fixes: 991d9fa02da0 ("dm: add thin provisioning target")
+Signed-off-by: Zhihao Cheng <chengzhihao1@huawei.com>
+Acked-by: Joe Thornber <ejt@redhat.com>
+Signed-off-by: Mike Snitzer <snitzer@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/md/dm-thin-metadata.c |    9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+--- a/drivers/md/dm-thin-metadata.c
++++ b/drivers/md/dm-thin-metadata.c
+@@ -660,6 +660,15 @@ static int __open_metadata(struct dm_poo
+               goto bad_cleanup_data_sm;
+       }
++      /*
++       * For pool metadata opening process, root setting is redundant
++       * because it will be set again in __begin_transaction(). But dm
++       * pool aborting process really needs to get last transaction's
++       * root to avoid accessing broken btree.
++       */
++      pmd->root = le64_to_cpu(disk_super->data_mapping_root);
++      pmd->details_root = le64_to_cpu(disk_super->device_details_root);
++
+       __setup_btree_details(pmd);
+       dm_bm_unlock(sblock);
index 9e63338deaf6948b37144a1ae9c59e27f96ed356..2094f1bb058577cc79837a05446ebf6ecb41acca 100644 (file)
@@ -274,3 +274,8 @@ media-stv0288-use-explicitly-signed-char.patch
 ktest.pl-minconfig-unset-configs-instead-of-just-removing-them.patch
 arm-ux500-do-not-directly-dereference-__iomem.patch
 selftests-use-optional-usercflags-and-userldflags.patch
+dm-cache-fix-abba-deadlock-between-shrink_slab-and-dm_cache_metadata_abort.patch
+dm-thin-use-last-transaction-s-pmd-root-when-commit-failed.patch
+dm-thin-fix-uaf-in-run_timer_softirq.patch
+dm-cache-fix-uaf-in-destroy.patch
+dm-cache-set-needs_check-flag-after-aborting-metadata.patch