Skip to content

Commit 4a98ef3

Browse files
committed
(wip) Add boot mode support
1 parent 6828311 commit 4a98ef3

4 files changed

Lines changed: 88 additions & 5 deletions

File tree

qubes/ext/core_features.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
import qubes.ext
2525

2626
_version_re = re.compile(r"[0-9]{1,3}\.[0-9]{1,3}")
27+
_bootmode_name_key_re = re.compile(r"boot-mode\.[-a-z_]*\.name$")
28+
_bootmode_kernelopts_key_re = re.compile(r"boot-mode\.[-a-z_]*\.kernelopts$")
2729

2830

2931
class CoreFeatures(qubes.ext.Extension):
@@ -104,6 +106,34 @@ async def qubes_features_request(self, vm, event, untrusted_features):
104106
untrusted_value = untrusted_features["qubes-agent-version"]
105107
if _version_re.fullmatch(untrusted_value):
106108
vm.features["qubes-agent-version"] = untrusted_value
109+
110+
# handle boot mode advertisement
111+
for _, (
112+
untrusted_feature_key, untrusted_feature_value
113+
) in enumerate(untrusted_features.items()):
114+
if not all(
115+
c in string.printable for c in untrusted_feature_value
116+
):
117+
continue
118+
if _bootmode_name_key_re.match(untrusted_feature_key):
119+
bootmode_feature = untrusted_feature_key
120+
bootmode_value = untrusted_feature_value
121+
vm.features[bootmode_feature] = bootmode_value
122+
elif _bootmode_kernelopts_key_re.match(untrusted_feature_key):
123+
# Don't allow setting the kernelopts for the default mode,
124+
# these are ignored anyway
125+
if untrusted_feature_key == \
126+
"boot-mode.default.kernelopts":
127+
continue
128+
bootmode_feature = untrusted_feature_key
129+
bootmode_value = untrusted_feature_value
130+
vm.features[bootmode_feature] = bootmode_value
131+
elif untrusted_feature_key == "boot-mode.active" or \
132+
untrusted_feature_key == "boot-mode.appvm-default":
133+
bootmode_feature = untrusted_feature_key
134+
bootmode_value = untrusted_feature_value
135+
if bootmode_feature not in vm.features:
136+
vm.features[bootmode_feature] = bootmode_value
107137
del untrusted_features
108138

109139
# default user for qvm-run etc

qubes/vm/appvm.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,22 @@ def template_changed_update_storage(self):
4040
self.storage.init_volume(volume_name, config)
4141

4242

43+
def template_changed_update_bootmode(self):
44+
"""Update boot mode configuration for TemplateVM changes"""
45+
if self.template.features.get("boot-mode.appvm-default", None) is None:
46+
self.features["boot-mode.active"] = "default"
47+
else:
48+
active_boot_mode = self.template.features["boot-mode.appvm-default"]
49+
try:
50+
_ = self.features.check_with_template(
51+
f"boot-mode.{active_boot_mode}.kernelopts"
52+
)
53+
self.features["boot-mode.active"] = active_boot_mode
54+
except KeyError:
55+
self.template.features["boot-mode.appvm-default"] = "default"
56+
self.features["boot-mode.active"] = "default"
57+
58+
4359
class AppVM(
4460
qubes.vm.mix.dvmtemplate.DVMTemplateMixin, qubes.vm.qubesvm.QubesVM
4561
):
@@ -149,8 +165,10 @@ def on_property_pre_set_template(
149165
@qubes.events.handler("property-set:template")
150166
def on_property_set_template(self, event, name, newvalue, oldvalue=None):
151167
"""Adjust root (and possibly other snap_on_start=True) volume
152-
on template change.
168+
on template change. Also switch active boot mode to match that set by
169+
the template.
153170
""" # pylint: disable=unused-argument
154171
template_changed_update_storage(self)
172+
template_changed_update_bootmode(self)
155173
for vm in self.dispvms:
156174
vm.on_property_set_template(event, name, newvalue, oldvalue)

qubes/vm/qubesvm.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,28 @@ def _setter_kbd_layout(self, prop, value):
216216
return value
217217

218218

219+
def _bootmode_kernelopts(self):
220+
"""
221+
Return the kernel options specified by the currently active boot mode,
222+
with a leading space. Force the VM's boot mode to 'default' if the active
223+
boot mode does not exist. If the active boot mode is (or ends up set to)
224+
'default', return an empty string.
225+
"""
226+
if self.features.get("boot-mode.active", None) is None:
227+
return ""
228+
if self.features["boot-mode.active"] == "default":
229+
return ""
230+
active_boot_mode = self.features["boot-mode.active"]
231+
try:
232+
kernelopts_value = self.features.check_with_template(
233+
f"boot-mode.{active_boot_mode}.kernelopts"
234+
)
235+
return f" {kernelopts_value}"
236+
except KeyError:
237+
self.features["boot-mode.active"] = "default"
238+
return ""
239+
240+
219241
def _default_virt_mode(self):
220242
if list(self.devices["pci"].get_assigned_devices()):
221243
return "hvm"
@@ -659,6 +681,15 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM):
659681
#
660682
# properties loaded from XML
661683
#
684+
bootmode_kernelopts = qubes.property(
685+
"bootmode_kernelopts",
686+
type=str,
687+
load_stage=4,
688+
default=_bootmode_kernelopts,
689+
doc="Additional kernel command line segment passed to domain, set by "
690+
"the domain's active boot mode."
691+
)
692+
662693
guivm = qubes.VMProperty(
663694
"guivm",
664695
load_stage=4,

templates/libvirt/xen.xml

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,15 +62,19 @@
6262
{% endif %}
6363
{% if vm.kernel %}
6464
{% if vm.features.check_with_template('no-default-kernelopts', False) -%}
65-
<cmdline>{{ vm.kernelopts }}</cmdline>
65+
<cmdline>{{ vm.kernelopts }}{{ vm.bootmode_kernelopts }}</cmdline>
6666
{% elif vm.features.check_with_template('apparmor', '0') == '1' -%}
67-
<cmdline>{{ vm.kernelopts_common }}{{ vm.kernelopts }} apparmor=1 security=apparmor</cmdline>
67+
<cmdline>{{ vm.kernelopts_common }}{{ vm.kernelopts }} apparmor=1 security=apparmor{{ vm.bootmode_kernelopts }}</cmdline>
6868
{% elif vm.features.check_with_template('selinux', '0') == '1' -%}
69-
<cmdline>{{ vm.kernelopts_common }}{{ vm.kernelopts }} selinux=1 security=selinux</cmdline>
69+
<cmdline>{{ vm.kernelopts_common }}{{ vm.kernelopts }} selinux=1 security=selinux{{ vm.bootmode_kernelopts }}</cmdline>
7070
{% else -%}
71-
<cmdline>{{ vm.kernelopts_common }}{{ vm.kernelopts }}</cmdline>
71+
<cmdline>{{ vm.kernelopts_common }}{{ vm.kernelopts }}{{ vm.bootmode_kernelopts }}</cmdline>
7272
{% endif -%}
7373
{% endif %}
74+
<!--
75+
Support for appending vm.bootmode_kernelopts to the kernel
76+
commandline for in-VM kernels should be added here.
77+
-->
7478
{% endblock %}
7579
</os>
7680

0 commit comments

Comments
 (0)