@samitouri / QOSamiQemu / commits / 4575407b93

monitor: reject attempts to delete the current monitor

If an 'object_del' command for a QMP monitor arrives targetting the current monitor, reject this request. If the current monitor is deleted, it will be impossible to send any reply and the client won't be able to remove the corresponding chardev backend. Note, it is not possible to rely on checking monitor_cur() because if 'object_del' is called via human-monitor-command, monitor_cur() will reflect the temporary HMP, not the QMP target that needs to be checked. Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org> [DB: extracted monitor tracking from larger commit; added logic to monitor_qmp_prepare_delete to reject request] Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com> Tested-by: Peter Krempa <pkrempa@redhat.com> Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> Message-ID: <20260706135824.2623960-26-berrange@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>

Christian Brauner committed Jul 6, 2026 at 14:58 UTC 4575407b932c81805a24d07505f39b8ae5aa7e2c
1 file changed +17
monitor/qmp.c
+17
@@ -72,6 +72,9 @@ typedef struct QMPRequest QMPRequest;
72
73 QmpCommandList qmp_commands, qmp_cap_negotiation_commands;
74
75 +/* Monitor being serviced by the dispatcher. Protected by BQL. */
76 +static MonitorQMP *qmp_dispatcher_current_mon;
77 +
78 OBJECT_DEFINE_TYPE(MonitorQMP, monitor_qmp, MONITOR_QMP, MONITOR);
79
80 static void monitor_qmp_cleanup_req_queue_locked(MonitorQMP *mon);
@@ -369,6 +372,7 @@ void coroutine_fn monitor_qmp_dispatcher_co(void *data)
372 */
373
374 mon = req_obj->mon;
375 + qmp_dispatcher_current_mon = mon;
376
377 /*
378 * We need to resume the monitor if handle_qmp_command()
@@ -429,6 +433,7 @@ void coroutine_fn monitor_qmp_dispatcher_co(void *data)
433 }
434
435 qmp_request_free(req_obj);
436 + qmp_dispatcher_current_mon = NULL;
437 }
438 qatomic_set(&qmp_dispatcher_co, NULL);
439 }
@@ -573,6 +578,11 @@ static void monitor_qmp_event(void *opaque, QEMUChrEvent event)
578 }
579 }
580
581 +static bool monitor_qmp_dispatcher_is_servicing(MonitorQMP *mon)
582 +{
583 + return qmp_dispatcher_current_mon == mon;
584 +}
585 +
586 static void monitor_qmp_setup_handlers_bh(void *opaque)
587 {
588 MonitorQMP *mon = opaque;
@@ -645,6 +655,13 @@ static void monitor_qmp_complete(UserCreatable *uc, Error **errp)
655
656 static bool monitor_qmp_prepare_delete(UserCreatable *uc, Error **errp)
657 {
658 + MonitorQMP *qmp = MONITOR_QMP(uc);
659 +
660 + if (monitor_qmp_dispatcher_is_servicing(qmp)) {
661 + error_setg(errp, "Cannot delete the current QMP monitor");
662 + return false;
663 + }
664 +
665 error_setg(errp, "Deleting QMP monitors is not supported");
666 return false;
667 }