a41c76
From bac1c96fbf2bd9d6ef728a813fda793ce1e99267 Mon Sep 17 00:00:00 2001
a41c76
Message-Id: <bac1c96fbf2bd9d6ef728a813fda793ce1e99267@dist-git>
a41c76
From: Jonathon Jongsma <jjongsma@redhat.com>
a41c76
Date: Thu, 20 Feb 2020 10:52:27 -0600
a41c76
Subject: [PATCH] qemu: remove qemuDomainObjBegin/EndJobWithAgent()
a41c76
MIME-Version: 1.0
a41c76
Content-Type: text/plain; charset=UTF-8
a41c76
Content-Transfer-Encoding: 8bit
a41c76
a41c76
This function potentially grabs both a monitor job and an agent job at
a41c76
the same time. This is problematic because it means that a malicious (or
a41c76
just buggy) guest agent can cause a denial of service on the host. The
a41c76
presence of this function makes it easy to do the wrong thing and hold
a41c76
both jobs at the same time. All existing uses have already been removed
a41c76
by previous commits.
a41c76
a41c76
Signed-off-by: Jonathon Jongsma <jjongsma@redhat.com>
a41c76
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
a41c76
(cherry picked from commit 3c436c22a4f94c85c2b5e7b5fb84af48219d78e3)
a41c76
Signed-off-by: Jonathon Jongsma <jjongsma@redhat.com>
a41c76
https://bugzilla.redhat.com/show_bug.cgi?id=1759566
a41c76
Message-Id: <20200220165227.11491-6-jjongsma@redhat.com>
a41c76
Reviewed-by: Ján Tomko <jtomko@redhat.com>
a41c76
---
a41c76
 src/qemu/THREADS.txt   | 58 +++++-------------------------------------
a41c76
 src/qemu/qemu_domain.c | 56 ++++------------------------------------
a41c76
 src/qemu/qemu_domain.h |  7 -----
a41c76
 3 files changed, 11 insertions(+), 110 deletions(-)
a41c76
a41c76
diff --git a/src/qemu/THREADS.txt b/src/qemu/THREADS.txt
a41c76
index aa428fda6a..a7d8709a43 100644
a41c76
--- a/src/qemu/THREADS.txt
a41c76
+++ b/src/qemu/THREADS.txt
a41c76
@@ -61,11 +61,12 @@ There are a number of locks on various objects
a41c76
 
a41c76
     Agent job condition is then used when thread wishes to talk to qemu
a41c76
     agent monitor. It is possible to acquire just agent job
a41c76
-    (qemuDomainObjBeginAgentJob), or only normal job
a41c76
-    (qemuDomainObjBeginJob) or both at the same time
a41c76
-    (qemuDomainObjBeginJobWithAgent). Which type of job to grab depends
a41c76
-    whether caller wishes to communicate only with agent socket, or only
a41c76
-    with qemu monitor socket or both, respectively.
a41c76
+    (qemuDomainObjBeginAgentJob), or only normal job (qemuDomainObjBeginJob)
a41c76
+    but not both at the same time. Holding an agent job and a normal job would
a41c76
+    allow an unresponsive or malicious agent to block normal libvirt API and
a41c76
+    potentially result in a denial of service. Which type of job to grab
a41c76
+    depends whether caller wishes to communicate only with agent socket, or
a41c76
+    only with qemu monitor socket.
a41c76
 
a41c76
     Immediately after acquiring the virDomainObjPtr lock, any method
a41c76
     which intends to update state must acquire asynchronous, normal or
a41c76
@@ -141,18 +142,6 @@ To acquire the agent job condition
a41c76
 
a41c76
 
a41c76
 
a41c76
-To acquire both normal and agent job condition
a41c76
-
a41c76
-  qemuDomainObjBeginJobWithAgent()
a41c76
-    - Waits until there is no normal and no agent job set
a41c76
-    - Sets both job.active and job.agentActive with required job types
a41c76
-
a41c76
-  qemuDomainObjEndJobWithAgent()
a41c76
-    - Sets both job.active and job.agentActive to 0
a41c76
-    - Signals on job.cond condition
a41c76
-
a41c76
-
a41c76
-
a41c76
 To acquire the asynchronous job condition
a41c76
 
a41c76
   qemuDomainObjBeginAsyncJob()
a41c76
@@ -292,41 +281,6 @@ Design patterns
a41c76
      virDomainObjEndAPI(&obj);
a41c76
 
a41c76
 
a41c76
- * Invoking both monitor and agent commands on a virDomainObjPtr
a41c76
-
a41c76
-     virDomainObjPtr obj;
a41c76
-     qemuAgentPtr agent;
a41c76
-
a41c76
-     obj = qemuDomObjFromDomain(dom);
a41c76
-
a41c76
-     qemuDomainObjBeginJobWithAgent(obj, QEMU_JOB_TYPE, QEMU_AGENT_JOB_TYPE);
a41c76
-
a41c76
-     if (!virDomainObjIsActive(dom))
a41c76
-         goto cleanup;
a41c76
-
a41c76
-     ...do prep work...
a41c76
-
a41c76
-     if (!qemuDomainAgentAvailable(obj, true))
a41c76
-         goto cleanup;
a41c76
-
a41c76
-     agent = qemuDomainObjEnterAgent(obj);
a41c76
-     qemuAgentXXXX(agent, ..);
a41c76
-     qemuDomainObjExitAgent(obj, agent);
a41c76
-
a41c76
-     ...
a41c76
-
a41c76
-     qemuDomainObjEnterMonitor(obj);
a41c76
-     qemuMonitorXXXX(priv->mon);
a41c76
-     qemuDomainObjExitMonitor(obj);
a41c76
-
a41c76
-     /* Alternatively, talk to the monitor first and then talk to the agent. */
a41c76
-
a41c76
-     ...do final work...
a41c76
-
a41c76
-     qemuDomainObjEndJobWithAgent(obj);
a41c76
-     virDomainObjEndAPI(&obj);
a41c76
-
a41c76
-
a41c76
  * Running asynchronous job
a41c76
 
a41c76
      virDomainObjPtr obj;
a41c76
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
a41c76
index 0baa80582c..f037f0812e 100644
a41c76
--- a/src/qemu/qemu_domain.c
a41c76
+++ b/src/qemu/qemu_domain.c
a41c76
@@ -9734,26 +9734,6 @@ qemuDomainObjBeginAgentJob(virQEMUDriverPtr driver,
a41c76
                                          QEMU_ASYNC_JOB_NONE, false);
a41c76
 }
a41c76
 
a41c76
-/**
a41c76
- * qemuDomainObjBeginJobWithAgent:
a41c76
- *
a41c76
- * Grabs both monitor and agent types of job. Use if caller talks to
a41c76
- * both monitor and guest agent. However, if @job (or @agentJob) is
a41c76
- * QEMU_JOB_NONE (or QEMU_AGENT_JOB_NONE) only agent job is acquired (or
a41c76
- * monitor job).
a41c76
- *
a41c76
- * To end job call qemuDomainObjEndJobWithAgent.
a41c76
- */
a41c76
-int
a41c76
-qemuDomainObjBeginJobWithAgent(virQEMUDriverPtr driver,
a41c76
-                               virDomainObjPtr obj,
a41c76
-                               qemuDomainJob job,
a41c76
-                               qemuDomainAgentJob agentJob)
a41c76
-{
a41c76
-    return qemuDomainObjBeginJobInternal(driver, obj, job, agentJob,
a41c76
-                                         QEMU_ASYNC_JOB_NONE, false);
a41c76
-}
a41c76
-
a41c76
 int qemuDomainObjBeginAsyncJob(virQEMUDriverPtr driver,
a41c76
                                virDomainObjPtr obj,
a41c76
                                qemuDomainAsyncJob asyncJob,
a41c76
@@ -9868,31 +9848,6 @@ qemuDomainObjEndAgentJob(virDomainObjPtr obj)
a41c76
     virCondBroadcast(&priv->job.cond);
a41c76
 }
a41c76
 
a41c76
-void
a41c76
-qemuDomainObjEndJobWithAgent(virQEMUDriverPtr driver,
a41c76
-                             virDomainObjPtr obj)
a41c76
-{
a41c76
-    qemuDomainObjPrivatePtr priv = obj->privateData;
a41c76
-    qemuDomainJob job = priv->job.active;
a41c76
-    qemuDomainAgentJob agentJob = priv->job.agentActive;
a41c76
-
a41c76
-    priv->jobs_queued--;
a41c76
-
a41c76
-    VIR_DEBUG("Stopping both jobs: %s %s (async=%s vm=%p name=%s)",
a41c76
-              qemuDomainJobTypeToString(job),
a41c76
-              qemuDomainAgentJobTypeToString(agentJob),
a41c76
-              qemuDomainAsyncJobTypeToString(priv->job.asyncJob),
a41c76
-              obj, obj->def->name);
a41c76
-
a41c76
-    qemuDomainObjResetJob(priv);
a41c76
-    qemuDomainObjResetAgentJob(priv);
a41c76
-    if (qemuDomainTrackJob(job))
a41c76
-        qemuDomainObjSaveStatus(driver, obj);
a41c76
-    /* We indeed need to wake up ALL threads waiting because
a41c76
-     * grabbing a job requires checking more variables. */
a41c76
-    virCondBroadcast(&priv->job.cond);
a41c76
-}
a41c76
-
a41c76
 void
a41c76
 qemuDomainObjEndAsyncJob(virQEMUDriverPtr driver, virDomainObjPtr obj)
a41c76
 {
a41c76
@@ -9926,9 +9881,9 @@ qemuDomainObjAbortAsyncJob(virDomainObjPtr obj)
a41c76
  * obj must be locked before calling
a41c76
  *
a41c76
  * To be called immediately before any QEMU monitor API call
a41c76
- * Must have already either called qemuDomainObjBeginJob() or
a41c76
- * qemuDomainObjBeginJobWithAgent() and checked that the VM is
a41c76
- * still active; may not be used for nested async jobs.
a41c76
+ * Must have already called qemuDomainObjBeginJob() and checked
a41c76
+ * that the VM is still active; may not be used for nested async
a41c76
+ * jobs.
a41c76
  *
a41c76
  * To be followed with qemuDomainObjExitMonitor() once complete
a41c76
  */
a41c76
@@ -10050,9 +10005,8 @@ qemuDomainObjEnterMonitorAsync(virQEMUDriverPtr driver,
a41c76
  * obj must be locked before calling
a41c76
  *
a41c76
  * To be called immediately before any QEMU agent API call.
a41c76
- * Must have already called qemuDomainObjBeginAgentJob() or
a41c76
- * qemuDomainObjBeginJobWithAgent() and checked that the VM is
a41c76
- * still active.
a41c76
+ * Must have already called qemuDomainObjBeginAgentJob() and
a41c76
+ * checked that the VM is still active.
a41c76
  *
a41c76
  * To be followed with qemuDomainObjExitAgent() once complete
a41c76
  */
a41c76
diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
a41c76
index cdcb6ecc7a..c581b3a162 100644
a41c76
--- a/src/qemu/qemu_domain.h
a41c76
+++ b/src/qemu/qemu_domain.h
a41c76
@@ -651,11 +651,6 @@ int qemuDomainObjBeginAgentJob(virQEMUDriverPtr driver,
a41c76
                                virDomainObjPtr obj,
a41c76
                                qemuDomainAgentJob agentJob)
a41c76
     G_GNUC_WARN_UNUSED_RESULT;
a41c76
-int qemuDomainObjBeginJobWithAgent(virQEMUDriverPtr driver,
a41c76
-                                   virDomainObjPtr obj,
a41c76
-                                   qemuDomainJob job,
a41c76
-                                   qemuDomainAgentJob agentJob)
a41c76
-    G_GNUC_WARN_UNUSED_RESULT;
a41c76
 int qemuDomainObjBeginAsyncJob(virQEMUDriverPtr driver,
a41c76
                                virDomainObjPtr obj,
a41c76
                                qemuDomainAsyncJob asyncJob,
a41c76
@@ -674,8 +669,6 @@ int qemuDomainObjBeginJobNowait(virQEMUDriverPtr driver,
a41c76
 void qemuDomainObjEndJob(virQEMUDriverPtr driver,
a41c76
                          virDomainObjPtr obj);
a41c76
 void qemuDomainObjEndAgentJob(virDomainObjPtr obj);
a41c76
-void qemuDomainObjEndJobWithAgent(virQEMUDriverPtr driver,
a41c76
-                                  virDomainObjPtr obj);
a41c76
 void qemuDomainObjEndAsyncJob(virQEMUDriverPtr driver,
a41c76
                               virDomainObjPtr obj);
a41c76
 void qemuDomainObjAbortAsyncJob(virDomainObjPtr obj);
a41c76
-- 
a41c76
2.25.0
a41c76