Read-only connections currently cannot use qemu-monitor-command even for HMP "info" commands, which only query QEMU state.
Allow HMP commands whose first token is exactly "info" on read-only connections. Keep QMP commands, file descriptor passing, and all other HMP commands restricted to read-write connections. Signed-off-by: Siddhi Katage <[email protected]> --- src/libvirt-qemu.c | 13 +++++++++++-- src/libvirt_private.syms | 1 + src/qemu/qemu_driver.c | 21 +++++++++++++++++++-- src/util/virqemu.c | 21 +++++++++++++++++++++ src/util/virqemu.h | 2 ++ 5 files changed, 54 insertions(+), 4 deletions(-) diff --git a/src/libvirt-qemu.c b/src/libvirt-qemu.c index 2898b71983..d38b747b44 100644 --- a/src/libvirt-qemu.c +++ b/src/libvirt-qemu.c @@ -25,6 +25,7 @@ #include "virlog.h" #include "viruuid.h" #include "datatypes.h" +#include "virqemu.h" #define VIR_FROM_THIS VIR_FROM_NONE @@ -77,8 +78,12 @@ virDomainQemuMonitorCommand(virDomainPtr domain, const char *cmd, virCheckDomainReturn(domain, -1); conn = domain->conn; + virCheckNonNullArgGoto(cmd, error); virCheckNonNullArgGoto(result, error); - virCheckReadOnlyGoto(conn->flags, error); + + if (!(flags & VIR_DOMAIN_QEMU_MONITOR_COMMAND_HMP) || + !virQEMUHMPCommandIsInfo(cmd)) + virCheckReadOnlyGoto(conn->flags, error); if (conn->driver->domainQemuMonitorCommand) { int ret; @@ -170,7 +175,11 @@ virDomainQemuMonitorCommandWithFiles(virDomainPtr domain, } virCheckNonNullArgGoto(result, error); - virCheckReadOnlyGoto(conn->flags, error); + + if (ninfiles > 0 || outfiles || + !(flags & VIR_DOMAIN_QEMU_MONITOR_COMMAND_HMP) || + !virQEMUHMPCommandIsInfo(cmd)) + virCheckReadOnlyGoto(conn->flags, error); if (conn->driver->domainQemuMonitorCommandWithFiles) { int ret; diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 30c4564456..6f7505ecde 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -3351,6 +3351,7 @@ virQEMUBuildBufferEscapeComma; virQEMUBuildCommandLineJSON; virQEMUBuildCommandLineJSONArrayNumbered; virQEMUBuildCommandLineJSONArrayObjectsStr; +virQEMUHMPCommandIsInfo; # util/virrandom.h diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 544955ecf9..2f542e0b8a 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -100,6 +100,7 @@ #include "vircgroup.h" #include "virperf.h" #include "virnuma.h" +#include "virqemu.h" #include "netdev_bandwidth_conf.h" #include "virdomainsnapshotobjlist.h" #include "virenum.h" @@ -13752,6 +13753,14 @@ qemuDomainBackupGetXMLDesc(virDomainPtr domain, #define QEMU_DOMAIN_MONITOR_COMMAND_FLAGS \ VIR_DOMAIN_QEMU_MONITOR_COMMAND_HMP +static int +qemuMonitorDomainGetInfo(virConnectPtr conn, + virDomainDef *def) +{ + return virDomainGetInfoEnsureACL(conn, def); +} + + static int qemuDomainQemuMonitorCommandWithFiles(virDomainPtr domain, const char *cmd, @@ -13789,8 +13798,16 @@ qemuDomainQemuMonitorCommandWithFiles(virDomainPtr domain, if (!(vm = qemuDomainObjFromDomain(domain))) goto cleanup; - if (virDomainQemuMonitorCommandWithFilesEnsureACL(domain->conn, vm->def) < 0) - goto cleanup; + /* HMP "info" commands only query QEMU state, so read access is enough. */ + if (ninfds == 0 && !outfds && + (flags & VIR_DOMAIN_QEMU_MONITOR_COMMAND_HMP) && + virQEMUHMPCommandIsInfo(cmd)) { + if (qemuMonitorDomainGetInfo(domain->conn, vm->def) < 0) + goto cleanup; + } else { + if (virDomainQemuMonitorCommandWithFilesEnsureACL(domain->conn, vm->def) < 0) + goto cleanup; + } if (virDomainObjBeginJob(vm, VIR_JOB_QUERY) < 0) goto cleanup; diff --git a/src/util/virqemu.c b/src/util/virqemu.c index d2a69026c8..74f3729b67 100644 --- a/src/util/virqemu.c +++ b/src/util/virqemu.c @@ -32,6 +32,27 @@ VIR_LOG_INIT("util.qemu"); + +bool +virQEMUHMPCommandIsInfo(const char *cmd) +{ + g_autofree char *trimmed = g_strdup(cmd); + const char *args; + + if (!trimmed) + return false; + + g_strstrip(trimmed); + + if (!STRPREFIX(trimmed, "info")) + return false; + + args = trimmed + strlen("info"); + + return *args == '\0' || g_ascii_isspace(*args); +} + + struct virQEMUCommandLineJSONIteratorData { const char *prefix; virBuffer *buf; diff --git a/src/util/virqemu.h b/src/util/virqemu.h index e5d36b95c4..b9e79fb9b6 100644 --- a/src/util/virqemu.h +++ b/src/util/virqemu.h @@ -42,3 +42,5 @@ int virQEMUBuildCommandLineJSON(virJSONValue *value, virQEMUBuildCommandLineJSONArrayFormatFunc array); void virQEMUBuildBufferEscapeComma(virBuffer *buf, const char *str); + +bool virQEMUHMPCommandIsInfo(const char *cmd); -- 2.47.3
