From dc0e1a548170fd916915aac5b585620231a8bc1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= Date: Sat, 23 Sep 2017 16:02:01 +0200 Subject: [PATCH] vm: do not allow deleting template property from AppVM and DispVM There is intentionally no default template in terms of qubes.property definition, to not cause problems when switching global default_template property - like breaking some VMs, or forcing the user to shutdown all of them for this. But this also means it shouldn't be allowed to reset template to "default" value, because it will result in a VM without template at all. Fixes QubesOS/qubes-issues#3115 --- qubes/tests/vm/appvm.py | 5 +++++ qubes/tests/vm/dispvm.py | 18 ++++++++++++++++++ qubes/vm/appvm.py | 6 ++++++ qubes/vm/dispvm.py | 5 +++-- 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/qubes/tests/vm/appvm.py b/qubes/tests/vm/appvm.py index 73bfc207..5dfc9c5d 100644 --- a/qubes/tests/vm/appvm.py +++ b/qubes/tests/vm/appvm.py @@ -130,6 +130,11 @@ class TC_90_AppVM(qubes.tests.vm.qubesvm.QubesVMTestsMixin, with self.assertRaises(qubes.exc.QubesVMNotHaltedError): vm.template = self.template + def test_004_template_reset(self): + vm = self.get_vm() + with self.assertRaises(qubes.exc.QubesValueError): + vm.template = qubes.property.DEFAULT + def test_500_property_migrate_template_for_dispvms(self): xml_template = ''' diff --git a/qubes/tests/vm/dispvm.py b/qubes/tests/vm/dispvm.py index f8b3174d..4236d258 100644 --- a/qubes/tests/vm/dispvm.py +++ b/qubes/tests/vm/dispvm.py @@ -103,6 +103,24 @@ class TC_00_DispVM(qubes.tests.QubesTestCase): dispvm = self.loop.run_until_complete( qubes.vm.dispvm.DispVM.from_appvm(self.appvm)) + def test_002_template_change(self): + self.appvm.template_for_dispvms = True + orig_getitem = self.app.domains.__getitem__ + with mock.patch.object(self.app, 'domains', wraps=self.app.domains) \ + as mock_domains: + mock_domains.configure_mock(**{ + 'get_new_unused_dispid': mock.Mock(return_value=42), + '__getitem__.side_effect': orig_getitem + }) + dispvm = self.app.add_new_vm(qubes.vm.dispvm.DispVM, + name='test-dispvm', template=self.appvm) + + with self.assertRaises(qubes.exc.QubesValueError): + dispvm.template = self.appvm + with self.assertRaises(qubes.exc.QubesValueError): + dispvm.template = qubes.property.DEFAULT + + def test_010_create_direct(self): self.appvm.template_for_dispvms = True orig_getitem = self.app.domains.__getitem__ diff --git a/qubes/vm/appvm.py b/qubes/vm/appvm.py index b853265b..8ab808d3 100644 --- a/qubes/vm/appvm.py +++ b/qubes/vm/appvm.py @@ -104,6 +104,12 @@ class AppVM(qubes.vm.qubesvm.QubesVM): ''' # pylint: disable=unused-argument assert self.template + @qubes.events.handler('property-pre-del:template') + def on_property_pre_del_template(self, event, name, oldvalue=None): + '''Forbid deleting template of running VM + ''' # pylint: disable=unused-argument,no-self-use + raise qubes.exc.QubesValueError('Cannot unset template') + @qubes.events.handler('property-pre-set:template') def on_property_pre_set_template(self, event, name, newvalue, oldvalue=None): diff --git a/qubes/vm/dispvm.py b/qubes/vm/dispvm.py index 67f13980..fc160b6a 100644 --- a/qubes/vm/dispvm.py +++ b/qubes/vm/dispvm.py @@ -121,8 +121,9 @@ class DispVM(qubes.vm.qubesvm.QubesVM): ''' # pylint: disable=unused-argument assert self.template - @qubes.events.handler('property-pre-set:template') - def on_property_pre_set_template(self, event, name, newvalue, + @qubes.events.handler('property-pre-set:template', + 'property-pre-del:template') + def on_property_pre_set_template(self, event, name, newvalue=None, oldvalue=None): ''' Disposable VM cannot have template changed ''' # pylint: disable=unused-argument