[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PULL 33/42] block-backend: Fix potential double blk_delete
From: |
Max Reitz |
Subject: |
[Qemu-devel] [PULL 33/42] block-backend: Fix potential double blk_delete() |
Date: |
Tue, 25 Sep 2018 17:15:32 +0200 |
From: Kevin Wolf <address@hidden>
blk_unref() first decreases the refcount of the BlockBackend and calls
blk_delete() if the refcount reaches zero. Requests can still be in
flight at this point, they are only drained during blk_delete():
At this point, arbitrary callbacks can run. If any callback takes a
temporary BlockBackend reference, it will first increase the refcount to
1 and then decrease it to 0 again, triggering another blk_delete(). This
will cause a use-after-free crash in the outer blk_delete().
Fix it by draining the BlockBackend before decreasing to refcount to 0.
Assert in blk_ref() that it never takes the first refcount (which would
mean that the BlockBackend is already being deleted).
Signed-off-by: Kevin Wolf <address@hidden>
Reviewed-by: Fam Zheng <address@hidden>
Reviewed-by: Max Reitz <address@hidden>
---
block/block-backend.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/block/block-backend.c b/block/block-backend.c
index 4e7d08ac3a..f71fdb4315 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -435,6 +435,7 @@ int blk_get_refcnt(BlockBackend *blk)
*/
void blk_ref(BlockBackend *blk)
{
+ assert(blk->refcnt > 0);
blk->refcnt++;
}
@@ -447,7 +448,13 @@ void blk_unref(BlockBackend *blk)
{
if (blk) {
assert(blk->refcnt > 0);
- if (!--blk->refcnt) {
+ if (blk->refcnt > 1) {
+ blk->refcnt--;
+ } else {
+ blk_drain(blk);
+ /* blk_drain() cannot resurrect blk, nobody held a reference */
+ assert(blk->refcnt == 1);
+ blk->refcnt = 0;
blk_delete(blk);
}
}
--
2.17.1
- [Qemu-devel] [PULL 25/42] blockjob: Wake up BDS when job becomes idle, (continued)
- [Qemu-devel] [PULL 25/42] blockjob: Wake up BDS when job becomes idle, Max Reitz, 2018/09/25
- [Qemu-devel] [PULL 26/42] aio-wait: Increase num_waiters even in home thread, Max Reitz, 2018/09/25
- [Qemu-devel] [PULL 23/42] job: Fix nested aio_poll() hanging in job_txn_apply, Max Reitz, 2018/09/25
- [Qemu-devel] [PULL 28/42] test-blockjob: Acquire AioContext around job_cancel_sync(), Max Reitz, 2018/09/25
- [Qemu-devel] [PULL 27/42] test-bdrv-drain: Drain with block jobs in an I/O thread, Max Reitz, 2018/09/25
- [Qemu-devel] [PULL 30/42] test-bdrv-drain: Test AIO_WAIT_WHILE() in completion callback, Max Reitz, 2018/09/25
- [Qemu-devel] [PULL 29/42] job: Use AIO_WAIT_WHILE() in job_finish_sync(), Max Reitz, 2018/09/25
- [Qemu-devel] [PULL 31/42] block: Add missing locking in bdrv_co_drain_bh_cb(), Max Reitz, 2018/09/25
- [Qemu-devel] [PULL 32/42] block-backend: Add .drained_poll callback, Max Reitz, 2018/09/25
- [Qemu-devel] [PULL 34/42] block-backend: Decrease in_flight only after callback, Max Reitz, 2018/09/25
- [Qemu-devel] [PULL 33/42] block-backend: Fix potential double blk_delete(),
Max Reitz <=
- [Qemu-devel] [PULL 35/42] blockjob: Lie better in child_job_drained_poll(), Max Reitz, 2018/09/25
- [Qemu-devel] [PULL 36/42] block: Remove aio_poll() in bdrv_drain_poll variants, Max Reitz, 2018/09/25
- [Qemu-devel] [PULL 38/42] job: Avoid deadlocks in job_completed_txn_abort(), Max Reitz, 2018/09/25
- [Qemu-devel] [PULL 37/42] test-bdrv-drain: Test nested poll in bdrv_drain_poll_top_level(), Max Reitz, 2018/09/25
- [Qemu-devel] [PULL 40/42] test-bdrv-drain: Fix outdated comments, Max Reitz, 2018/09/25
- [Qemu-devel] [PULL 39/42] test-bdrv-drain: AIO_WAIT_WHILE() in job .commit/.abort, Max Reitz, 2018/09/25
- [Qemu-devel] [PULL 42/42] test-bdrv-drain: Test draining job source child and parent, Max Reitz, 2018/09/25
- [Qemu-devel] [PULL 41/42] block: Use a single global AioWait, Max Reitz, 2018/09/25
- [Qemu-devel] [PULL 04/42] block/commit: refactor commit to use job callbacks, Max Reitz, 2018/09/25
- Re: [Qemu-devel] [PULL 00/42] Block patches, Peter Maydell, 2018/09/25