Skip to content

Commit

Permalink
qcow2: Fix dangling pointer after reopen for 'file'
Browse files Browse the repository at this point in the history
Without an external data file, s->data_file is a second pointer with the
same value as bs->file. When changing bs->file to a different BdrvChild
and freeing the old BdrvChild, s->data_file must also be updated,
otherwise it points to freed memory and causes crashes.

This problem was caught by iotests case 245.

Fixes: df2b7086f169239ebad5d150efa29c9bb6d4f820
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Message-Id: <20210708114709.206487-2-kwolf@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
  • Loading branch information
kevmw committed Jul 9, 2021
1 parent a7cd44b commit bcfd86d
Showing 1 changed file with 29 additions and 0 deletions.
29 changes: 29 additions & 0 deletions block/qcow2.c
Expand Up @@ -1926,6 +1926,7 @@ static void qcow2_refresh_limits(BlockDriverState *bs, Error **errp)
static int qcow2_reopen_prepare(BDRVReopenState *state,
BlockReopenQueue *queue, Error **errp)
{
BDRVQcow2State *s = state->bs->opaque;
Qcow2ReopenState *r;
int ret;

Expand Down Expand Up @@ -1956,6 +1957,16 @@ static int qcow2_reopen_prepare(BDRVReopenState *state,
}
}

/*
* Without an external data file, s->data_file points to the same BdrvChild
* as bs->file. It needs to be resynced after reopen because bs->file may
* be changed. We can't use it in the meantime.
*/
if (!has_data_file(state->bs)) {
assert(s->data_file == state->bs->file);
s->data_file = NULL;
}

return 0;

fail:
Expand All @@ -1966,7 +1977,16 @@ static int qcow2_reopen_prepare(BDRVReopenState *state,

static void qcow2_reopen_commit(BDRVReopenState *state)
{
BDRVQcow2State *s = state->bs->opaque;

qcow2_update_options_commit(state->bs, state->opaque);
if (!s->data_file) {
/*
* If we don't have an external data file, s->data_file was cleared by
* qcow2_reopen_prepare() and needs to be updated.
*/
s->data_file = state->bs->file;
}
g_free(state->opaque);
}

Expand All @@ -1990,6 +2010,15 @@ static void qcow2_reopen_commit_post(BDRVReopenState *state)

static void qcow2_reopen_abort(BDRVReopenState *state)
{
BDRVQcow2State *s = state->bs->opaque;

if (!s->data_file) {
/*
* If we don't have an external data file, s->data_file was cleared by
* qcow2_reopen_prepare() and needs to be restored.
*/
s->data_file = state->bs->file;
}
qcow2_update_options_abort(state->bs, state->opaque);
g_free(state->opaque);
}
Expand Down

0 comments on commit bcfd86d

Please sign in to comment.