qcow2: Fix dangling pointer after reopen for 'file'
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>
This commit is contained in:
parent
a7cd44bef3
commit
bcfd86d6a6
@ -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;
|
||||
|
||||
@ -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:
|
||||
@ -1966,7 +1977,16 @@ fail:
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user