net/colo-compare: guard finalize against uninitialized state
colo_compare_finalize() assumes the object was fully set up by colo_compare_complete(), but a bare object_new() followed by object_unref() skips the complete callback entirely. This causes two crashes: - qemu_mutex_destroy on the static event_mtx which was never initialized (colo_compare_active is false) - qemu_bh_delete(NULL) and iothread dereference when s->iothread is NULL Guard the event_mtx teardown with colo_compare_active, and the iothread-dependent cleanup with an s->iothread NULL check. Fixes: 45942b79b9f8 ("net/colo-compare.c: Check that colo-compare is active") Cc: peterx@redhat.com Acked-by: Peter Xu <peterx@redhat.com> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Marc-André Lureau committed
Apr 25, 2026 at 01:00 UTC
abc177e885c379d66f38db4436a977953362e718
1 file changed
+15
-16
net/colo-compare.c
+15
-16
@@ -1416,7 +1416,7 @@ static void colo_compare_finalize(Object *obj)
1416
break;
1417
}
1418
}
1419
- if (QTAILQ_EMPTY(&net_compares)) {
1419
+ if (colo_compare_active && QTAILQ_EMPTY(&net_compares)) {
1420
colo_compare_active = false;
1421
qemu_mutex_destroy(&event_mtx);
1422
qemu_cond_destroy(&event_complete_cond);
@@ -1431,30 +1431,29 @@ static void colo_compare_finalize(Object *obj)
1431
}
1432
1433
colo_compare_timer_del(s);
1434
+ g_clear_pointer(&s->event_bh, qemu_bh_delete);
1435
1435
- qemu_bh_delete(s->event_bh);
1436
+ if (s->iothread) {
1437
+ AioContext *ctx = iothread_get_aio_context(s->iothread);
1438
1437
- AioContext *ctx = iothread_get_aio_context(s->iothread);
1438
- AIO_WAIT_WHILE(ctx, !s->out_sendco.done);
1439
- if (s->notify_dev) {
1440
- AIO_WAIT_WHILE(ctx, !s->notify_sendco.done);
1441
- }
1439
+ AIO_WAIT_WHILE(ctx, !s->out_sendco.done);
1440
+ if (s->notify_dev) {
1441
+ AIO_WAIT_WHILE(ctx, !s->notify_sendco.done);
1442
+ }
1443
+
1444
+ /* Release all unhandled packets after compare thread exited */
1445
+ g_queue_foreach(&s->conn_list, colo_flush_packets, s);
1446
+ AIO_WAIT_WHILE(NULL, !s->out_sendco.done);
1447
1443
- /* Release all unhandled packets after compare thead exited */
1444
- g_queue_foreach(&s->conn_list, colo_flush_packets, s);
1445
- AIO_WAIT_WHILE(NULL, !s->out_sendco.done);
1448
+ object_unref(OBJECT(s->iothread));
1449
+ }
1450
1451
g_queue_clear(&s->conn_list);
1452
g_queue_clear(&s->out_sendco.send_list);
1453
if (s->notify_dev) {
1454
g_queue_clear(&s->notify_sendco.send_list);
1455
}
1452
-
1453
- if (s->connection_track_table) {
1454
- g_hash_table_destroy(s->connection_track_table);
1455
- }
1456
-
1457
- object_unref(OBJECT(s->iothread));
1456
+ g_clear_pointer(&s->connection_track_table, g_hash_table_destroy);
1457
1458
g_free(s->pri_indev);
1459
g_free(s->sec_indev);