03cc27
From ff8c9ca6d8b5e74d59013d063cc12323622d8fb1 Mon Sep 17 00:00:00 2001
03cc27
Message-Id: <ff8c9ca6d8b5e74d59013d063cc12323622d8fb1@dist-git>
03cc27
From: Jonathon Jongsma <jjongsma@redhat.com>
03cc27
Date: Fri, 1 May 2020 16:53:41 -0500
03cc27
Subject: [PATCH] qemu: remove qemuDomainObjBegin/EndJobWithAgent()
03cc27
03cc27
This function potentially grabs both a monitor job and an agent job at
03cc27
the same time. This is problematic because it means that a malicious (or
03cc27
just buggy) guest agent can cause a denial of service on the host. The
03cc27
presence of this function makes it easy to do the wrong thing and hold
03cc27
both jobs at the same time. All existing uses have already been removed
03cc27
by previous commits.
03cc27
03cc27
Signed-off-by: Jonathon Jongsma <jjongsma@redhat.com>
03cc27
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
03cc27
(cherry picked from commit 3c436c22a4f94c85c2b5e7b5fb84af48219d78e3)
03cc27
03cc27
CVE-2019-20485
03cc27
03cc27
Signed-off-by: Jonathon Jongsma <jjongsma@redhat.com>
03cc27
Message-Id: <20200501215341.27683-6-jjongsma@redhat.com>
03cc27
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
03cc27
---
03cc27
 src/qemu/THREADS.txt   | 58 +++++-------------------------------------
03cc27
 src/qemu/qemu_domain.c | 56 ++++------------------------------------
03cc27
 src/qemu/qemu_domain.h |  7 -----
03cc27
 3 files changed, 11 insertions(+), 110 deletions(-)
03cc27
03cc27
diff --git a/src/qemu/THREADS.txt b/src/qemu/THREADS.txt
03cc27
index d17f3f4e0c..b34235075a 100644
03cc27
--- a/src/qemu/THREADS.txt
03cc27
+++ b/src/qemu/THREADS.txt
03cc27
@@ -71,11 +71,12 @@ There are a number of locks on various objects
03cc27
 
03cc27
     Agent job condition is then used when thread wishes to talk to qemu
03cc27
     agent monitor. It is possible to acquire just agent job
03cc27
-    (qemuDomainObjBeginAgentJob), or only normal job
03cc27
-    (qemuDomainObjBeginJob) or both at the same time
03cc27
-    (qemuDomainObjBeginJobWithAgent). Which type of job to grab depends
03cc27
-    whether caller wishes to communicate only with agent socket, or only
03cc27
-    with qemu monitor socket or both, respectively.
03cc27
+    (qemuDomainObjBeginAgentJob), or only normal job (qemuDomainObjBeginJob)
03cc27
+    but not both at the same time. Holding an agent job and a normal job would
03cc27
+    allow an unresponsive or malicious agent to block normal libvirt API and
03cc27
+    potentially result in a denial of service. Which type of job to grab
03cc27
+    depends whether caller wishes to communicate only with agent socket, or
03cc27
+    only with qemu monitor socket.
03cc27
 
03cc27
     Immediately after acquiring the virDomainObjPtr lock, any method
03cc27
     which intends to update state must acquire asynchronous, normal or
03cc27
@@ -151,18 +152,6 @@ To acquire the agent job condition
03cc27
 
03cc27
 
03cc27
 
03cc27
-To acquire both normal and agent job condition
03cc27
-
03cc27
-  qemuDomainObjBeginJobWithAgent()
03cc27
-    - Waits until there is no normal and no agent job set
03cc27
-    - Sets both job.active and job.agentActive with required job types
03cc27
-
03cc27
-  qemuDomainObjEndJobWithAgent()
03cc27
-    - Sets both job.active and job.agentActive to 0
03cc27
-    - Signals on job.cond condition
03cc27
-
03cc27
-
03cc27
-
03cc27
 To acquire the asynchronous job condition
03cc27
 
03cc27
   qemuDomainObjBeginAsyncJob()
03cc27
@@ -302,41 +291,6 @@ Design patterns
03cc27
      virDomainObjEndAPI(&obj);
03cc27
 
03cc27
 
03cc27
- * Invoking both monitor and agent commands on a virDomainObjPtr
03cc27
-
03cc27
-     virDomainObjPtr obj;
03cc27
-     qemuAgentPtr agent;
03cc27
-
03cc27
-     obj = qemuDomObjFromDomain(dom);
03cc27
-
03cc27
-     qemuDomainObjBeginJobWithAgent(obj, QEMU_JOB_TYPE, QEMU_AGENT_JOB_TYPE);
03cc27
-
03cc27
-     if (!virDomainObjIsActive(dom))
03cc27
-         goto cleanup;
03cc27
-
03cc27
-     ...do prep work...
03cc27
-
03cc27
-     if (!qemuDomainAgentAvailable(obj, true))
03cc27
-         goto cleanup;
03cc27
-
03cc27
-     agent = qemuDomainObjEnterAgent(obj);
03cc27
-     qemuAgentXXXX(agent, ..);
03cc27
-     qemuDomainObjExitAgent(obj, agent);
03cc27
-
03cc27
-     ...
03cc27
-
03cc27
-     qemuDomainObjEnterMonitor(obj);
03cc27
-     qemuMonitorXXXX(priv->mon);
03cc27
-     qemuDomainObjExitMonitor(obj);
03cc27
-
03cc27
-     /* Alternatively, talk to the monitor first and then talk to the agent. */
03cc27
-
03cc27
-     ...do final work...
03cc27
-
03cc27
-     qemuDomainObjEndJobWithAgent(obj);
03cc27
-     virDomainObjEndAPI(&obj);
03cc27
-
03cc27
-
03cc27
  * Running asynchronous job
03cc27
 
03cc27
      virDomainObjPtr obj;
03cc27
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
03cc27
index 3c67769771..b4792c9476 100644
03cc27
--- a/src/qemu/qemu_domain.c
03cc27
+++ b/src/qemu/qemu_domain.c
03cc27
@@ -6905,26 +6905,6 @@ qemuDomainObjBeginAgentJob(virQEMUDriverPtr driver,
03cc27
                                          QEMU_ASYNC_JOB_NONE, false);
03cc27
 }
03cc27
 
03cc27
-/**
03cc27
- * qemuDomainObjBeginJobWithAgent:
03cc27
- *
03cc27
- * Grabs both monitor and agent types of job. Use if caller talks to
03cc27
- * both monitor and guest agent. However, if @job (or @agentJob) is
03cc27
- * QEMU_JOB_NONE (or QEMU_AGENT_JOB_NONE) only agent job is acquired (or
03cc27
- * monitor job).
03cc27
- *
03cc27
- * To end job call qemuDomainObjEndJobWithAgent.
03cc27
- */
03cc27
-int
03cc27
-qemuDomainObjBeginJobWithAgent(virQEMUDriverPtr driver,
03cc27
-                               virDomainObjPtr obj,
03cc27
-                               qemuDomainJob job,
03cc27
-                               qemuDomainAgentJob agentJob)
03cc27
-{
03cc27
-    return qemuDomainObjBeginJobInternal(driver, obj, job, agentJob,
03cc27
-                                         QEMU_ASYNC_JOB_NONE, false);
03cc27
-}
03cc27
-
03cc27
 int qemuDomainObjBeginAsyncJob(virQEMUDriverPtr driver,
03cc27
                                virDomainObjPtr obj,
03cc27
                                qemuDomainAsyncJob asyncJob,
03cc27
@@ -7039,31 +7019,6 @@ qemuDomainObjEndAgentJob(virDomainObjPtr obj)
03cc27
     virCondBroadcast(&priv->job.cond);
03cc27
 }
03cc27
 
03cc27
-void
03cc27
-qemuDomainObjEndJobWithAgent(virQEMUDriverPtr driver,
03cc27
-                             virDomainObjPtr obj)
03cc27
-{
03cc27
-    qemuDomainObjPrivatePtr priv = obj->privateData;
03cc27
-    qemuDomainJob job = priv->job.active;
03cc27
-    qemuDomainAgentJob agentJob = priv->job.agentActive;
03cc27
-
03cc27
-    priv->jobs_queued--;
03cc27
-
03cc27
-    VIR_DEBUG("Stopping both jobs: %s %s (async=%s vm=%p name=%s)",
03cc27
-              qemuDomainJobTypeToString(job),
03cc27
-              qemuDomainAgentJobTypeToString(agentJob),
03cc27
-              qemuDomainAsyncJobTypeToString(priv->job.asyncJob),
03cc27
-              obj, obj->def->name);
03cc27
-
03cc27
-    qemuDomainObjResetJob(priv);
03cc27
-    qemuDomainObjResetAgentJob(priv);
03cc27
-    if (qemuDomainTrackJob(job))
03cc27
-        qemuDomainObjSaveJob(driver, obj);
03cc27
-    /* We indeed need to wake up ALL threads waiting because
03cc27
-     * grabbing a job requires checking more variables. */
03cc27
-    virCondBroadcast(&priv->job.cond);
03cc27
-}
03cc27
-
03cc27
 void
03cc27
 qemuDomainObjEndAsyncJob(virQEMUDriverPtr driver, virDomainObjPtr obj)
03cc27
 {
03cc27
@@ -7097,9 +7052,9 @@ qemuDomainObjAbortAsyncJob(virDomainObjPtr obj)
03cc27
  * obj must be locked before calling
03cc27
  *
03cc27
  * To be called immediately before any QEMU monitor API call
03cc27
- * Must have already either called qemuDomainObjBeginJob() or
03cc27
- * qemuDomainObjBeginJobWithAgent() and checked that the VM is
03cc27
- * still active; may not be used for nested async jobs.
03cc27
+ * Must have already called qemuDomainObjBeginJob() and checked
03cc27
+ * that the VM is still active; may not be used for nested async
03cc27
+ * jobs.
03cc27
  *
03cc27
  * To be followed with qemuDomainObjExitMonitor() once complete
03cc27
  */
03cc27
@@ -7216,9 +7171,8 @@ qemuDomainObjEnterMonitorAsync(virQEMUDriverPtr driver,
03cc27
  * obj must be locked before calling
03cc27
  *
03cc27
  * To be called immediately before any QEMU agent API call.
03cc27
- * Must have already called qemuDomainObjBeginAgentJob() or
03cc27
- * qemuDomainObjBeginJobWithAgent() and checked that the VM is
03cc27
- * still active.
03cc27
+ * Must have already called qemuDomainObjBeginAgentJob() and
03cc27
+ * checked that the VM is still active.
03cc27
  *
03cc27
  * To be followed with qemuDomainObjExitAgent() once complete
03cc27
  */
03cc27
diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
03cc27
index daed69e856..e4cc65c4cc 100644
03cc27
--- a/src/qemu/qemu_domain.h
03cc27
+++ b/src/qemu/qemu_domain.h
03cc27
@@ -527,11 +527,6 @@ int qemuDomainObjBeginAgentJob(virQEMUDriverPtr driver,
03cc27
                                virDomainObjPtr obj,
03cc27
                                qemuDomainAgentJob agentJob)
03cc27
     ATTRIBUTE_RETURN_CHECK;
03cc27
-int qemuDomainObjBeginJobWithAgent(virQEMUDriverPtr driver,
03cc27
-                                   virDomainObjPtr obj,
03cc27
-                                   qemuDomainJob job,
03cc27
-                                   qemuDomainAgentJob agentJob)
03cc27
-    ATTRIBUTE_RETURN_CHECK;
03cc27
 int qemuDomainObjBeginAsyncJob(virQEMUDriverPtr driver,
03cc27
                                virDomainObjPtr obj,
03cc27
                                qemuDomainAsyncJob asyncJob,
03cc27
@@ -550,8 +545,6 @@ int qemuDomainObjBeginJobNowait(virQEMUDriverPtr driver,
03cc27
 void qemuDomainObjEndJob(virQEMUDriverPtr driver,
03cc27
                          virDomainObjPtr obj);
03cc27
 void qemuDomainObjEndAgentJob(virDomainObjPtr obj);
03cc27
-void qemuDomainObjEndJobWithAgent(virQEMUDriverPtr driver,
03cc27
-                                  virDomainObjPtr obj);
03cc27
 void qemuDomainObjEndAsyncJob(virQEMUDriverPtr driver,
03cc27
                               virDomainObjPtr obj);
03cc27
 void qemuDomainObjAbortAsyncJob(virDomainObjPtr obj);
03cc27
-- 
03cc27
2.26.2
03cc27