From c05e60de1acb174bb40257d3481267e35dc62960 Mon Sep 17 00:00:00 2001 Message-Id: From: Pavel Hrdina Date: Wed, 15 May 2019 10:37:53 +0200 Subject: [PATCH] virt-manager: add new checkbox to control CPU security features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By default we copy CPU security features to the guest if specific CPU model is selected. However, this may break migration and will affect performance of the guest. This adds an option to disable this default behavior. The checkbox is clickable only on x86 and only on host where we can detect any CPU security features, otherwise a tooltip is set to notify users that there is nothing to copy. Signed-off-by: Pavel Hrdina Reviewed-by: Daniel P. Berrangé (cherry picked from commit 8720637cff7b0766d9e27a60b0f81740176d70c8) Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1716402 Signed-off-by: Pavel Hrdina --- ui/details.ui | 15 +++++++++++++++ virtManager/details.py | 21 +++++++++++++++++++++ virtManager/domain.py | 5 +++-- virtinst/domain/cpu.py | 30 ++++++++++++++++++++++++++++++ 4 files changed, 69 insertions(+), 2 deletions(-) diff --git a/ui/details.ui b/ui/details.ui index c18070c8..1e1be759 100644 --- a/ui/details.ui +++ b/ui/details.ui @@ -2122,6 +2122,21 @@ 1 + + + Enable available CPU security flaw mitigations + True + True + False + True + + + + 0 + 2 + 2 + + diff --git a/virtManager/details.py b/virtManager/details.py index b7e7fc14..b8899d77 100644 --- a/virtManager/details.py +++ b/virtManager/details.py @@ -523,6 +523,7 @@ class vmmDetails(vmmGObjectUI): "on_cpu_maxvcpus_changed": self.config_maxvcpus_changed, "on_cpu_model_changed": lambda *x: self.config_cpu_model_changed(x), "on_cpu_copy_host_clicked": self.on_cpu_copy_host_clicked, + "on_cpu_secure_toggled": self.on_cpu_secure_toggled, "on_cpu_cores_changed": self.config_cpu_topology_changed, "on_cpu_sockets_changed": self.config_cpu_topology_changed, "on_cpu_threads_changed": self.config_cpu_topology_changed, @@ -1716,6 +1717,11 @@ class vmmDetails(vmmGObjectUI): def on_cpu_copy_host_clicked(self, src): uiutil.set_grid_row_visible( self.widget("cpu-model"), not src.get_active()) + uiutil.set_grid_row_visible( + self.widget("cpu-secure"), not src.get_active()) + self.enable_apply(EDIT_CPU) + + def on_cpu_secure_toggled(self, ignore): self.enable_apply(EDIT_CPU) def config_cpu_model_changed(self, ignore): @@ -2014,6 +2020,7 @@ class vmmDetails(vmmGObjectUI): if self.edited(EDIT_CPU): kwargs["model"] = self.get_config_cpu_model() + kwargs["secure"] = self.widget("cpu-secure").get_active() if self.edited(EDIT_TOPOLOGY): do_top = self.widget("cpu-topology-enable").get_active() @@ -2574,6 +2581,11 @@ class vmmDetails(vmmGObjectUI): n1, n2 = self.vm.network_traffic_vectors() self.network_traffic_graph.set_property("data_array", n1 + n2) + def _cpu_secure_is_available(self): + domcaps = self.vm.get_domain_capabilities() + features = domcaps.get_cpu_security_features() + return self.vm.get_xmlobj().os.is_x86() and len(features) > 0 + def refresh_config_cpu(self): # Set topology first, because it impacts maxvcpus values cpu = self.vm.get_cpu_config() @@ -2627,6 +2639,15 @@ class vmmDetails(vmmGObjectUI): self.widget("cpu-copy-host").set_active(bool(is_host)) self.on_cpu_copy_host_clicked(self.widget("cpu-copy-host")) + if not self._cpu_secure_is_available(): + self.widget("cpu-secure").set_sensitive(False) + self.widget("cpu-secure").set_tooltip_text( + "No security features to copy, the host is missing " + "security patches or the host CPU is not vulnerable.") + + cpu.check_security_features(self.vm.get_xmlobj()) + self.widget("cpu-secure").set_active(cpu.secure) + def refresh_config_memory(self): host_mem_widget = self.widget("state-host-memory") host_mem = self.vm.conn.host_memory_size() // 1024 diff --git a/virtManager/domain.py b/virtManager/domain.py index 5b3f1e44..c8f4e822 100644 --- a/virtManager/domain.py +++ b/virtManager/domain.py @@ -495,7 +495,7 @@ class vmmDomain(vmmLibvirtObject): self._redefine_xmlobj(xmlobj) def define_cpu(self, vcpus=_SENTINEL, maxvcpus=_SENTINEL, - model=_SENTINEL, sockets=_SENTINEL, + model=_SENTINEL, secure=_SENTINEL, sockets=_SENTINEL, cores=_SENTINEL, threads=_SENTINEL): guest = self._make_xmlobj_to_define() @@ -509,7 +509,8 @@ class vmmDomain(vmmLibvirtObject): guest.cpu.cores = cores guest.cpu.threads = threads - if model != _SENTINEL: + if secure != _SENTINEL or model != _SENTINEL: + guest.cpu.secure = secure if model in guest.cpu.SPECIAL_MODES: guest.cpu.set_special_mode(guest, model) else: diff --git a/virtinst/domain/cpu.py b/virtinst/domain/cpu.py index ab40f788..c6a411bb 100644 --- a/virtinst/domain/cpu.py +++ b/virtinst/domain/cpu.py @@ -123,6 +123,36 @@ class DomainCpu(XMLBuilder): if not exists: self.add_feature(feature) + def check_security_features(self, guest): + """ + Since 'secure' property is not exported into the domain XML + we might need to refresh its state. + """ + domcaps = guest.lookup_domcaps() + features = domcaps.get_cpu_security_features() + + if len(features) == 0: + self.secure = False + return + + for feature in features: + exists = False + for f in self.features: + if f.name == feature and f.policy == "require": + exists = True + break + if not exists: + self.secure = False + return + + def _remove_security_features(self, guest): + domcaps = guest.lookup_domcaps() + for feature in domcaps.get_cpu_security_features(): + for f in self.features: + if f.name == feature and f.policy == "require": + self.remove_child(f) + break + def set_model(self, guest, val): logging.debug("setting cpu model %s", val) if val: -- 2.21.0