|
|
3d61c0 |
From 50eaeeb15e51030ac9548a90e7388868a645ecca Mon Sep 17 00:00:00 2001
|
|
|
3d61c0 |
Message-Id: <50eaeeb15e51030ac9548a90e7388868a645ecca@dist-git>
|
|
|
3d61c0 |
From: Pavel Hrdina <phrdina@redhat.com>
|
|
|
3d61c0 |
Date: Wed, 3 Apr 2019 15:23:20 +0200
|
|
|
3d61c0 |
Subject: [PATCH] virt-manager: add new checkbox to control CPU security
|
|
|
3d61c0 |
features
|
|
|
3d61c0 |
MIME-Version: 1.0
|
|
|
3d61c0 |
Content-Type: text/plain; charset=UTF-8
|
|
|
3d61c0 |
Content-Transfer-Encoding: 8bit
|
|
|
3d61c0 |
|
|
|
3d61c0 |
By default we copy CPU security features to the guest if specific CPU
|
|
|
3d61c0 |
model is selected. However, this may break migration and will affect
|
|
|
3d61c0 |
performance of the guest. This adds an option to disable this default
|
|
|
3d61c0 |
behavior.
|
|
|
3d61c0 |
|
|
|
3d61c0 |
The checkbox is clickable only on x86 and only on host where we can
|
|
|
3d61c0 |
detect any CPU security features, otherwise a tooltip is set to notify
|
|
|
3d61c0 |
users that there is nothing to copy.
|
|
|
3d61c0 |
|
|
|
3d61c0 |
Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
|
|
|
3d61c0 |
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
|
|
|
3d61c0 |
(cherry picked from commit 8720637cff7b0766d9e27a60b0f81740176d70c8)
|
|
|
3d61c0 |
|
|
|
3d61c0 |
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1582667
|
|
|
3d61c0 |
|
|
|
3d61c0 |
Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
|
|
|
3d61c0 |
Reviewed-by: Cole Robinson <crobinso@redhat.com>
|
|
|
3d61c0 |
---
|
|
|
3d61c0 |
ui/details.ui | 15 +++++++++++++++
|
|
|
3d61c0 |
virtManager/details.py | 21 +++++++++++++++++++++
|
|
|
3d61c0 |
virtManager/domain.py | 5 +++--
|
|
|
3d61c0 |
virtinst/cpu.py | 30 ++++++++++++++++++++++++++++++
|
|
|
3d61c0 |
4 files changed, 69 insertions(+), 2 deletions(-)
|
|
|
3d61c0 |
|
|
|
3d61c0 |
diff --git a/ui/details.ui b/ui/details.ui
|
|
|
3d61c0 |
index e0689f4d..6fe5e18a 100644
|
|
|
3d61c0 |
--- a/ui/details.ui
|
|
|
3d61c0 |
+++ b/ui/details.ui
|
|
|
3d61c0 |
@@ -2213,6 +2213,21 @@
|
|
|
3d61c0 |
<property name="top_attach">1</property>
|
|
|
3d61c0 |
</packing>
|
|
|
3d61c0 |
</child>
|
|
|
3d61c0 |
+ <child>
|
|
|
3d61c0 |
+ <object class="GtkCheckButton" id="cpu-secure">
|
|
|
3d61c0 |
+ <property name="label" translatable="yes">Enable available CPU security flaw mitigations</property>
|
|
|
3d61c0 |
+ <property name="visible">True</property>
|
|
|
3d61c0 |
+ <property name="can_focus">True</property>
|
|
|
3d61c0 |
+ <property name="receives_default">False</property>
|
|
|
3d61c0 |
+ <property name="draw_indicator">True</property>
|
|
|
3d61c0 |
+ <signal name="toggled" handler="on_cpu_secure_toggled" swapped="no"/>
|
|
|
3d61c0 |
+ </object>
|
|
|
3d61c0 |
+ <packing>
|
|
|
3d61c0 |
+ <property name="left_attach">0</property>
|
|
|
3d61c0 |
+ <property name="top_attach">2</property>
|
|
|
3d61c0 |
+ <property name="width">2</property>
|
|
|
3d61c0 |
+ </packing>
|
|
|
3d61c0 |
+ </child>
|
|
|
3d61c0 |
</object>
|
|
|
3d61c0 |
</child>
|
|
|
3d61c0 |
</object>
|
|
|
3d61c0 |
diff --git a/virtManager/details.py b/virtManager/details.py
|
|
|
3d61c0 |
index 65fea500..e5028b25 100644
|
|
|
3d61c0 |
--- a/virtManager/details.py
|
|
|
3d61c0 |
+++ b/virtManager/details.py
|
|
|
3d61c0 |
@@ -507,6 +507,7 @@ class vmmDetails(vmmGObjectUI):
|
|
|
3d61c0 |
"on_cpu_maxvcpus_changed": self.config_maxvcpus_changed,
|
|
|
3d61c0 |
"on_cpu_model_changed": lambda *x: self.config_cpu_model_changed(x),
|
|
|
3d61c0 |
"on_cpu_copy_host_clicked": self.on_cpu_copy_host_clicked,
|
|
|
3d61c0 |
+ "on_cpu_secure_toggled": self.on_cpu_secure_toggled,
|
|
|
3d61c0 |
"on_cpu_cores_changed": self.config_cpu_topology_changed,
|
|
|
3d61c0 |
"on_cpu_sockets_changed": self.config_cpu_topology_changed,
|
|
|
3d61c0 |
"on_cpu_threads_changed": self.config_cpu_topology_changed,
|
|
|
3d61c0 |
@@ -1700,6 +1701,11 @@ class vmmDetails(vmmGObjectUI):
|
|
|
3d61c0 |
def on_cpu_copy_host_clicked(self, src):
|
|
|
3d61c0 |
uiutil.set_grid_row_visible(
|
|
|
3d61c0 |
self.widget("cpu-model"), not src.get_active())
|
|
|
3d61c0 |
+ uiutil.set_grid_row_visible(
|
|
|
3d61c0 |
+ self.widget("cpu-secure"), not src.get_active())
|
|
|
3d61c0 |
+ self.enable_apply(EDIT_CPU)
|
|
|
3d61c0 |
+
|
|
|
3d61c0 |
+ def on_cpu_secure_toggled(self, ignore):
|
|
|
3d61c0 |
self.enable_apply(EDIT_CPU)
|
|
|
3d61c0 |
|
|
|
3d61c0 |
def config_cpu_model_changed(self, ignore):
|
|
|
3d61c0 |
@@ -1999,6 +2005,7 @@ class vmmDetails(vmmGObjectUI):
|
|
|
3d61c0 |
|
|
|
3d61c0 |
if self.edited(EDIT_CPU):
|
|
|
3d61c0 |
kwargs["model"] = self.get_config_cpu_model()
|
|
|
3d61c0 |
+ kwargs["secure"] = self.widget("cpu-secure").get_active()
|
|
|
3d61c0 |
|
|
|
3d61c0 |
if self.edited(EDIT_TOPOLOGY):
|
|
|
3d61c0 |
do_top = self.widget("cpu-topology-enable").get_active()
|
|
|
3d61c0 |
@@ -2529,6 +2536,11 @@ class vmmDetails(vmmGObjectUI):
|
|
|
3d61c0 |
n1, n2 = self.vm.network_traffic_vectors()
|
|
|
3d61c0 |
self.network_traffic_graph.set_property("data_array", n1 + n2)
|
|
|
3d61c0 |
|
|
|
3d61c0 |
+ def _cpu_secure_is_available(self):
|
|
|
3d61c0 |
+ domcaps = self.vm.get_domain_capabilities()
|
|
|
3d61c0 |
+ features = domcaps.get_cpu_security_features()
|
|
|
3d61c0 |
+ return self.vm.get_xmlobj().os.is_x86() and len(features) > 0
|
|
|
3d61c0 |
+
|
|
|
3d61c0 |
def refresh_config_cpu(self):
|
|
|
3d61c0 |
# Set topology first, because it impacts maxvcpus values
|
|
|
3d61c0 |
cpu = self.vm.get_cpu_config()
|
|
|
3d61c0 |
@@ -2582,6 +2594,15 @@ class vmmDetails(vmmGObjectUI):
|
|
|
3d61c0 |
self.widget("cpu-copy-host").set_active(bool(is_host))
|
|
|
3d61c0 |
self.on_cpu_copy_host_clicked(self.widget("cpu-copy-host"))
|
|
|
3d61c0 |
|
|
|
3d61c0 |
+ if not self._cpu_secure_is_available():
|
|
|
3d61c0 |
+ self.widget("cpu-secure").set_sensitive(False)
|
|
|
3d61c0 |
+ self.widget("cpu-secure").set_tooltip_text(
|
|
|
3d61c0 |
+ "No security features to copy, the host is missing "
|
|
|
3d61c0 |
+ "security patches or the host CPU is not vulnerable.")
|
|
|
3d61c0 |
+
|
|
|
3d61c0 |
+ cpu.check_security_features(self.vm.get_xmlobj())
|
|
|
3d61c0 |
+ self.widget("cpu-secure").set_active(cpu.secure)
|
|
|
3d61c0 |
+
|
|
|
3d61c0 |
def refresh_config_memory(self):
|
|
|
3d61c0 |
host_mem_widget = self.widget("state-host-memory")
|
|
|
3d61c0 |
host_mem = self.vm.conn.host_memory_size() // 1024
|
|
|
3d61c0 |
diff --git a/virtManager/domain.py b/virtManager/domain.py
|
|
|
3d61c0 |
index 7c1f511d..c423a177 100644
|
|
|
3d61c0 |
--- a/virtManager/domain.py
|
|
|
3d61c0 |
+++ b/virtManager/domain.py
|
|
|
3d61c0 |
@@ -647,7 +647,7 @@ class vmmDomain(vmmLibvirtObject):
|
|
|
3d61c0 |
self._redefine_xmlobj(xmlobj)
|
|
|
3d61c0 |
|
|
|
3d61c0 |
def define_cpu(self, vcpus=_SENTINEL, maxvcpus=_SENTINEL,
|
|
|
3d61c0 |
- model=_SENTINEL, sockets=_SENTINEL,
|
|
|
3d61c0 |
+ model=_SENTINEL, secure=_SENTINEL, sockets=_SENTINEL,
|
|
|
3d61c0 |
cores=_SENTINEL, threads=_SENTINEL):
|
|
|
3d61c0 |
guest = self._make_xmlobj_to_define()
|
|
|
3d61c0 |
|
|
|
3d61c0 |
@@ -661,7 +661,8 @@ class vmmDomain(vmmLibvirtObject):
|
|
|
3d61c0 |
guest.cpu.cores = cores
|
|
|
3d61c0 |
guest.cpu.threads = threads
|
|
|
3d61c0 |
|
|
|
3d61c0 |
- if model != _SENTINEL:
|
|
|
3d61c0 |
+ if secure != _SENTINEL or model != _SENTINEL:
|
|
|
3d61c0 |
+ guest.cpu.secure = secure
|
|
|
3d61c0 |
if model in guest.cpu.SPECIAL_MODES:
|
|
|
3d61c0 |
guest.cpu.set_special_mode(guest, model)
|
|
|
3d61c0 |
else:
|
|
|
3d61c0 |
diff --git a/virtinst/cpu.py b/virtinst/cpu.py
|
|
|
3d61c0 |
index 4776f90e..c76f06e8 100644
|
|
|
3d61c0 |
--- a/virtinst/cpu.py
|
|
|
3d61c0 |
+++ b/virtinst/cpu.py
|
|
|
3d61c0 |
@@ -145,6 +145,36 @@ class CPU(XMLBuilder):
|
|
|
3d61c0 |
if not exists:
|
|
|
3d61c0 |
self.add_feature(feature)
|
|
|
3d61c0 |
|
|
|
3d61c0 |
+ def check_security_features(self, guest):
|
|
|
3d61c0 |
+ """
|
|
|
3d61c0 |
+ Since 'secure' property is not exported into the domain XML
|
|
|
3d61c0 |
+ we might need to refresh its state.
|
|
|
3d61c0 |
+ """
|
|
|
3d61c0 |
+ domcaps = guest.lookup_domcaps()
|
|
|
3d61c0 |
+ features = domcaps.get_cpu_security_features()
|
|
|
3d61c0 |
+
|
|
|
3d61c0 |
+ if len(features) == 0:
|
|
|
3d61c0 |
+ self.secure = False
|
|
|
3d61c0 |
+ return
|
|
|
3d61c0 |
+
|
|
|
3d61c0 |
+ for feature in features:
|
|
|
3d61c0 |
+ exists = False
|
|
|
3d61c0 |
+ for f in self.features:
|
|
|
3d61c0 |
+ if f.name == feature and f.policy == "require":
|
|
|
3d61c0 |
+ exists = True
|
|
|
3d61c0 |
+ break
|
|
|
3d61c0 |
+ if not exists:
|
|
|
3d61c0 |
+ self.secure = False
|
|
|
3d61c0 |
+ return
|
|
|
3d61c0 |
+
|
|
|
3d61c0 |
+ def _remove_security_features(self, guest):
|
|
|
3d61c0 |
+ domcaps = guest.lookup_domcaps()
|
|
|
3d61c0 |
+ for feature in domcaps.get_cpu_security_features():
|
|
|
3d61c0 |
+ for f in self.features:
|
|
|
3d61c0 |
+ if f.name == feature and f.policy == "require":
|
|
|
3d61c0 |
+ self.remove_child(f)
|
|
|
3d61c0 |
+ break
|
|
|
3d61c0 |
+
|
|
|
3d61c0 |
def set_model(self, guest, val):
|
|
|
3d61c0 |
logging.debug("setting cpu model %s", val)
|
|
|
3d61c0 |
if val:
|
|
|
3d61c0 |
--
|
|
|
3d61c0 |
2.20.1
|
|
|
3d61c0 |
|