]> git.baikalelectronics.ru Git - kernel.git/commitdiff
dm thin: fix use-after-free crash in dm_sm_register_threshold_callback
authorLuo Meng <luomeng12@huawei.com>
Thu, 14 Jul 2022 11:28:25 +0000 (19:28 +0800)
committerMike Snitzer <snitzer@kernel.org>
Fri, 15 Jul 2022 22:09:14 +0000 (18:09 -0400)
Fault inject on pool metadata device reports:
  BUG: KASAN: use-after-free in dm_pool_register_metadata_threshold+0x40/0x80
  Read of size 8 at addr ffff8881b9d50068 by task dmsetup/950

  CPU: 7 PID: 950 Comm: dmsetup Tainted: G        W         5.19.0-rc6 #1
  Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.14.0-1.fc33 04/01/2014
  Call Trace:
   <TASK>
   dump_stack_lvl+0x34/0x44
   print_address_description.constprop.0.cold+0xeb/0x3f4
   kasan_report.cold+0xe6/0x147
   dm_pool_register_metadata_threshold+0x40/0x80
   pool_ctr+0xa0a/0x1150
   dm_table_add_target+0x2c8/0x640
   table_load+0x1fd/0x430
   ctl_ioctl+0x2c4/0x5a0
   dm_ctl_ioctl+0xa/0x10
   __x64_sys_ioctl+0xb3/0xd0
   do_syscall_64+0x35/0x80
   entry_SYSCALL_64_after_hwframe+0x46/0xb0

This can be easily reproduced using:
  echo offline > /sys/block/sda/device/state
  dd if=/dev/zero of=/dev/mapper/thin bs=4k count=10
  dmsetup load pool --table "0 20971520 thin-pool /dev/sda /dev/sdb 128 0 0"

If a metadata commit fails, the transaction will be aborted and the
metadata space maps will be destroyed. If a DM table reload then
happens for this failed thin-pool, a use-after-free will occur in
dm_sm_register_threshold_callback (called from
dm_pool_register_metadata_threshold).

Fix this by in dm_pool_register_metadata_threshold() by returning the
-EINVAL error if the thin-pool is in fail mode. Also fail pool_ctr()
with a new error message: "Error registering metadata threshold".

Fixes: 1fb0bf620f327 ("dm thin: generate event when metadata threshold passed")
Cc: stable@vger.kernel.org
Reported-by: Hulk Robot <hulkci@huawei.com>
Signed-off-by: Luo Meng <luomeng12@huawei.com>
Signed-off-by: Mike Snitzer <snitzer@kernel.org>
drivers/md/dm-thin-metadata.c
drivers/md/dm-thin.c

index 2db7030aba00b4984323a1b82c386bcd934bb8f0..a27395c8621ff51e6a5d68a8414493e4c19437a9 100644 (file)
@@ -2045,10 +2045,13 @@ int dm_pool_register_metadata_threshold(struct dm_pool_metadata *pmd,
                                        dm_sm_threshold_fn fn,
                                        void *context)
 {
-       int r;
+       int r = -EINVAL;
 
        pmd_write_lock_in_core(pmd);
-       r = dm_sm_register_threshold_callback(pmd->metadata_sm, threshold, fn, context);
+       if (!pmd->fail_io) {
+               r = dm_sm_register_threshold_callback(pmd->metadata_sm,
+                                                     threshold, fn, context);
+       }
        pmd_write_unlock(pmd);
 
        return r;
index 84c083f766736f37e6b514e273045a72e3fe8bd8..e76c96c760a9b5629fcd60fed99a1229cc3e3dda 100644 (file)
@@ -3375,8 +3375,10 @@ static int pool_ctr(struct dm_target *ti, unsigned argc, char **argv)
                                                calc_metadata_threshold(pt),
                                                metadata_low_callback,
                                                pool);
-       if (r)
+       if (r) {
+               ti->error = "Error registering metadata threshold";
                goto out_flags_changed;
+       }
 
        dm_pool_register_pre_commit_callback(pool->pmd,
                                             metadata_pre_commit_callback, pool);