diff mbox series

[RFC,v2,7/7] migration: Reset current_migration properly

Message ID 20241029211607.2114845-8-peterx@redhat.com (mailing list archive)
State New
Headers show
Series QOM: Singleton interface | expand

Commit Message

Peter Xu Oct. 29, 2024, 9:16 p.m. UTC
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 place to do is via its own
finalize(), which means QEMU is releasing the last refcount and right
before freeing the object memory.  Meanwhile, QEMU won't know who holds the
last refcount, so it can't reset the variable manually / explicitly.

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 <peterx@redhat.com>
---
 migration/migration.c | 23 ++++++++++++++++++++---
 1 file changed, 20 insertions(+), 3 deletions(-)
diff mbox series

Patch

diff --git a/migration/migration.c b/migration/migration.c
index f4456f7142..70b9ef8228 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
@@ -3864,12 +3866,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 instance of migration, and when reaching
+     * here it means migration object is going away.  Clear the global
+     * reference to reflect that.
+     */
+    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;