Browse Source

Merge branch 'kernelopts-files'

* kernelopts-files:
  vm: allow files in kernels_dir override built-in default kernelopts
Marek Marczykowski-Górecki 5 years ago
parent
commit
60bbbdd702
2 changed files with 62 additions and 5 deletions
  1. 29 0
      qubes/tests/vm/qubesvm.py
  2. 33 5
      qubes/vm/qubesvm.py

+ 29 - 0
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)

+ 33 - 5
qubes/vm/qubesvm.py

@@ -152,6 +152,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.
@@ -518,11 +550,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.')