Blob Blame History Raw
From 9a68121178334ac95dd057c98a3b8922a243fb93 Mon Sep 17 00:00:00 2001
Message-Id: <9a68121178334ac95dd057c98a3b8922a243fb93.1383922567.git.jdenemar@redhat.com>
From: Peter Krempa <pkrempa@redhat.com>
Date: Fri, 8 Nov 2013 12:33:35 +0100
Subject: [PATCH] qemu: process: Validate specific CPUID flags of a guest

https://bugzilla.redhat.com/show_bug.cgi?id=1008989

When starting a VM the qemu process may filter out some requested
features of a domain as it's not supported either by the host or by
qemu. Libvirt didn't check if this happened which might end up in
changing of the guest ABI when migrating.

The proof of concept implementation adds the check for the recently
introduced kvm_pv_unhalt cpuid feature bit. This feature depends on both
qemu and host kernel support and thus increase the possibility of guest
ABI breakage.

(cherry picked from commit d94b7817719b064849818b9ba6c37e403b7c003c)

Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
---
 src/qemu/qemu_process.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 46 insertions(+)

diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index e0097df..40e3754 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -43,6 +43,7 @@
 #include "qemu_bridge_filter.h"
 #include "qemu_migration.h"
 
+#include "cpu/cpu.h"
 #include "datatypes.h"
 #include "virlog.h"
 #include "virerror.h"
@@ -3437,6 +3438,47 @@ qemuValidateCpuMax(virDomainDefPtr def, virQEMUCapsPtr qemuCaps)
     return true;
 }
 
+
+static bool
+qemuProcessVerifyGuestCPU(virQEMUDriverPtr driver, virDomainObjPtr vm)
+{
+    virDomainDefPtr def = vm->def;
+    virArch arch = def->os.arch;
+    virCPUDataPtr guestcpu = NULL;
+    qemuDomainObjPrivatePtr priv = vm->privateData;
+    bool ret = false;
+
+    switch (arch) {
+    case VIR_ARCH_I686:
+    case VIR_ARCH_X86_64:
+        qemuDomainObjEnterMonitor(driver, vm);
+        guestcpu = qemuMonitorGetGuestCPU(priv->mon, arch);
+        qemuDomainObjExitMonitor(driver, vm);
+
+        if (!(guestcpu))
+            goto cleanup;
+
+        if (def->features[VIR_DOMAIN_FEATURE_PVSPINLOCK] == VIR_DOMAIN_FEATURE_STATE_ON) {
+            if (!cpuHasFeature(guestcpu, VIR_CPU_x86_KVM_PV_UNHALT)) {
+                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                               _("host doesn't support paravirtual spinlocks"));
+                goto cleanup;
+            }
+        }
+        break;
+
+    default:
+        break;
+    }
+
+    ret = true;
+
+cleanup:
+    cpuDataFree(guestcpu);
+    return ret;
+}
+
+
 int qemuProcessStart(virConnectPtr conn,
                      virQEMUDriverPtr driver,
                      virDomainObjPtr vm,
@@ -3904,6 +3946,10 @@ int qemuProcessStart(virConnectPtr conn,
         priv->agentError = true;
     }
 
+    VIR_DEBUG("Detecting if required emulator features are present");
+    if (!qemuProcessVerifyGuestCPU(driver, vm))
+        goto cleanup;
+
     VIR_DEBUG("Detecting VCPU PIDs");
     if (qemuProcessDetectVcpuPIDs(driver, vm) < 0)
         goto cleanup;
-- 
1.8.4.2