4cd28d
From a2fe4ef20df702070ffec676172c19e6c89b8312 Mon Sep 17 00:00:00 2001
4cd28d
Message-Id: <a2fe4ef20df702070ffec676172c19e6c89b8312@dist-git>
4cd28d
From: Paolo Bonzini <pbonzini@redhat.com>
4cd28d
Date: Tue, 12 Dec 2017 16:23:40 +0100
4cd28d
Subject: [PATCH] conf: include x86 microcode version in virsh capabiltiies
4cd28d
4cd28d
A microcode update can cause the CPUID bits to change; an example
4cd28d
from the past was the update that disabled TSX on several Haswell and
4cd28d
Broadwell machines.
4cd28d
4cd28d
In order to track the x86 microcode version in the QEMU capabilities,
4cd28d
we have to fetch it and store it in the host CPU.  This also makes the
4cd28d
version visible in "virsh capabilities", which is a nice side effect.
4cd28d
4cd28d
CVE-2017-5715
4cd28d
4cd28d
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
4cd28d
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
4cd28d
4cd28d
Conflicts:
4cd28d
	src/cpu/cpu_x86.c
4cd28d
            - context; x86DecodeCPUData has more parameters in 7.4
4cd28d
---
4cd28d
 src/conf/capabilities.c  | 12 ++++++++++++
4cd28d
 src/conf/capabilities.h  |  2 ++
4cd28d
 src/conf/cpu_conf.c      | 14 ++++++++++++++
4cd28d
 src/conf/cpu_conf.h      |  1 +
4cd28d
 src/cpu/cpu_x86.c        |  9 +++++++++
4cd28d
 src/libvirt_private.syms |  1 +
4cd28d
 6 files changed, 39 insertions(+)
4cd28d
4cd28d
diff --git a/src/conf/capabilities.c b/src/conf/capabilities.c
4cd28d
index 08907aced1..fad6cc1c07 100644
4cd28d
--- a/src/conf/capabilities.c
4cd28d
+++ b/src/conf/capabilities.c
4cd28d
@@ -355,6 +355,18 @@ virCapabilitiesAddHostNUMACell(virCapsPtr caps,
4cd28d
 }
4cd28d
 
4cd28d
 
4cd28d
+/**
4cd28d
+ * virCapabilitiesGetMicrocodeVersion:
4cd28d
+ * @caps: capabilities to access
4cd28d
+ *
4cd28d
+ * Get host CPU microcode version, or 0 if unavailable
4cd28d
+ */
4cd28d
+unsigned int
4cd28d
+virCapabilitiesGetMicrocodeVersion(virCapsPtr caps)
4cd28d
+{
4cd28d
+    return caps->host.cpu ? caps->host.cpu->microcodeVersion : 0;
4cd28d
+}
4cd28d
+
4cd28d
 /**
4cd28d
  * virCapabilitiesSetHostCPU:
4cd28d
  * @caps: capabilities to extend
4cd28d
diff --git a/src/conf/capabilities.h b/src/conf/capabilities.h
4cd28d
index d10eef3afd..75e0748e9e 100644
4cd28d
--- a/src/conf/capabilities.h
4cd28d
+++ b/src/conf/capabilities.h
4cd28d
@@ -299,6 +299,8 @@ virBitmapPtr virCapabilitiesGetCpusForNodemask(virCapsPtr caps,
4cd28d
 
4cd28d
 int virCapabilitiesGetNodeInfo(virNodeInfoPtr nodeinfo);
4cd28d
 
4cd28d
+unsigned int virCapabilitiesGetMicrocodeVersion(virCapsPtr caps);
4cd28d
+
4cd28d
 int virCapabilitiesInitPages(virCapsPtr caps);
4cd28d
 
4cd28d
 int virCapabilitiesInitNUMA(virCapsPtr caps);
4cd28d
diff --git a/src/conf/cpu_conf.c b/src/conf/cpu_conf.c
4cd28d
index e570dffcd2..239f671fa7 100644
4cd28d
--- a/src/conf/cpu_conf.c
4cd28d
+++ b/src/conf/cpu_conf.c
4cd28d
@@ -127,6 +127,7 @@ virCPUDefCopyModelFilter(virCPUDefPtr dst,
4cd28d
         VIR_STRDUP(dst->vendor_id, src->vendor_id) < 0 ||
4cd28d
         VIR_ALLOC_N(dst->features, src->nfeatures) < 0)
4cd28d
         return -1;
4cd28d
+    dst->microcodeVersion = src->microcodeVersion;
4cd28d
     dst->nfeatures_max = src->nfeatures;
4cd28d
     dst->nfeatures = 0;
4cd28d
 
4cd28d
@@ -178,6 +179,7 @@ virCPUDefStealModel(virCPUDefPtr dst,
4cd28d
 
4cd28d
     VIR_STEAL_PTR(dst->model, src->model);
4cd28d
     VIR_STEAL_PTR(dst->features, src->features);
4cd28d
+    dst->microcodeVersion = src->microcodeVersion;
4cd28d
     dst->nfeatures_max = src->nfeatures_max;
4cd28d
     src->nfeatures_max = 0;
4cd28d
     dst->nfeatures = src->nfeatures;
4cd28d
@@ -379,6 +381,14 @@ virCPUDefParseXML(xmlXPathContextPtr ctxt,
4cd28d
             goto cleanup;
4cd28d
         }
4cd28d
         VIR_FREE(arch);
4cd28d
+
4cd28d
+        if (virXPathBoolean("boolean(./microcode[1]/@version)", ctxt) > 0 &&
4cd28d
+            virXPathUInt("string(./microcode[1]/@version)", ctxt,
4cd28d
+                         &def->microcodeVersion) < 0) {
4cd28d
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
4cd28d
+                           _("invalid microcode version"));
4cd28d
+            goto cleanup;
4cd28d
+        }
4cd28d
     }
4cd28d
 
4cd28d
     if (!(def->model = virXPathString("string(./model[1])", ctxt)) &&
4cd28d
@@ -720,6 +730,10 @@ virCPUDefFormatBuf(virBufferPtr buf,
4cd28d
     if (formatModel && def->vendor)
4cd28d
         virBufferEscapeString(buf, "<vendor>%s</vendor>\n", def->vendor);
4cd28d
 
4cd28d
+    if (def->type == VIR_CPU_TYPE_HOST && def->microcodeVersion)
4cd28d
+        virBufferAsprintf(buf, "<microcode version='%u'/>\n",
4cd28d
+                          def->microcodeVersion);
4cd28d
+
4cd28d
     if (def->sockets && def->cores && def->threads) {
4cd28d
         virBufferAddLit(buf, "
4cd28d
         virBufferAsprintf(buf, " sockets='%u'", def->sockets);
4cd28d
diff --git a/src/conf/cpu_conf.h b/src/conf/cpu_conf.h
4cd28d
index 1978814d36..1a13ae6e46 100644
4cd28d
--- a/src/conf/cpu_conf.h
4cd28d
+++ b/src/conf/cpu_conf.h
4cd28d
@@ -133,6 +133,7 @@ struct _virCPUDef {
4cd28d
     char *vendor_id;    /* vendor id returned by CPUID in the guest */
4cd28d
     int fallback;       /* enum virCPUFallback */
4cd28d
     char *vendor;
4cd28d
+    unsigned int microcodeVersion;
4cd28d
     unsigned int sockets;
4cd28d
     unsigned int cores;
4cd28d
     unsigned int threads;
4cd28d
diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c
4cd28d
index 8af0a1a2b7..efef7f235d 100644
4cd28d
--- a/src/cpu/cpu_x86.c
4cd28d
+++ b/src/cpu/cpu_x86.c
4cd28d
@@ -33,6 +33,7 @@
4cd28d
 #include "virbuffer.h"
4cd28d
 #include "virendian.h"
4cd28d
 #include "virstring.h"
4cd28d
+#include "virhostcpu.h"
4cd28d
 
4cd28d
 #define VIR_FROM_THIS VIR_FROM_CPU
4cd28d
 
4cd28d
@@ -153,6 +154,8 @@ struct _virCPUx86Map {
4cd28d
 };
4cd28d
 
4cd28d
 static virCPUx86MapPtr cpuMap;
4cd28d
+static unsigned int microcodeVersion;
4cd28d
+
4cd28d
 int virCPUx86DriverOnceInit(void);
4cd28d
 VIR_ONCE_GLOBAL_INIT(virCPUx86Driver);
4cd28d
 
4cd28d
@@ -1391,6 +1394,8 @@ virCPUx86DriverOnceInit(void)
4cd28d
     if (!(cpuMap = virCPUx86LoadMap()))
4cd28d
         return -1;
4cd28d
 
4cd28d
+    microcodeVersion = virHostCPUGetMicrocodeVersion();
4cd28d
+
4cd28d
     return 0;
4cd28d
 }
4cd28d
 
4cd28d
@@ -2408,6 +2413,9 @@ virCPUx86GetHost(virCPUDefPtr cpu,
4cd28d
     virCPUDataPtr cpuData = NULL;
4cd28d
     int ret = -1;
4cd28d
 
4cd28d
+    if (virCPUx86DriverInitialize() < 0)
4cd28d
+        goto cleanup;
4cd28d
+
4cd28d
     if (!(cpuData = virCPUDataNew(archs[0])))
4cd28d
         goto cleanup;
4cd28d
 
4cd28d
@@ -2416,6 +2424,7 @@ virCPUx86GetHost(virCPUDefPtr cpu,
4cd28d
         goto cleanup;
4cd28d
 
4cd28d
     ret = x86DecodeCPUData(cpu, cpuData, models, nmodels, NULL);
4cd28d
+    cpu->microcodeVersion = microcodeVersion;
4cd28d
 
4cd28d
  cleanup:
4cd28d
     virCPUx86DataFree(cpuData);
4cd28d
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
4cd28d
index c50b6c2f77..c7834115fd 100644
4cd28d
--- a/src/libvirt_private.syms
4cd28d
+++ b/src/libvirt_private.syms
4cd28d
@@ -57,6 +57,7 @@ virCapabilitiesFreeGuest;
4cd28d
 virCapabilitiesFreeMachines;
4cd28d
 virCapabilitiesFreeNUMAInfo;
4cd28d
 virCapabilitiesGetCpusForNodemask;
4cd28d
+virCapabilitiesGetMicrocodeVersion;
4cd28d
 virCapabilitiesGetNodeInfo;
4cd28d
 virCapabilitiesHostSecModelAddBaseLabel;
4cd28d
 virCapabilitiesInitNUMA;
4cd28d
-- 
4cd28d
2.15.1
4cd28d