03cc27
From 5975af3d23091c73737968cea32490bca31c0479 Mon Sep 17 00:00:00 2001
03cc27
Message-Id: <5975af3d23091c73737968cea32490bca31c0479@dist-git>
03cc27
From: Jonathon Jongsma <jjongsma@redhat.com>
03cc27
Date: Fri, 1 May 2020 16:53:37 -0500
03cc27
Subject: [PATCH] qemu: don't take agent and monitor job for shutdown
03cc27
03cc27
We have to assume that the guest agent may be malicious so we don't want
03cc27
to allow any agent queries to block any other libvirt API. By holding
03cc27
a monitor job while we're querying the agent, we open ourselves up to a
03cc27
DoS.  So split the function into separate parts: one that does the agent
03cc27
shutdown and one that does the monitor shutdown. Each part holds only a
03cc27
job of the appropriate type.
03cc27
03cc27
Signed-off-by: Jonathon Jongsma <jjongsma@redhat.com>
03cc27
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
03cc27
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
03cc27
(cherry picked from commit 1cb8bc52c1035573a0c1a87f724a6c7dfee82f12)
03cc27
03cc27
CVE-2019-20485
03cc27
03cc27
Signed-off-by: Jonathon Jongsma <jjongsma@redhat.com>
03cc27
Message-Id: <20200501215341.27683-2-jjongsma@redhat.com>
03cc27
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
03cc27
---
03cc27
 src/qemu/qemu_driver.c | 121 ++++++++++++++++++++++++++---------------
03cc27
 1 file changed, 77 insertions(+), 44 deletions(-)
03cc27
03cc27
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
03cc27
index 2852b96edd..bdc955e1fa 100644
03cc27
--- a/src/qemu/qemu_driver.c
03cc27
+++ b/src/qemu/qemu_driver.c
03cc27
@@ -1913,6 +1913,77 @@ static int qemuDomainResume(virDomainPtr dom)
03cc27
     return ret;
03cc27
 }
03cc27
 
03cc27
+
03cc27
+static int
03cc27
+qemuDomainShutdownFlagsAgent(virQEMUDriverPtr driver,
03cc27
+                             virDomainObjPtr vm,
03cc27
+                             bool isReboot,
03cc27
+                             bool reportError)
03cc27
+{
03cc27
+    int ret = -1;
03cc27
+    qemuAgentPtr agent;
03cc27
+    int agentFlag = isReboot ?  QEMU_AGENT_SHUTDOWN_REBOOT :
03cc27
+        QEMU_AGENT_SHUTDOWN_POWERDOWN;
03cc27
+
03cc27
+    if (qemuDomainObjBeginAgentJob(driver, vm,
03cc27
+                                   QEMU_AGENT_JOB_MODIFY) < 0)
03cc27
+        goto cleanup;
03cc27
+
03cc27
+    if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_RUNNING) {
03cc27
+        virReportError(VIR_ERR_OPERATION_INVALID,
03cc27
+                       "%s", _("domain is not running"));
03cc27
+        goto endjob;
03cc27
+    }
03cc27
+
03cc27
+    if (!qemuDomainAgentAvailable(vm, reportError))
03cc27
+        goto endjob;
03cc27
+
03cc27
+    qemuDomainSetFakeReboot(driver, vm, false);
03cc27
+    agent = qemuDomainObjEnterAgent(vm);
03cc27
+    ret = qemuAgentShutdown(agent, agentFlag);
03cc27
+    qemuDomainObjExitAgent(vm, agent);
03cc27
+
03cc27
+ endjob:
03cc27
+    qemuDomainObjEndAgentJob(vm);
03cc27
+
03cc27
+ cleanup:
03cc27
+    return ret;
03cc27
+}
03cc27
+
03cc27
+
03cc27
+static int
03cc27
+qemuDomainShutdownFlagsMonitor(virQEMUDriverPtr driver,
03cc27
+                               virDomainObjPtr vm,
03cc27
+                               bool isReboot)
03cc27
+{
03cc27
+    int ret = -1;
03cc27
+    qemuDomainObjPrivatePtr priv;
03cc27
+
03cc27
+    priv = vm->privateData;
03cc27
+
03cc27
+    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
03cc27
+        goto cleanup;
03cc27
+
03cc27
+    if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_RUNNING) {
03cc27
+        virReportError(VIR_ERR_OPERATION_INVALID,
03cc27
+                       "%s", _("domain is not running"));
03cc27
+        goto endjob;
03cc27
+    }
03cc27
+
03cc27
+    qemuDomainSetFakeReboot(driver, vm, isReboot);
03cc27
+    qemuDomainObjEnterMonitor(driver, vm);
03cc27
+    ret = qemuMonitorSystemPowerdown(priv->mon);
03cc27
+    if (qemuDomainObjExitMonitor(driver, vm) < 0)
03cc27
+        ret = -1;
03cc27
+
03cc27
+ endjob:
03cc27
+    qemuDomainObjEndJob(driver, vm);
03cc27
+
03cc27
+ cleanup:
03cc27
+    return ret;
03cc27
+}
03cc27
+
03cc27
+
03cc27
 static int qemuDomainShutdownFlags(virDomainPtr dom, unsigned int flags)
03cc27
 {
03cc27
     virQEMUDriverPtr driver = dom->conn->privateData;
03cc27
@@ -1922,8 +1993,6 @@ static int qemuDomainShutdownFlags(virDomainPtr dom, unsigned int flags)
03cc27
     bool useAgent = false, agentRequested, acpiRequested;
03cc27
     bool isReboot = false;
03cc27
     bool agentForced;
03cc27
-    qemuDomainAgentJob agentJob = QEMU_AGENT_JOB_NONE;
03cc27
-    int agentFlag = QEMU_AGENT_SHUTDOWN_POWERDOWN;
03cc27
 
03cc27
     virCheckFlags(VIR_DOMAIN_SHUTDOWN_ACPI_POWER_BTN |
03cc27
                   VIR_DOMAIN_SHUTDOWN_GUEST_AGENT, -1);
03cc27
@@ -1934,7 +2003,6 @@ static int qemuDomainShutdownFlags(virDomainPtr dom, unsigned int flags)
03cc27
     if (vm->def->onPoweroff == VIR_DOMAIN_LIFECYCLE_ACTION_RESTART ||
03cc27
         vm->def->onPoweroff == VIR_DOMAIN_LIFECYCLE_ACTION_RESTART_RENAME) {
03cc27
         isReboot = true;
03cc27
-        agentFlag = QEMU_AGENT_SHUTDOWN_REBOOT;
03cc27
         VIR_INFO("Domain on_poweroff setting overridden, attempting reboot");
03cc27
     }
03cc27
 
03cc27
@@ -1949,62 +2017,27 @@ static int qemuDomainShutdownFlags(virDomainPtr dom, unsigned int flags)
03cc27
     if (virDomainShutdownFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
03cc27
         goto cleanup;
03cc27
 
03cc27
-    if (useAgent)
03cc27
-        agentJob = QEMU_AGENT_JOB_MODIFY;
03cc27
-
03cc27
-    if (qemuDomainObjBeginJobWithAgent(driver, vm,
03cc27
-                                       QEMU_JOB_MODIFY,
03cc27
-                                       agentJob) < 0)
03cc27
-        goto cleanup;
03cc27
-
03cc27
-    if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_RUNNING) {
03cc27
-        virReportError(VIR_ERR_OPERATION_INVALID,
03cc27
-                       "%s", _("domain is not running"));
03cc27
-        goto endjob;
03cc27
-    }
03cc27
-
03cc27
     agentForced = agentRequested && !acpiRequested;
03cc27
-    if (!qemuDomainAgentAvailable(vm, agentForced)) {
03cc27
-        if (agentForced)
03cc27
-            goto endjob;
03cc27
-        useAgent = false;
03cc27
-    }
03cc27
-
03cc27
-
03cc27
     if (useAgent) {
03cc27
-        qemuAgentPtr agent;
03cc27
-        qemuDomainSetFakeReboot(driver, vm, false);
03cc27
-        agent = qemuDomainObjEnterAgent(vm);
03cc27
-        ret = qemuAgentShutdown(agent, agentFlag);
03cc27
-        qemuDomainObjExitAgent(vm, agent);
03cc27
+        ret = qemuDomainShutdownFlagsAgent(driver, vm, isReboot, agentForced);
03cc27
+        if (ret < 0 && agentForced)
03cc27
+            goto cleanup;
03cc27
     }
03cc27
 
03cc27
     /* If we are not enforced to use just an agent, try ACPI
03cc27
      * shutdown as well in case agent did not succeed.
03cc27
      */
03cc27
-    if (!useAgent ||
03cc27
-        (ret < 0 && (acpiRequested || !flags))) {
03cc27
-
03cc27
+    if (!useAgent || (ret < 0 && (acpiRequested || !flags))) {
03cc27
         /* Even if agent failed, we have to check if guest went away
03cc27
          * by itself while our locks were down.  */
03cc27
         if (useAgent && !virDomainObjIsActive(vm)) {
03cc27
             ret = 0;
03cc27
-            goto endjob;
03cc27
+            goto cleanup;
03cc27
         }
03cc27
 
03cc27
-        qemuDomainSetFakeReboot(driver, vm, isReboot);
03cc27
-        qemuDomainObjEnterMonitor(driver, vm);
03cc27
-        ret = qemuMonitorSystemPowerdown(priv->mon);
03cc27
-        if (qemuDomainObjExitMonitor(driver, vm) < 0)
03cc27
-            ret = -1;
03cc27
+        ret = qemuDomainShutdownFlagsMonitor(driver, vm, isReboot);
03cc27
     }
03cc27
 
03cc27
- endjob:
03cc27
-    if (agentJob)
03cc27
-        qemuDomainObjEndJobWithAgent(driver, vm);
03cc27
-    else
03cc27
-        qemuDomainObjEndJob(driver, vm);
03cc27
-
03cc27
  cleanup:
03cc27
     virDomainObjEndAPI(&vm;;
03cc27
     return ret;
03cc27
-- 
03cc27
2.26.2
03cc27