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>
This commit is contained in:
Christian Brauner
2026-07-06 14:58:13 +01:00
committed by Markus Armbruster
parent 94c64bfb44
commit 4575407b93

View File

@@ -72,6 +72,9 @@ typedef struct QMPRequest QMPRequest;
QmpCommandList qmp_commands, qmp_cap_negotiation_commands;
/* Monitor being serviced by the dispatcher. Protected by BQL. */
static MonitorQMP *qmp_dispatcher_current_mon;
OBJECT_DEFINE_TYPE(MonitorQMP, monitor_qmp, MONITOR_QMP, MONITOR);
static void monitor_qmp_cleanup_req_queue_locked(MonitorQMP *mon);
@@ -369,6 +372,7 @@ void coroutine_fn monitor_qmp_dispatcher_co(void *data)
*/
mon = req_obj->mon;
qmp_dispatcher_current_mon = mon;
/*
* We need to resume the monitor if handle_qmp_command()
@@ -429,6 +433,7 @@ void coroutine_fn monitor_qmp_dispatcher_co(void *data)
}
qmp_request_free(req_obj);
qmp_dispatcher_current_mon = NULL;
}
qatomic_set(&qmp_dispatcher_co, NULL);
}
@@ -573,6 +578,11 @@ static void monitor_qmp_event(void *opaque, QEMUChrEvent event)
}
}
static bool monitor_qmp_dispatcher_is_servicing(MonitorQMP *mon)
{
return qmp_dispatcher_current_mon == mon;
}
static void monitor_qmp_setup_handlers_bh(void *opaque)
{
MonitorQMP *mon = opaque;
@@ -645,6 +655,13 @@ static void monitor_qmp_complete(UserCreatable *uc, Error **errp)
static bool monitor_qmp_prepare_delete(UserCreatable *uc, Error **errp)
{
MonitorQMP *qmp = MONITOR_QMP(uc);
if (monitor_qmp_dispatcher_is_servicing(qmp)) {
error_setg(errp, "Cannot delete the current QMP monitor");
return false;
}
error_setg(errp, "Deleting QMP monitors is not supported");
return false;
}