[dm-devel] [PATCH v2 3/3] dm thin metadata: Fix use-after-free in dm_bm_set_read_only

Ye Bin yebin10 at huawei.com
Tue Sep 1 06:25:44 UTC 2020


We got follow error when test disk online/offline:
[  301.798344] device-mapper: thin: 253:5: aborting current metadata transaction
[  301.848441] device-mapper: thin: 253:5: failed to abort metadata transaction
[  301.849206] Aborting journal on device dm-26-8.
[  301.850489] EXT4-fs error (device dm-26) in __ext4_new_inode:943: Journal has aborted
[  301.851095] EXT4-fs (dm-26): Delayed block allocation failed for inode 398742 at logical offset 181 with max blocks 19 with error 30
[  301.854476] BUG: KASAN: use-after-free in dm_bm_set_read_only+0x3a/0x40 [dm_persistent_data]
[  301.854483] Write of size 1 at addr ffff88802d3c9688 by task dockerd/2201
[  301.854491]
[  301.855766] EXT4-fs error (device dm-26) in ext4_writepages:2934: Journal has aborted
[  301.857018] CPU: 2 PID: 2201 Comm: dockerd Kdump: loaded Not tainted 4.18.0-147.5.0.5.h126.eulerosv2r9.x86_64-debug #3
[  301.857025] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.9.1-0-gb3ef39f-20170502_104147-build9a64a246a203 04/01/2014
[  301.857031] Call Trace:
[  301.859617]  dump_stack+0xdd/0x18e
[  301.859624]  ? show_regs_print_info+0x12/0x12
[  301.859634]  ? __rwsem_mark_wake+0xa40/0xa40
[  301.859641]  print_address_description+0x6a/0x270
[  301.859647]  kasan_report+0x1a4/0x2f0
[  301.859658]  ? dm_bm_set_read_only+0x3a/0x40 [dm_persistent_data]
[  301.859668]  ? dm_bm_set_read_only+0x3a/0x40 [dm_persistent_data]
[  301.859677]  dm_bm_set_read_only+0x3a/0x40 [dm_persistent_data]
[  301.859687]  dm_pool_metadata_read_only+0x42/0x60 [dm_thin_pool]
[  301.859695]  set_pool_mode+0x606/0xd80 [dm_thin_pool]
[  301.859701]  ? up_read+0x40/0x40
[  301.859709]  ? process_prepared_discard_fail+0x80/0x80 [dm_thin_pool]
[  301.859717]  ? metadata_operation_failed+0x16b/0x1e0 [dm_thin_pool]
[  301.859725]  metadata_operation_failed+0x187/0x1e0 [dm_thin_pool]
[  301.859733]  commit+0x257/0x370 [dm_thin_pool]
[  301.859741]  ? metadata_operation_failed+0x1e0/0x1e0 [dm_thin_pool]
[  301.859750]  ? _parse_integer+0x130/0x130
[  301.859757]  ? memcpy+0x34/0x50
[  301.859765]  pool_message+0x24f/0xc70 [dm_thin_pool]
[  301.859782]  ? realloc_argv+0x73/0x110 [dm_mod]
[  301.859789]  ? commit+0x370/0x370 [dm_thin_pool]
[  301.859796]  ? kasan_unpoison_shadow+0x30/0x40
[  301.859803]  ? __kasan_slab_free+0x145/0x180
[  301.859813]  ? realloc_argv+0xcb/0x110 [dm_mod]
[  301.859818]  ? kfree+0x90/0x1a0
[  301.859824]  ? rcu_sync_dtor+0x160/0x160
[  301.859834]  ? dm_split_args+0x447/0x5c0 [dm_mod]
[  301.859844]  ? dm_get_live_table+0x76/0x140 [dm_mod]
[  301.859854]  ? dm_get_stats+0x20/0x20 [dm_mod]
[  301.859864]  ? dm_table_find_target+0x242/0x2b0 [dm_mod]
[  301.859872]  ? commit+0x370/0x370 [dm_thin_pool]
[  301.859881]  target_message+0x759/0xb80 [dm_mod]
[  301.859893]  ? __dev_status+0x6c0/0x6c0 [dm_mod]
[  301.859898]  ? selinux_inode_copy_up+0x180/0x180
[  301.859905]  ? __virt_addr_valid+0x17f/0x220
[  301.859911]  ? usercopy_abort+0xd0/0xd0
[  301.859916]  ? kasan_kmalloc_large+0x71/0xe0
[  301.859922]  ? kmalloc_large_node+0x68/0x80
[  301.859933]  ? __dev_status+0x6c0/0x6c0 [dm_mod]
[  301.859942]  ctl_ioctl+0x5b7/0xe40 [dm_mod]
[  301.859953]  ? free_params+0x50/0x50 [dm_mod]
[  301.859960]  ? avc_has_extended_perms+0x6d8/0x1030
[  301.859971]  ? mem_cgroup_throttle_swaprate+0x92/0x520
[  301.859980]  ? lru_cache_add_active_or_unevictable+0x12e/0x330
[  301.859991]  ? rcu_barrier+0x5f0/0x5f0
[  301.860001]  dm_ctl_ioctl+0x23/0x30 [dm_mod]
[  301.860016]  ? ctl_ioctl+0xe40/0xe40 [dm_mod]
[  301.860027]  do_vfs_ioctl+0x1a6/0x13c0
[  301.860038]  ? selinux_file_ioctl+0x418/0x6d0
[  301.860047]  ? ioctl_preallocate+0x2a0/0x2a0
[  301.860054]  ? selinux_file_mprotect+0x590/0x590
[  301.860064]  ? iterate_fd+0x2c0/0x2c0
[  301.860075]  ? trace_event_raw_event_sys_enter+0x670/0x670
[  301.860083]  ? handle_mm_fault+0x292/0x7a0
[  301.860089]  ? security_file_ioctl+0x5d/0xb0
[  301.860094]  ? selinux_file_mprotect+0x590/0x590
[  301.860100]  ksys_ioctl+0x89/0xa0
[  301.860107]  __x64_sys_ioctl+0x74/0xb0
[  301.860113]  do_syscall_64+0x172/0x590
[  301.860120]  ? syscall_return_slowpath+0x3c0/0x3c0
[  301.860128]  ? __do_page_fault+0xa80/0xa80
[  301.860135]  ? prepare_exit_to_usermode+0x1bb/0x290
[  301.860141]  ? enter_from_user_mode+0x70/0x70
[  301.860149]  ? __switch_to_asm+0x35/0x70
[  301.860155]  ? __switch_to_asm+0x41/0x70
[  301.860163]  entry_SYSCALL_64_after_hwframe+0x65/0xca
[  301.860169] RIP: 0033:0x7f7246f028a7
[  301.860179] Code: b3 66 90 48 8b 05 f9 15 0c 00 64 c7 00 26 00 00 00 48 c7 c0 ff ff ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 b8 10 00 00 00 0f 05 <48> 3d 01 f0 ff ff
8 64 89 01 48
[  301.860182] RSP: 002b:00007f71e3ffeaf8 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
[  301.860189] RAX: ffffffffffffffda RBX: 0000564d3473cb30 RCX: 00007f7246f028a7
[  301.860193] RDX: 00007f71d4059c80 RSI: 00000000c138fd0e RDI: 000000000000000a
[  301.860196] RBP: 00007f7247013513 R08: 0000000000000000 R09: 0000000000000001
[  301.860200] R10: 000000c000eb44c0 R11: 0000000000000246 R12: 0000000000000000
[  301.860204] R13: 00007f71d4059cb0 R14: 00007f71d4059c80 R15: 00007f71d4006f20
[  301.860208]
[  301.860438] Allocated by task 2201:
[  301.860848]  kasan_kmalloc+0xa0/0xd0
[  301.860854]  kmem_cache_alloc_trace+0xf3/0x1e0
[  301.860864]  dm_block_manager_create+0x55/0x130 [dm_persistent_data]
[  301.860872]  __create_persistent_data_objects+0xbe/0x1820 [dm_thin_pool]
[  301.860879]  dm_pool_abort_metadata+0x136/0x1e0 [dm_thin_pool]
[  301.860886]  metadata_operation_failed+0xac/0x1e0 [dm_thin_pool]
[  301.860892]  commit+0x257/0x370 [dm_thin_pool]
[  301.860901]  pool_message+0x24f/0xc70 [dm_thin_pool]
[  301.860916]  target_message+0x759/0xb80 [dm_mod]
[  301.860930]  ctl_ioctl+0x5b7/0xe40 [dm_mod]
[  301.860943]  dm_ctl_ioctl+0x23/0x30 [dm_mod]
[  301.860949]  do_vfs_ioctl+0x1a6/0x13c0
[  301.860954]  ksys_ioctl+0x89/0xa0
[  301.860959]  __x64_sys_ioctl+0x74/0xb0
[  301.860964]  do_syscall_64+0x172/0x590
[  301.860970]  entry_SYSCALL_64_after_hwframe+0x65/0xca
[  301.860972]
[  301.861192] Freed by task 2201:
[  301.861642]  __kasan_slab_free+0x130/0x180
[  301.861649]  kfree+0x90/0x1a0
[  301.861657]  __create_persistent_data_objects+0x163/0x1820 [dm_thin_pool]
[  301.861665]  dm_pool_abort_metadata+0x136/0x1e0 [dm_thin_pool]
[  301.861672]  metadata_operation_failed+0xac/0x1e0 [dm_thin_pool]
[  301.861678]  commit+0x257/0x370 [dm_thin_pool]
[  301.861685]  pool_message+0x24f/0xc70 [dm_thin_pool]
[  301.860916]  target_message+0x759/0xb80 [dm_mod]
[  301.860930]  ctl_ioctl+0x5b7/0xe40 [dm_mod]
[  301.860943]  dm_ctl_ioctl+0x23/0x30 [dm_mod]
[  301.860949]  do_vfs_ioctl+0x1a6/0x13c0
[  301.860954]  ksys_ioctl+0x89/0xa0
[  301.860959]  __x64_sys_ioctl+0x74/0xb0
[  301.860964]  do_syscall_64+0x172/0x590
[  301.860970]  entry_SYSCALL_64_after_hwframe+0x65/0xca
[  301.860972]
[  301.861192] Freed by task 2201:
[  301.861642]  __kasan_slab_free+0x130/0x180
[  301.861649]  kfree+0x90/0x1a0
[  301.861657]  __create_persistent_data_objects+0x163/0x1820 [dm_thin_pool]
[  301.861665]  dm_pool_abort_metadata+0x136/0x1e0 [dm_thin_pool]
[  301.861672]  metadata_operation_failed+0xac/0x1e0 [dm_thin_pool]
[  301.861678]  commit+0x257/0x370 [dm_thin_pool]
[  301.861685]  pool_message+0x24f/0xc70 [dm_thin_pool]
[  301.861698]  target_message+0x759/0xb80 [dm_mod]
[  301.861708]  ctl_ioctl+0x5b7/0xe40 [dm_mod]
[  301.861717]  dm_ctl_ioctl+0x23/0x30 [dm_mod]
[  301.861722]  do_vfs_ioctl+0x1a6/0x13c0
[  301.861727]  ksys_ioctl+0x89/0xa0
[  301.861732]  __x64_sys_ioctl+0x74/0xb0
[  301.861737]  do_syscall_64+0x172/0x590
[  301.861743]  entry_SYSCALL_64_after_hwframe+0x65/0xca
[  301.861744]
[  301.862034] The buggy address belongs to the object at ffff88802d3c9680#012 which belongs to the cache kmalloc-16 of size 16
[  301.863534] The buggy address is located 8 bytes inside of#012 16-byte region [ffff88802d3c9680, ffff88802d3c9690)
[  301.864847] The buggy address belongs to the page:
[  301.865475] page:ffffea0000b4f240 count:1 mapcount:0 mapping:ffff888107c0f980 index:0xffff88802d3c9200
[  301.866815] flags: 0xfffffc0000100(slab)
[  301.867302] raw: 000fffffc0000100 ffffea00042b9bc8 ffff888107c00110 ffff888107c0f980
[  301.868192] raw: ffff88802d3c97c0 000000000080007d 00000001ffffffff 0000000000000000
[  301.869084] page dumped because: kasan: bad access detected
[  301.869729]
[  301.869916] Memory state around the buggy address:
[  301.870475]  ffff88802d3c9580: 00 00 fc fc fb fb fc fc fb fb fc fc fb fb fc fc
[  301.871290]  ffff88802d3c9600: fb fb fc fc fb fb fc fc fb fb fc fc fb fb fc fc
[  301.872114] >ffff88802d3c9680: fb fb fc fc fb fb fc fc fb fb fc fc fb fb fc fc
[  301.872944]                       ^
[  301.873362]  ffff88802d3c9700: fb fb fc fc fb fb fc fc fb fb fc fc 00 00 fc fc
[  301.874174]  ffff88802d3c9780: fb fb fc fc fb fb fc fc 00 00 fc fc fb fb fc fc
[  301.875000] ==================================================================

reason:
imetadata_operation_failed
    abort_transaction
        dm_pool_abort_metadata
	    __create_persistent_data_objects
	        r = __open_or_format_metadata
	        if (r)--> If failed will free pmd->bm but pmd->bm not set NULL
		    dm_block_manager_destroy(pmd->bm);
    set_pool_mode
	dm_pool_metadata_read_only(pool->pmd);
	dm_bm_set_read_only(pmd->bm);  --> use-after-free

Add judge pmd->dm if NULL in dm_bm_set_read_only and dm_bm_set_read_write function.
If bm is NULL means create bm failed then dm_bm_is_read_only must return true.

Signed-off-by: Ye Bin <yebin10 at huawei.com>
---
 drivers/md/dm-thin-metadata.c                 |  2 +-
 drivers/md/persistent-data/dm-block-manager.c | 14 ++++++++------
 2 files changed, 9 insertions(+), 7 deletions(-)

diff --git a/drivers/md/dm-thin-metadata.c b/drivers/md/dm-thin-metadata.c
index ddb7f1f0bc48..b461836b6d26 100644
--- a/drivers/md/dm-thin-metadata.c
+++ b/drivers/md/dm-thin-metadata.c
@@ -958,7 +958,7 @@ int dm_pool_metadata_close(struct dm_pool_metadata *pmd)
 	}
 
 	pmd_write_lock_in_core(pmd);
-	if (!dm_bm_is_read_only(pmd->bm) && !pmd->fail_io) {
+	if (!pmd->fail_io && !dm_bm_is_read_only(pmd->bm)) {
 		r = __commit_transaction(pmd);
 		if (r < 0)
 			DMWARN("%s: __commit_transaction() failed, error = %d",
diff --git a/drivers/md/persistent-data/dm-block-manager.c b/drivers/md/persistent-data/dm-block-manager.c
index 749ec268d957..54c089a50b15 100644
--- a/drivers/md/persistent-data/dm-block-manager.c
+++ b/drivers/md/persistent-data/dm-block-manager.c
@@ -493,7 +493,7 @@ int dm_bm_write_lock(struct dm_block_manager *bm,
 	void *p;
 	int r;
 
-	if (bm->read_only)
+	if (dm_bm_is_read_only(bm))
 		return -EPERM;
 
 	p = dm_bufio_read(bm->bufio, b, (struct dm_buffer **) result);
@@ -562,7 +562,7 @@ int dm_bm_write_lock_zero(struct dm_block_manager *bm,
 	struct buffer_aux *aux;
 	void *p;
 
-	if (bm->read_only)
+	if (dm_bm_is_read_only(bm))
 		return -EPERM;
 
 	p = dm_bufio_new(bm->bufio, b, (struct dm_buffer **) result);
@@ -602,7 +602,7 @@ EXPORT_SYMBOL_GPL(dm_bm_unlock);
 
 int dm_bm_flush(struct dm_block_manager *bm)
 {
-	if (bm->read_only)
+	if (dm_bm_is_read_only(bm))
 		return -EPERM;
 
 	return dm_bufio_write_dirty_buffers(bm->bufio);
@@ -616,19 +616,21 @@ void dm_bm_prefetch(struct dm_block_manager *bm, dm_block_t b)
 
 bool dm_bm_is_read_only(struct dm_block_manager *bm)
 {
-	return bm->read_only;
+	return (bm ? bm->read_only : true);
 }
 EXPORT_SYMBOL_GPL(dm_bm_is_read_only);
 
 void dm_bm_set_read_only(struct dm_block_manager *bm)
 {
-	bm->read_only = true;
+	if (bm)
+		bm->read_only = true;
 }
 EXPORT_SYMBOL_GPL(dm_bm_set_read_only);
 
 void dm_bm_set_read_write(struct dm_block_manager *bm)
 {
-	bm->read_only = false;
+	if (bm)
+		bm->read_only = false;
 }
 EXPORT_SYMBOL_GPL(dm_bm_set_read_write);
 
-- 
2.25.4





More information about the dm-devel mailing list