Skip to content

Commit d657a14

Browse files
xzpeterFabiano Rosas
authored andcommitted
migration: Fix UAF for incoming migration on MigrationState
On the incoming migration side, QEMU uses a coroutine to load all the VM states. Inside, it may reference MigrationState on global states like migration capabilities, parameters, error state, shared mutexes and more. However there's nothing yet to make sure MigrationState won't get destroyed (e.g. after migration_shutdown()). Meanwhile there's also no API available to remove the incoming coroutine in migration_shutdown(), avoiding it to access the freed elements. There's a bug report showing this can happen and crash dest QEMU when migration is cancelled on source. When it happens, the dest main thread is trying to cleanup everything: #0 qemu_aio_coroutine_enter #1 aio_dispatch_handler #2 aio_poll #3 monitor_cleanup #4 qemu_cleanup #5 qemu_default_main Then it found the migration incoming coroutine, schedule it (even after migration_shutdown()), causing crash: #0 __pthread_kill_implementation #1 __pthread_kill_internal #2 __GI_raise #3 __GI_abort #4 __assert_fail_base #5 __assert_fail #6 qemu_mutex_lock_impl #7 qemu_lockable_mutex_lock #8 qemu_lockable_lock #9 qemu_lockable_auto_lock #10 migrate_set_error #11 process_incoming_migration_co #12 coroutine_trampoline To fix it, take a refcount after an incoming setup is properly done when qmp_migrate_incoming() succeeded the 1st time. As it's during a QMP handler which needs BQL, it means the main loop is still alive (without going into cleanups, which also needs BQL). Releasing the refcount now only until the incoming migration coroutine finished or failed. Hence the refcount is valid for both (1) setup phase of incoming ports, mostly IO watches (e.g. qio_channel_add_watch_full()), and (2) the incoming coroutine itself (process_incoming_migration_co()). Note that we can't unref in migration_incoming_state_destroy(), because both qmp_xen_load_devices_state() and load_snapshot() will use it without an incoming migration. Those hold BQL so they're not prone to this issue. PS: I suspect nobody uses Xen's command at all, as it didn't register yank, hence AFAIU the command should crash on master when trying to unregister yank in migration_incoming_state_destroy().. but that's another story. Also note that in some incoming failure cases we may not always unref the MigrationState refcount, which is a trade-off to keep things simple. We could make it accurate, but it can be an overkill. Some examples: - Unlike most of the rest protocols, socket_start_incoming_migration() may create net listener after incoming port setup sucessfully. It means we can't unref in migration_channel_process_incoming() as a generic path because socket protocol might keep using MigrationState. - For either socket or file, multiple IO watches might be created, it means logically each IO watch needs to take one refcount for MigrationState so as to be 100% accurate on ownership of refcount taken. In general, we at least need per-protocol handling to make it accurate, which can be an overkill if we know incoming failed after all. Add a short comment to explain that when taking the refcount in qmp_migrate_incoming(). Bugzilla: https://issues.redhat.com/browse/RHEL-69775 Tested-by: Yan Fu <[email protected]> Signed-off-by: Peter Xu <[email protected]> Reviewed-by: Fabiano Rosas <[email protected]> Message-ID: <[email protected]> Signed-off-by: Fabiano Rosas <[email protected]>
1 parent 5136598 commit d657a14

File tree

1 file changed

+38
-2
lines changed

1 file changed

+38
-2
lines changed

migration/migration.c

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,27 @@ static void migration_downtime_start(MigrationState *s)
116116
s->downtime_start = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
117117
}
118118

119+
/*
120+
* This is unfortunate: incoming migration actually needs the outgoing
121+
* migration state (MigrationState) to be there too, e.g. to query
122+
* capabilities, parameters, using locks, setup errors, etc.
123+
*
124+
* NOTE: when calling this, making sure current_migration exists and not
125+
* been freed yet! Otherwise trying to access the refcount is already
126+
* an use-after-free itself..
127+
*
128+
* TODO: Move shared part of incoming / outgoing out into separate object.
129+
* Then this is not needed.
130+
*/
131+
static void migrate_incoming_ref_outgoing_state(void)
132+
{
133+
object_ref(migrate_get_current());
134+
}
135+
static void migrate_incoming_unref_outgoing_state(void)
136+
{
137+
object_unref(migrate_get_current());
138+
}
139+
119140
static void migration_downtime_end(MigrationState *s)
120141
{
121142
int64_t now = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
@@ -863,7 +884,7 @@ process_incoming_migration_co(void *opaque)
863884
* postcopy thread.
864885
*/
865886
trace_process_incoming_migration_co_postcopy_end_main();
866-
return;
887+
goto out;
867888
}
868889
/* Else if something went wrong then just fall out of the normal exit */
869890
}
@@ -879,7 +900,8 @@ process_incoming_migration_co(void *opaque)
879900
}
880901

881902
migration_bh_schedule(process_incoming_migration_bh, mis);
882-
return;
903+
goto out;
904+
883905
fail:
884906
migrate_set_state(&mis->state, MIGRATION_STATUS_ACTIVE,
885907
MIGRATION_STATUS_FAILED);
@@ -896,6 +918,9 @@ process_incoming_migration_co(void *opaque)
896918

897919
exit(EXIT_FAILURE);
898920
}
921+
out:
922+
/* Pairs with the refcount taken in qmp_migrate_incoming() */
923+
migrate_incoming_unref_outgoing_state();
899924
}
900925

901926
/**
@@ -1901,6 +1926,17 @@ void qmp_migrate_incoming(const char *uri, bool has_channels,
19011926
return;
19021927
}
19031928

1929+
/*
1930+
* Making sure MigrationState is available until incoming migration
1931+
* completes.
1932+
*
1933+
* NOTE: QEMU _might_ leak this refcount in some failure paths, but
1934+
* that's OK. This is the minimum change we need to at least making
1935+
* sure success case is clean on the refcount. We can try harder to
1936+
* make it accurate for any kind of failures, but it might be an
1937+
* overkill and doesn't bring us much benefit.
1938+
*/
1939+
migrate_incoming_ref_outgoing_state();
19041940
once = false;
19051941
}
19061942

0 commit comments

Comments
 (0)