diff options
author | Kevin Wolf <kwolf@redhat.com> | 2017-06-02 23:04:55 +0200 |
---|---|---|
committer | Kevin Wolf <kwolf@redhat.com> | 2017-06-09 13:46:13 +0200 |
commit | 19ebd13ed45ad5d5f277f5914d55b83f13eb09eb (patch) | |
tree | ee37d5d3330a0e7824b4fd5aa377d0a6c92b6d30 /block/commit.c | |
parent | 49695eeb7485f1c45c288e741ae6b939c7bfb2a6 (diff) |
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>
Diffstat (limited to 'block/commit.c')
-rw-r--r-- | block/commit.c | 7 |
1 files changed, 7 insertions, 0 deletions
diff --git a/block/commit.c b/block/commit.c index a3028b20f3..af6fa68cf3 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) |