virt-manager: add new checkbox to control CPU security features

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 <phrdina@redhat.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
This commit is contained in:
Pavel Hrdina 2019-04-03 15:23:20 +02:00
parent 00f8dea370
commit 8720637cff
4 changed files with 69 additions and 2 deletions

View File

@ -2122,6 +2122,21 @@
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="cpu-secure">
<property name="label" translatable="yes">Enable available CPU security flaw mitigations</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="on_cpu_secure_toggled" swapped="no"/>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">2</property>
<property name="width">2</property>
</packing>
</child>
</object>
</child>
</object>

View File

@ -537,6 +537,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,
@ -1732,6 +1733,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):
@ -2032,6 +2038,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()
@ -2605,6 +2612,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()
@ -2658,6 +2670,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

View File

@ -442,7 +442,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()
@ -456,7 +456,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:

View File

@ -122,6 +122,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: