Skip to content

Commit

Permalink
dm thin: fix use-after-free in metadata_pre_commit_callback
Browse files Browse the repository at this point in the history
dm-thin uses struct pool to hold the state of the pool. There may be
multiple pool_c's pointing to a given pool, each pool_c represents a
loaded target. pool_c's may be created and destroyed arbitrarily and the
pool contains a reference count of pool_c's pointing to it.

Since commit 694cfe7 ("dm thin: Flush data device before
committing metadata") a pointer to pool_c is passed to
dm_pool_register_pre_commit_callback and this function stores it in
pmd->pre_commit_context. If this pool_c is freed, but pool is not
(because there is another pool_c referencing it), we end up in a
situation where pmd->pre_commit_context structure points to freed
pool_c. It causes a crash in metadata_pre_commit_callback.

Fix this by moving the dm_pool_register_pre_commit_callback() from
pool_ctr() to pool_preresume(). This way the in-core thin-pool metadata
is only ever armed with callback data whose lifetime matches the
active thin-pool target.

In should be noted that this fix preserves the ability to load a
thin-pool table that uses a different data block device (that contains
the same data) -- though it is unclear if that capability is still
useful and/or needed.

Fixes: 694cfe7 ("dm thin: Flush data device before committing metadata")
Cc: [email protected]
Reported-by: Zdenek Kabelac <[email protected]>
Reported-by: Mikulas Patocka <[email protected]>
Signed-off-by: Mike Snitzer <[email protected]>
  • Loading branch information
snitm committed Jan 15, 2020
1 parent 44d8ebf commit a4a8d28
Showing 1 changed file with 3 additions and 4 deletions.
7 changes: 3 additions & 4 deletions drivers/md/dm-thin.c
Original file line number Diff line number Diff line change
Expand Up @@ -3408,10 +3408,6 @@ static int pool_ctr(struct dm_target *ti, unsigned argc, char **argv)
if (r)
goto out_flags_changed;

dm_pool_register_pre_commit_callback(pt->pool->pmd,
metadata_pre_commit_callback,
pt);

pt->callbacks.congested_fn = pool_is_congested;
dm_table_add_target_callbacks(ti->table, &pt->callbacks);

Expand Down Expand Up @@ -3574,6 +3570,9 @@ static int pool_preresume(struct dm_target *ti)
if (r)
return r;

dm_pool_register_pre_commit_callback(pool->pmd,
metadata_pre_commit_callback, pt);

r = maybe_resize_data_dev(ti, &need_commit1);
if (r)
return r;
Expand Down

0 comments on commit a4a8d28

Please sign in to comment.