From: Christian Brauner <brauner@kernel.org> 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] Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> --- monitor/qmp.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/monitor/qmp.c b/monitor/qmp.c index ff39b8cda4..7d80a9bd57 100644 --- a/monitor/qmp.c +++ b/monitor/qmp.c @@ -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; } -- 2.54.0