c401cc
From 192667c53a356a2bc3aa389312345453dd1c3bd5 Mon Sep 17 00:00:00 2001
c401cc
Message-Id: <192667c53a356a2bc3aa389312345453dd1c3bd5.1390394206.git.jdenemar@redhat.com>
c401cc
From: Peter Krempa <pkrempa@redhat.com>
c401cc
Date: Fri, 17 Jan 2014 14:28:18 +0100
c401cc
Subject: [PATCH] qemu: Avoid operations on NULL monitor if VM fails early
c401cc
c401cc
https://bugzilla.redhat.com/show_bug.cgi?id=1054785 [7.0]
c401cc
https://bugzilla.redhat.com/show_bug.cgi?id=1047659 [6.6]
c401cc
c401cc
If a VM dies very early during an attempted connect to the guest agent
c401cc
while the locks are down the domain monitor object will be freed. The
c401cc
object is then accessed later as any failure during guest agent startup
c401cc
isn't considered fatal.
c401cc
c401cc
In the current upstream version this doesn't lead to a crash as
c401cc
virObjectLock called when entering the monitor in
c401cc
qemuProcessDetectVcpuPIDs checks the pointer before attempting to
c401cc
dereference (lock) it. The NULL pointer is then caught in the monitor
c401cc
helper code.
c401cc
c401cc
Before the introduction of virObjectLockable - observed on 0.10.2 - the
c401cc
pointer is locked directly via virMutexLock leading to a crash.
c401cc
c401cc
To avoid this problem we need to differentiate between the guest agent
c401cc
not being present and the VM quitting when the locks were down. The fix
c401cc
reorganizes the code in qemuConnectAgent to add the check and then adds
c401cc
special handling to the callers.
c401cc
c401cc
(cherry picked from commit b952cbbccafd5ead8b5a70b2608a1d5a7f03b31e)
c401cc
c401cc
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
c401cc
---
c401cc
 src/qemu/qemu_process.c | 34 +++++++++++++++++++++++++---------
c401cc
 1 file changed, 25 insertions(+), 9 deletions(-)
c401cc
c401cc
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
c401cc
index a4b757c..af66e0d 100644
c401cc
--- a/src/qemu/qemu_process.c
c401cc
+++ b/src/qemu/qemu_process.c
c401cc
@@ -245,6 +245,17 @@ qemuConnectAgent(virQEMUDriverPtr driver, virDomainObjPtr vm)
c401cc
     virObjectLock(vm);
c401cc
     priv->agentStart = 0;
c401cc
 
c401cc
+    if (agent == NULL)
c401cc
+        virObjectUnref(vm);
c401cc
+
c401cc
+    if (!virDomainObjIsActive(vm)) {
c401cc
+        qemuAgentClose(agent);
c401cc
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
c401cc
+                       _("guest crashed while connecting to the guest agent"));
c401cc
+        ret = -2;
c401cc
+        goto cleanup;
c401cc
+    }
c401cc
+
c401cc
     if (virSecurityManagerClearSocketLabel(driver->securityManager,
c401cc
                                            vm->def) < 0) {
c401cc
         VIR_ERROR(_("Failed to clear security context for agent for %s"),
c401cc
@@ -252,13 +263,7 @@ qemuConnectAgent(virQEMUDriverPtr driver, virDomainObjPtr vm)
c401cc
         goto cleanup;
c401cc
     }
c401cc
 
c401cc
-    if (agent == NULL)
c401cc
-        virObjectUnref(vm);
c401cc
 
c401cc
-    if (!virDomainObjIsActive(vm)) {
c401cc
-        qemuAgentClose(agent);
c401cc
-        goto cleanup;
c401cc
-    }
c401cc
     priv->agent = agent;
c401cc
 
c401cc
     if (priv->agent == NULL) {
c401cc
@@ -3092,6 +3097,7 @@ qemuProcessReconnect(void *opaque)
c401cc
     int reason;
c401cc
     virQEMUDriverConfigPtr cfg;
c401cc
     size_t i;
c401cc
+    int ret;
c401cc
 
c401cc
     memcpy(&oldjob, &data->oldjob, sizeof(oldjob));
c401cc
 
c401cc
@@ -3116,7 +3122,10 @@ qemuProcessReconnect(void *opaque)
c401cc
         goto error;
c401cc
 
c401cc
     /* Failure to connect to agent shouldn't be fatal */
c401cc
-    if (qemuConnectAgent(driver, obj) < 0) {
c401cc
+    if ((ret = qemuConnectAgent(driver, obj)) < 0) {
c401cc
+        if (ret == -2)
c401cc
+            goto error;
c401cc
+
c401cc
         VIR_WARN("Cannot connect to QEMU guest agent for %s",
c401cc
                  obj->def->name);
c401cc
         virResetLastError();
c401cc
@@ -4005,7 +4014,10 @@ int qemuProcessStart(virConnectPtr conn,
c401cc
         goto cleanup;
c401cc
 
c401cc
     /* Failure to connect to agent shouldn't be fatal */
c401cc
-    if (qemuConnectAgent(driver, vm) < 0) {
c401cc
+    if ((ret = qemuConnectAgent(driver, vm)) < 0) {
c401cc
+        if (ret == -2)
c401cc
+            goto cleanup;
c401cc
+
c401cc
         VIR_WARN("Cannot connect to QEMU guest agent for %s",
c401cc
                  vm->def->name);
c401cc
         virResetLastError();
c401cc
@@ -4463,6 +4475,7 @@ int qemuProcessAttach(virConnectPtr conn ATTRIBUTE_UNUSED,
c401cc
     virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
c401cc
     virCapsPtr caps = NULL;
c401cc
     bool active = false;
c401cc
+    int ret;
c401cc
 
c401cc
     VIR_DEBUG("Beginning VM attach process");
c401cc
 
c401cc
@@ -4577,7 +4590,10 @@ int qemuProcessAttach(virConnectPtr conn ATTRIBUTE_UNUSED,
c401cc
         goto error;
c401cc
 
c401cc
     /* Failure to connect to agent shouldn't be fatal */
c401cc
-    if (qemuConnectAgent(driver, vm) < 0) {
c401cc
+    if ((ret = qemuConnectAgent(driver, vm)) < 0) {
c401cc
+        if (ret == -2)
c401cc
+            goto error;
c401cc
+
c401cc
         VIR_WARN("Cannot connect to QEMU guest agent for %s",
c401cc
                  vm->def->name);
c401cc
         virResetLastError();
c401cc
-- 
c401cc
1.8.5.3
c401cc