File libvirt-conf-include-x86-microcode-version-in-virsh-capabiltiies.patch of Package libvirt

From 5c9fbf633ebbb43ae7297591a5fb13cd5d6c43cd Mon Sep 17 00:00:00 2001
Message-Id: <5c9fbf633ebbb43ae7297591a5fb13cd5d6c43cd@dist-git>
From: Paolo Bonzini <pbonzini@redhat.com>
Date: Tue, 12 Dec 2017 16:23:40 +0100
Subject: [PATCH] conf: include x86 microcode version in virsh capabiltiies

A microcode update can cause the CPUID bits to change; an example
from the past was the update that disabled TSX on several Haswell and
Broadwell machines.

In order to track the x86 microcode version in the QEMU capabilities,
we have to fetch it and store it in the host CPU.  This also makes the
version visible in "virsh capabilities", which is a nice side effect.

CVE-2017-5715

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>

Conflicts:
	src/conf/capabilities.h
            - context

	src/conf/cpu_conf.c
            - context, missing virCPUDefStealModel, and the copying is
              done directly in virCPUDefCopyModel

	src/cpu/cpu_x86.c
            - CPU driver was heavily refactored since 6.9; the code had
              to be moved to the caller of cpuNodeData

	src/libvirt_private.syms
            - context

Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
---
 src/conf/capabilities.c      | 12 ++++++++++++
 src/conf/capabilities.h      |  2 ++
 src/conf/cpu_conf.c          | 13 +++++++++++++
 src/conf/cpu_conf.h          |  1 +
 src/libvirt_private.syms     |  1 +
 src/qemu/qemu_capabilities.c | 11 +++++++++++
 tests/testutilsqemu.c        |  1 +
 7 files changed, 41 insertions(+)

diff --git a/src/conf/capabilities.c b/src/conf/capabilities.c
index e37faec6cc..d71038673a 100644
--- a/src/conf/capabilities.c
+++ b/src/conf/capabilities.c
@@ -291,6 +291,18 @@ virCapabilitiesAddHostNUMACell(virCapsPtr caps,
 }
 
 
+/**
+ * virCapabilitiesGetMicrocodeVersion:
+ * @caps: capabilities to access
+ *
+ * Get host CPU microcode version, or 0 if unavailable
+ */
+unsigned int
+virCapabilitiesGetMicrocodeVersion(virCapsPtr caps)
+{
+    return caps->host.cpu ? caps->host.cpu->microcodeVersion : 0;
+}
+
 /**
  * virCapabilitiesSetHostCPU:
  * @caps: capabilities to extend
diff --git a/src/conf/capabilities.h b/src/conf/capabilities.h
index 577b0d5e7f..ac34f0bd02 100644
--- a/src/conf/capabilities.h
+++ b/src/conf/capabilities.h
@@ -284,4 +284,6 @@ virCapabilitiesFormatXML(virCapsPtr caps);
 virBitmapPtr virCapabilitiesGetCpusForNodemask(virCapsPtr caps,
                                                virBitmapPtr nodemask);
 
+unsigned int virCapabilitiesGetMicrocodeVersion(virCapsPtr caps);
+
 #endif /* __VIR_CAPABILITIES_H */
diff --git a/src/conf/cpu_conf.c b/src/conf/cpu_conf.c
index 3e675b70a0..7c3e1a560a 100644
--- a/src/conf/cpu_conf.c
+++ b/src/conf/cpu_conf.c
@@ -104,6 +104,7 @@ virCPUDefCopyModel(virCPUDefPtr dst,
         || (src->vendor_id && !(dst->vendor_id = strdup(src->vendor_id)))
         || VIR_ALLOC_N(dst->features, src->nfeatures) < 0)
         goto no_memory;
+    dst->microcodeVersion = src->microcodeVersion;
     dst->nfeatures_max = dst->nfeatures = src->nfeatures;
 
     for (i = 0; i < dst->nfeatures; i++) {
@@ -275,6 +276,14 @@ virCPUDefParseXML(const xmlNodePtr node,
                            "%s", _("Missing CPU architecture"));
             goto error;
         }
+
+        if (virXPathBoolean("boolean(./microcode[1]/@version)", ctxt) > 0 &&
+            virXPathUInt("string(./microcode[1]/@version)", ctxt,
+                         &def->microcodeVersion) < 0) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                           _("invalid microcode version"));
+            goto cleanup;
+        }
     }
 
     if (!(def->model = virXPathString("string(./model[1])", ctxt)) &&
@@ -623,6 +632,10 @@ virCPUDefFormatBuf(virBufferPtr buf,
     if (formatModel && def->vendor)
         virBufferAsprintf(buf, "<vendor>%s</vendor>\n", def->vendor);
 
+    if (def->type == VIR_CPU_TYPE_HOST && def->microcodeVersion)
+        virBufferAsprintf(buf, "<microcode version='%u'/>\n",
+                          def->microcodeVersion);
+
     if (def->sockets && def->cores && def->threads) {
         virBufferAddLit(buf, "<topology");
         virBufferAsprintf(buf, " sockets='%u'", def->sockets);
diff --git a/src/conf/cpu_conf.h b/src/conf/cpu_conf.h
index 879f8eb693..edcc5d8578 100644
--- a/src/conf/cpu_conf.h
+++ b/src/conf/cpu_conf.h
@@ -109,6 +109,7 @@ struct _virCPUDef {
     char *vendor_id;    /* vendor id returned by CPUID in the guest */
     int fallback;       /* enum virCPUFallback */
     char *vendor;
+    unsigned int microcodeVersion;
     unsigned int sockets;
     unsigned int cores;
     unsigned int threads;
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index ff7ce38e62..d0cab246fe 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -69,6 +69,7 @@ virCapabilitiesFreeNUMAInfo;
 virCapabilitiesGenerateMac;
 virCapabilitiesIsEmulatorRequired;
 virCapabilitiesGetCpusForNodemask;
+virCapabilitiesGetMicrocodeVersion;
 virCapabilitiesNew;
 virCapabilitiesSetEmulatorRequired;
 virCapabilitiesSetHostCPU;
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index d7afa2ead8..2daee3fe53 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -801,6 +801,8 @@ static int
 qemuCapsInitCPU(virCapsPtr caps,
                 const char *arch)
 {
+    static unsigned int microcodeVersion = 0;
+    static bool microcodeValid = false;
     virCPUDefPtr cpu = NULL;
     union cpuData *data = NULL;
     virNodeInfo nodeinfo;
@@ -825,6 +827,15 @@ qemuCapsInitCPU(virCapsPtr caps,
         || cpuDecode(cpu, data, NULL, 0, NULL) < 0)
         goto cleanup;
 
+    if (STREQ(arch, "i686") || STREQ(arch, "x86_64")) {
+        /* This is safe since we are called iff driver is locked */
+        if (!microcodeValid) {
+            microcodeVersion = virHostCPUGetMicrocodeVersion();
+            microcodeValid = true;
+        }
+        cpu->microcodeVersion = microcodeVersion;
+    }
+
     ret = 0;
 
 cleanup:
diff --git a/tests/testutilsqemu.c b/tests/testutilsqemu.c
index d922fd8ddd..bc472326ac 100644
--- a/tests/testutilsqemu.c
+++ b/tests/testutilsqemu.c
@@ -147,6 +147,7 @@ virCapsPtr testQemuCapsInit(void) {
         NULL,                   /* vendor_id */
         0,                      /* fallback */
         (char *) "Intel",       /* vendor */
+        0,                      /* microcodeVersion */
         1,                      /* sockets */
         2,                      /* cores */
         1,                      /* threads */
-- 
2.15.1

openSUSE Build Service is sponsored by