@samitouri / QOSamiQemu / commits / abc177e885

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);