From f9593ce3e696291570f595026f7598b2fc064d5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= Date: Sat, 23 Feb 2019 01:39:51 +0100 Subject: [PATCH] vm: allow files in kernels_dir override built-in default kernelopts If default-kernelopts-pci.txt is present, it will override default built-in kernelopts for the VMs with PCI device assigned. Similarly if default-kernelopts-nopci.txt is present, it will override default kernelopts for VMs without PCI devices. For template-based VMs, kernelopts of the template takes precedence over default-kernelopts-nopci.txt but not default-kernelopts-pci.txt. Fixes QubesOS/qubes-issues#4839 --- qubes/tests/vm/qubesvm.py | 29 ++++++++++++++++++++++++++++ qubes/vm/qubesvm.py | 40 ++++++++++++++++++++++++++++++++++----- 2 files changed, 64 insertions(+), 5 deletions(-) diff --git a/qubes/tests/vm/qubesvm.py b/qubes/tests/vm/qubesvm.py index 42988cfa..8a7d759b 100644 --- a/qubes/tests/vm/qubesvm.py +++ b/qubes/tests/vm/qubesvm.py @@ -21,6 +21,7 @@ # import base64 import os +import tempfile import unittest import uuid @@ -480,8 +481,15 @@ class TC_90_QubesVM(QubesVMTestsMixin, qubes.tests.QubesTestCase): self.assertPropertyValue(vm, 'kernel', '', '', '') self.assertPropertyValue(vm, 'kernel', None, '', '') + @unittest.mock.patch.dict(qubes.config.system_path, + {'qubes_kernels_base_dir': '/tmp'}) def test_260_kernelopts(self): + d = tempfile.mkdtemp(prefix='/tmp/') + self.addCleanup(shutil.rmtree, d) + open(d + '/vmlinuz', 'w').close() + open(d + '/initramfs', 'w').close() vm = self.get_vm() + vm.kernel = os.path.basename(d) self.assertPropertyDefaultValue(vm, 'kernelopts', qubes.config.defaults['kernelopts']) self.assertPropertyValue(vm, 'kernelopts', 'some options', @@ -503,6 +511,27 @@ class TC_90_QubesVM(QubesVMTestsMixin, qubes.tests.QubesTestCase): self.assertPropertyDefaultValue(vm, 'kernelopts', qubes.config.defaults['kernelopts_pcidevs']) + @unittest.mock.patch.dict(qubes.config.system_path, + {'qubes_kernels_base_dir': '/tmp'}) + def test_262_kernelopts(self): + d = tempfile.mkdtemp(prefix='/tmp/') + self.addCleanup(shutil.rmtree, d) + open(d + '/vmlinuz', 'w').close() + open(d + '/initramfs', 'w').close() + with open(d + '/default-kernelopts-nopci.txt', 'w') as f: + f.write('some default options') + vm = self.get_vm() + vm.kernel = os.path.basename(d) + self.assertPropertyDefaultValue(vm, 'kernelopts', + 'some default options') + self.assertPropertyValue(vm, 'kernelopts', 'some options', + 'some options', 'some options') + del vm.kernelopts + self.assertPropertyDefaultValue(vm, 'kernelopts', + 'some default options') + self.assertPropertyValue(vm, 'kernelopts', '', + '', '') + def test_270_qrexec_timeout(self): vm = self.get_vm() self.assertPropertyDefaultValue(vm, 'qrexec_timeout', 60) diff --git a/qubes/vm/qubesvm.py b/qubes/vm/qubesvm.py index a8d3ecc4..d1b83d10 100644 --- a/qubes/vm/qubesvm.py +++ b/qubes/vm/qubesvm.py @@ -148,6 +148,38 @@ def _default_maxmem(self): return _default_with_template('maxmem', default_maxmem)(self) +def _default_kernelopts(self): + ''' + Return default kernel options for the given kernel. If kernel directory + contains 'default-kernelopts-{pci,nopci}.txt' file, use that. Otherwise + use built-in defaults. + For qubes without PCI devices, kernelopts of qube's template are + considered (for template-based qubes). + ''' + if not self.kernel: + return '' + if 'kernel' in self.volumes: + kernels_dir = self.storage.kernels_dir + else: + kernels_dir = os.path.join( + qubes.config.system_path['qubes_kernels_base_dir'], + self.kernel) + pci = bool(list(self.devices['pci'].persistent())) + if pci: + path = os.path.join(kernels_dir, 'default-kernelopts-pci.txt') + else: + try: + return self.template.kernelopts + except AttributeError: + pass + path = os.path.join(kernels_dir, 'default-kernelopts-nopci.txt') + if os.path.exists(path): + with open(path) as f_kernelopts: + return f_kernelopts.read().strip() + else: + return (qubes.config.defaults['kernelopts_pcidevs'] if pci else + qubes.config.defaults['kernelopts']) + class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM): '''Base functionality of Qubes VM shared between all VMs. @@ -514,11 +546,7 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM): # CORE2: swallowed uses_default_kernelopts # pylint: disable=no-member kernelopts = qubes.property('kernelopts', type=str, load_stage=4, - default=(lambda self: qubes.config.defaults['kernelopts_pcidevs'] - # pylint: disable=no-member - if list(self.devices['pci'].persistent()) - else self.template.kernelopts if hasattr(self, 'template') - else qubes.config.defaults['kernelopts']), + default=_default_kernelopts, doc='Kernel command line passed to domain. TemplateBasedVMs use its ' 'template\'s value by default.') @@ -1982,6 +2010,8 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM): return None + + # # helper methods #