Peter Xu <[email protected]> writes:

> current_migration is never reset, even if the migration object is freed
> already.  It means anyone references that can trigger UAF and it'll be hard
> to debug.
>
> Properly clear the pointer now, so far the only way to do is via
> finalize() as we know there's only one instance of it, meanwhile QEMU won't
> know who holds the refcount, so it can't reset the variable manually but
> only in finalize().
>
> To make it more readable, also initialize the variable in the
> instance_init() so it's very well paired at least.
>
> Signed-off-by: Peter Xu <[email protected]>
> ---
>  migration/migration.c | 23 ++++++++++++++++++++---
>  1 file changed, 20 insertions(+), 3 deletions(-)
>
> diff --git a/migration/migration.c b/migration/migration.c
> index 1b5285af95..74812ca785 100644
> --- a/migration/migration.c
> +++ b/migration/migration.c
> @@ -233,9 +233,11 @@ static int migration_stop_vm(MigrationState *s, RunState 
> state)
>  
>  void migration_object_init(void)
>  {
> -    /* This can only be called once. */
> -    assert(!current_migration);
> -    current_migration = MIGRATION_OBJ(object_new(TYPE_MIGRATION));
> +    /* This creates the singleton migration object */
> +    object_new(TYPE_MIGRATION);
> +
> +    /* This should be set now when initialize the singleton object */
> +    assert(current_migration);
>  
>      /*
>       * Init the migrate incoming object as well no matter whether
> @@ -3886,12 +3888,27 @@ static void migration_instance_finalize(Object *obj)
>      qemu_sem_destroy(&ms->rp_state.rp_pong_acks);
>      qemu_sem_destroy(&ms->postcopy_qemufile_src_sem);
>      error_free(ms->error);
> +
> +    /*
> +     * We know we only have one intance of migration, and when reaching

instance

> +     * here it means migration object is gone.  Clear the global reference
> +     * to reflect that.

Not really gone at this point. The free only happens when this function
returns.

> +     */
> +    current_migration = NULL;
>  }
>  
>  static void migration_instance_init(Object *obj)
>  {
>      MigrationState *ms = MIGRATION_OBJ(obj);
>  
> +    /*
> +     * There can only be one migration object globally. Keep a record of
> +     * the pointer in current_migration, which will be reset after the
> +     * object finalize().
> +     */
> +    assert(!current_migration);
> +    current_migration = ms;
> +
>      ms->state = MIGRATION_STATUS_NONE;
>      ms->mbps = -1;
>      ms->pages_per_second = -1;

Reply via email to