dm thin: fix use-after-free in metadata_pre_commit_callback
authorMike Snitzer <snitzer@redhat.com>
Mon, 13 Jan 2020 17:29:04 +0000 (12:29 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 5 Feb 2020 21:22:53 +0000 (21:22 +0000)
commite16b302f691ce6c6baca5619d4a2046f817f4aa8
treefbf084a5e224591fefe5a794fcad2c44f3501b68
parent35511d9471bee93dab7fa7750f41baf400f52160
dm thin: fix use-after-free in metadata_pre_commit_callback

[ Upstream commit a4a8d286586d4b28c8517a51db8d86954aadc74b ]

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 694cfe7f31db3 ("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: 694cfe7f31db3 ("dm thin: Flush data device before committing metadata")
Cc: stable@vger.kernel.org
Reported-by: Zdenek Kabelac <zkabelac@redhat.com>
Reported-by: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/md/dm-thin.c