c1c534
From 4f1684dd855d48517e04507edadba2fd454e4ada Mon Sep 17 00:00:00 2001
c1c534
Message-Id: <4f1684dd855d48517e04507edadba2fd454e4ada@dist-git>
c1c534
From: Paolo Bonzini <pbonzini@redhat.com>
c1c534
Date: Tue, 12 Dec 2017 16:23:40 +0100
c1c534
Subject: [PATCH] conf: include x86 microcode version in virsh capabiltiies
c1c534
c1c534
A microcode update can cause the CPUID bits to change; an example
c1c534
from the past was the update that disabled TSX on several Haswell and
c1c534
Broadwell machines.
c1c534
c1c534
In order to track the x86 microcode version in the QEMU capabilities,
c1c534
we have to fetch it and store it in the host CPU.  This also makes the
c1c534
version visible in "virsh capabilities", which is a nice side effect.
c1c534
c1c534
CVE-2017-5715
c1c534
c1c534
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
c1c534
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
c1c534
---
c1c534
 src/conf/cpu_conf.c | 14 ++++++++++++++
c1c534
 src/conf/cpu_conf.h |  1 +
c1c534
 src/cpu/cpu_x86.c   |  9 +++++++++
c1c534
 3 files changed, 24 insertions(+)
c1c534
c1c534
diff --git a/src/conf/cpu_conf.c b/src/conf/cpu_conf.c
c1c534
index 669935acf8..7e00299c66 100644
c1c534
--- a/src/conf/cpu_conf.c
c1c534
+++ b/src/conf/cpu_conf.c
c1c534
@@ -130,6 +130,7 @@ virCPUDefCopyModelFilter(virCPUDefPtr dst,
c1c534
         VIR_STRDUP(dst->vendor_id, src->vendor_id) < 0 ||
c1c534
         VIR_ALLOC_N(dst->features, src->nfeatures) < 0)
c1c534
         return -1;
c1c534
+    dst->microcodeVersion = src->microcodeVersion;
c1c534
     dst->nfeatures_max = src->nfeatures;
c1c534
     dst->nfeatures = 0;
c1c534
 
c1c534
@@ -181,6 +182,7 @@ virCPUDefStealModel(virCPUDefPtr dst,
c1c534
 
c1c534
     VIR_STEAL_PTR(dst->model, src->model);
c1c534
     VIR_STEAL_PTR(dst->features, src->features);
c1c534
+    dst->microcodeVersion = src->microcodeVersion;
c1c534
     dst->nfeatures_max = src->nfeatures_max;
c1c534
     src->nfeatures_max = 0;
c1c534
     dst->nfeatures = src->nfeatures;
c1c534
@@ -382,6 +384,14 @@ virCPUDefParseXML(xmlXPathContextPtr ctxt,
c1c534
             goto cleanup;
c1c534
         }
c1c534
         VIR_FREE(arch);
c1c534
+
c1c534
+        if (virXPathBoolean("boolean(./microcode[1]/@version)", ctxt) > 0 &&
c1c534
+            virXPathUInt("string(./microcode[1]/@version)", ctxt,
c1c534
+                         &def->microcodeVersion) < 0) {
c1c534
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
c1c534
+                           _("invalid microcode version"));
c1c534
+            goto cleanup;
c1c534
+        }
c1c534
     }
c1c534
 
c1c534
     if (!(def->model = virXPathString("string(./model[1])", ctxt)) &&
c1c534
@@ -720,6 +730,10 @@ virCPUDefFormatBuf(virBufferPtr buf,
c1c534
     if (formatModel && def->vendor)
c1c534
         virBufferEscapeString(buf, "<vendor>%s</vendor>\n", def->vendor);
c1c534
 
c1c534
+    if (def->type == VIR_CPU_TYPE_HOST && def->microcodeVersion)
c1c534
+        virBufferAsprintf(buf, "<microcode version='%u'/>\n",
c1c534
+                          def->microcodeVersion);
c1c534
+
c1c534
     if (def->sockets && def->cores && def->threads) {
c1c534
         virBufferAddLit(buf, "
c1c534
         virBufferAsprintf(buf, " sockets='%u'", def->sockets);
c1c534
diff --git a/src/conf/cpu_conf.h b/src/conf/cpu_conf.h
c1c534
index d1983f5d4f..9f2e7ee264 100644
c1c534
--- a/src/conf/cpu_conf.h
c1c534
+++ b/src/conf/cpu_conf.h
c1c534
@@ -133,6 +133,7 @@ struct _virCPUDef {
c1c534
     char *vendor_id;    /* vendor id returned by CPUID in the guest */
c1c534
     int fallback;       /* enum virCPUFallback */
c1c534
     char *vendor;
c1c534
+    unsigned int microcodeVersion;
c1c534
     unsigned int sockets;
c1c534
     unsigned int cores;
c1c534
     unsigned int threads;
c1c534
diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c
c1c534
index 693e571a3d..ad35532fc1 100644
c1c534
--- a/src/cpu/cpu_x86.c
c1c534
+++ b/src/cpu/cpu_x86.c
c1c534
@@ -33,6 +33,7 @@
c1c534
 #include "virbuffer.h"
c1c534
 #include "virendian.h"
c1c534
 #include "virstring.h"
c1c534
+#include "virhostcpu.h"
c1c534
 
c1c534
 #define VIR_FROM_THIS VIR_FROM_CPU
c1c534
 
c1c534
@@ -153,6 +154,8 @@ struct _virCPUx86Map {
c1c534
 };
c1c534
 
c1c534
 static virCPUx86MapPtr cpuMap;
c1c534
+static unsigned int microcodeVersion;
c1c534
+
c1c534
 int virCPUx86DriverOnceInit(void);
c1c534
 VIR_ONCE_GLOBAL_INIT(virCPUx86Driver);
c1c534
 
c1c534
@@ -1409,6 +1412,8 @@ virCPUx86DriverOnceInit(void)
c1c534
     if (!(cpuMap = virCPUx86LoadMap()))
c1c534
         return -1;
c1c534
 
c1c534
+    microcodeVersion = virHostCPUGetMicrocodeVersion();
c1c534
+
c1c534
     return 0;
c1c534
 }
c1c534
 
c1c534
@@ -2424,6 +2429,9 @@ virCPUx86GetHost(virCPUDefPtr cpu,
c1c534
     virCPUDataPtr cpuData = NULL;
c1c534
     int ret = -1;
c1c534
 
c1c534
+    if (virCPUx86DriverInitialize() < 0)
c1c534
+        goto cleanup;
c1c534
+
c1c534
     if (!(cpuData = virCPUDataNew(archs[0])))
c1c534
         goto cleanup;
c1c534
 
c1c534
@@ -2432,6 +2440,7 @@ virCPUx86GetHost(virCPUDefPtr cpu,
c1c534
         goto cleanup;
c1c534
 
c1c534
     ret = x86DecodeCPUData(cpu, cpuData, models);
c1c534
+    cpu->microcodeVersion = microcodeVersion;
c1c534
 
c1c534
  cleanup:
c1c534
     virCPUx86DataFree(cpuData);
c1c534
-- 
c1c534
2.15.1
c1c534