Skip to content

Commit 135496c

Browse files
mingnusMikulas Patocka
authored andcommitted
dm cache: fix flushing uninitialized delayed_work on cache_ctr error
An unexpected WARN_ON from flush_work() may occur when cache creation fails, caused by destroying the uninitialized delayed_work waker in the error path of cache_create(). For example, the warning appears on the superblock checksum error. Reproduce steps: dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" dmsetup create cdata --table "0 65536 linear /dev/sdc 8192" dmsetup create corig --table "0 524288 linear /dev/sdc 262144" dd if=/dev/urandom of=/dev/mapper/cmeta bs=4k count=1 oflag=direct dmsetup create cache --table "0 524288 cache /dev/mapper/cmeta \ /dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writethrough smq 0" Kernel logs: (snip) WARNING: CPU: 0 PID: 84 at kernel/workqueue.c:4178 __flush_work+0x5d4/0x890 Fix by pulling out the cancel_delayed_work_sync() from the constructor's error path. This patch doesn't affect the use-after-free fix for concurrent dm_resume and dm_destroy (commit 6a459d8 ("dm cache: Fix UAF in destroy()")) as cache_dtr is not changed. Signed-off-by: Ming-Hung Tsai <[email protected]> Fixes: 6a459d8 ("dm cache: Fix UAF in destroy()") Cc: [email protected] Signed-off-by: Mikulas Patocka <[email protected]> Acked-by: Joe Thornber <[email protected]>
1 parent 235d2e7 commit 135496c

File tree

1 file changed

+15
-9
lines changed

1 file changed

+15
-9
lines changed

drivers/md/dm-cache-target.c

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1905,16 +1905,13 @@ static void check_migrations(struct work_struct *ws)
19051905
* This function gets called on the error paths of the constructor, so we
19061906
* have to cope with a partially initialised struct.
19071907
*/
1908-
static void destroy(struct cache *cache)
1908+
static void __destroy(struct cache *cache)
19091909
{
1910-
unsigned int i;
1911-
19121910
mempool_exit(&cache->migration_pool);
19131911

19141912
if (cache->prison)
19151913
dm_bio_prison_destroy_v2(cache->prison);
19161914

1917-
cancel_delayed_work_sync(&cache->waker);
19181915
if (cache->wq)
19191916
destroy_workqueue(cache->wq);
19201917

@@ -1942,13 +1939,22 @@ static void destroy(struct cache *cache)
19421939
if (cache->policy)
19431940
dm_cache_policy_destroy(cache->policy);
19441941

1942+
bioset_exit(&cache->bs);
1943+
1944+
kfree(cache);
1945+
}
1946+
1947+
static void destroy(struct cache *cache)
1948+
{
1949+
unsigned int i;
1950+
1951+
cancel_delayed_work_sync(&cache->waker);
1952+
19451953
for (i = 0; i < cache->nr_ctr_args ; i++)
19461954
kfree(cache->ctr_args[i]);
19471955
kfree(cache->ctr_args);
19481956

1949-
bioset_exit(&cache->bs);
1950-
1951-
kfree(cache);
1957+
__destroy(cache);
19521958
}
19531959

19541960
static void cache_dtr(struct dm_target *ti)
@@ -2561,7 +2567,7 @@ static int cache_create(struct cache_args *ca, struct cache **result)
25612567
*result = cache;
25622568
return 0;
25632569
bad:
2564-
destroy(cache);
2570+
__destroy(cache);
25652571
return r;
25662572
}
25672573

@@ -2612,7 +2618,7 @@ static int cache_ctr(struct dm_target *ti, unsigned int argc, char **argv)
26122618

26132619
r = copy_ctr_args(cache, argc - 3, (const char **)argv + 3);
26142620
if (r) {
2615-
destroy(cache);
2621+
__destroy(cache);
26162622
goto out;
26172623
}
26182624

0 commit comments

Comments
 (0)