dm thin: fix use-after-free crash in dm_sm_register_threshold_callback
commit 3534e5a5ed2997ca1b00f44a0378a075bd05e8a3 upstream.
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: ac8c3f3df6
("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>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
cb583ca612
commit
05cef0999b
@ -2060,10 +2060,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;
|
||||
|
@ -3425,8 +3425,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;
|
||||
}
|
||||
|
||||
pt->callbacks.congested_fn = pool_is_congested;
|
||||
dm_table_add_target_callbacks(ti->table, &pt->callbacks);
|
||||
|
Loading…
Reference in New Issue
Block a user