summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin Wolf <kwolf@redhat.com>2017-06-02 23:04:55 +0200
committerMichael Roth <mdroth@linux.vnet.ibm.com>2017-08-24 16:51:19 -0500
commitf28b8906dd38816ed4da5a98bdeb5ff797afae8a (patch)
treee10edbf98303eb667e21b452f0fc0c11e940bc01
parentbace1f90f9207ec79e9d28eb668532b43ac8b81f (diff)
downloadqemu-f28b8906dd38816ed4da5a98bdeb5ff797afae8a.tar.gz
commit: Fix use after free in completion
The final bdrv_set_backing_hd() could be working on already freed nodes because the commit job drops its references (through BlockBackends) to both overlay_bs and top already a bit earlier. One way to trigger the bug is hot unplugging a disk for which blockdev_mark_auto_del() cancels the block job. Fix this by taking BDS-level references while we're still using the nodes. Cc: qemu-stable@nongnu.org Signed-off-by: Kevin Wolf <kwolf@redhat.com> Reviewed-by: John Snow <jsnow@redhat.com> (cherry picked from commit 19ebd13ed45ad5d5f277f5914d55b83f13eb09eb) Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
-rw-r--r--block/commit.c7
1 files changed, 7 insertions, 0 deletions
diff --git a/block/commit.c b/block/commit.c
index 76a0d98c6f..3bae46e9dd 100644
--- a/block/commit.c
+++ b/block/commit.c
@@ -89,6 +89,10 @@ static void commit_complete(BlockJob *job, void *opaque)
int ret = data->ret;
bool remove_commit_top_bs = false;
+ /* Make sure overlay_bs and top stay around until bdrv_set_backing_hd() */
+ bdrv_ref(top);
+ bdrv_ref(overlay_bs);
+
/* Remove base node parent that still uses BLK_PERM_WRITE/RESIZE before
* the normal backing chain can be restored. */
blk_unref(s->base);
@@ -124,6 +128,9 @@ static void commit_complete(BlockJob *job, void *opaque)
if (remove_commit_top_bs) {
bdrv_set_backing_hd(overlay_bs, top, &error_abort);
}
+
+ bdrv_unref(overlay_bs);
+ bdrv_unref(top);
}
static void coroutine_fn commit_run(void *opaque)