tools: reset private volume when importing template over existing one
Reinstalling template is a recommended way to get it back to a clean state after potential compromise. In that case it is essential to discard any persistent storage of old template, as it could be used by the attacker to re-compromise it after reinstall. Do this similar as root volume is overridden - via volume import function. Fixes QubesOS/qubes-issues#5192
This commit is contained in:
parent
21569b3a31
commit
fdc632c959
@ -160,6 +160,21 @@ class TC_00_qvm_template_postprocess(qubesadmin.tests.QubesTestCase):
|
|||||||
vm, template_dir)
|
vm, template_dir)
|
||||||
self.assertAllCalled()
|
self.assertAllCalled()
|
||||||
|
|
||||||
|
def test_005_reset_private_img(self):
|
||||||
|
self.app.qubesd_connection_type = 'socket'
|
||||||
|
|
||||||
|
self.app.expected_calls[('dom0', 'admin.vm.List', None, None)] = \
|
||||||
|
b'0\0test-vm class=TemplateVM state=Halted\n'
|
||||||
|
self.app.expected_calls[
|
||||||
|
('test-vm', 'admin.vm.volume.List', None, None)] = \
|
||||||
|
b'0\0root\nprivate\nvolatile\nkernel\n'
|
||||||
|
self.app.expected_calls[('test-vm', 'admin.vm.volume.Import', 'private',
|
||||||
|
b'')] = b'0\0'
|
||||||
|
|
||||||
|
vm = self.app.domains['test-vm']
|
||||||
|
qubesadmin.tools.qvm_template_postprocess.reset_private_img(vm)
|
||||||
|
self.assertAllCalled()
|
||||||
|
|
||||||
def test_010_import_appmenus(self):
|
def test_010_import_appmenus(self):
|
||||||
with open(os.path.join(self.source_dir.name,
|
with open(os.path.join(self.source_dir.name,
|
||||||
'vm-whitelisted-appmenus.list'), 'w') as f:
|
'vm-whitelisted-appmenus.list'), 'w') as f:
|
||||||
@ -314,8 +329,9 @@ class TC_00_qvm_template_postprocess(qubesadmin.tests.QubesTestCase):
|
|||||||
|
|
||||||
@mock.patch('qubesadmin.tools.qvm_template_postprocess.import_appmenus')
|
@mock.patch('qubesadmin.tools.qvm_template_postprocess.import_appmenus')
|
||||||
@mock.patch('qubesadmin.tools.qvm_template_postprocess.import_root_img')
|
@mock.patch('qubesadmin.tools.qvm_template_postprocess.import_root_img')
|
||||||
def test_021_post_install_reinstall(self, mock_import_root_img,
|
@mock.patch('qubesadmin.tools.qvm_template_postprocess.reset_private_img')
|
||||||
mock_import_appmenus):
|
def test_021_post_install_reinstall(self, mock_reset_private_img,
|
||||||
|
mock_import_root_img, mock_import_appmenus):
|
||||||
self.app.expected_calls[('dom0', 'admin.vm.List', None, None)] = \
|
self.app.expected_calls[('dom0', 'admin.vm.List', None, None)] = \
|
||||||
b'0\0test-vm class=TemplateVM state=Halted\n'
|
b'0\0test-vm class=TemplateVM state=Halted\n'
|
||||||
self.app.add_new_vm = mock.Mock()
|
self.app.add_new_vm = mock.Mock()
|
||||||
@ -353,6 +369,8 @@ class TC_00_qvm_template_postprocess(qubesadmin.tests.QubesTestCase):
|
|||||||
self.assertFalse(self.app.add_new_vm.called)
|
self.assertFalse(self.app.add_new_vm.called)
|
||||||
mock_import_root_img.assert_called_once_with(self.app.domains[
|
mock_import_root_img.assert_called_once_with(self.app.domains[
|
||||||
'test-vm'], self.source_dir.name)
|
'test-vm'], self.source_dir.name)
|
||||||
|
mock_reset_private_img.assert_called_once_with(self.app.domains[
|
||||||
|
'test-vm'])
|
||||||
mock_import_appmenus.assert_called_once_with(self.app.domains[
|
mock_import_appmenus.assert_called_once_with(self.app.domains[
|
||||||
'test-vm'], self.source_dir.name)
|
'test-vm'], self.source_dir.name)
|
||||||
if qubesadmin.tools.qvm_template_postprocess.have_events:
|
if qubesadmin.tools.qvm_template_postprocess.have_events:
|
||||||
@ -366,8 +384,9 @@ class TC_00_qvm_template_postprocess(qubesadmin.tests.QubesTestCase):
|
|||||||
|
|
||||||
@mock.patch('qubesadmin.tools.qvm_template_postprocess.import_appmenus')
|
@mock.patch('qubesadmin.tools.qvm_template_postprocess.import_appmenus')
|
||||||
@mock.patch('qubesadmin.tools.qvm_template_postprocess.import_root_img')
|
@mock.patch('qubesadmin.tools.qvm_template_postprocess.import_root_img')
|
||||||
def test_022_post_install_skip_start(self, mock_import_root_img,
|
@mock.patch('qubesadmin.tools.qvm_template_postprocess.reset_private_img')
|
||||||
mock_import_appmenus):
|
def test_022_post_install_skip_start(self, mock_reset_private_img,
|
||||||
|
mock_import_root_img, mock_import_appmenus):
|
||||||
self.app.expected_calls[('dom0', 'admin.vm.List', None, None)] = \
|
self.app.expected_calls[('dom0', 'admin.vm.List', None, None)] = \
|
||||||
b'0\0test-vm class=TemplateVM state=Halted\n'
|
b'0\0test-vm class=TemplateVM state=Halted\n'
|
||||||
self.app.expected_calls[
|
self.app.expected_calls[
|
||||||
@ -391,6 +410,8 @@ class TC_00_qvm_template_postprocess(qubesadmin.tests.QubesTestCase):
|
|||||||
self.assertFalse(self.app.add_new_vm.called)
|
self.assertFalse(self.app.add_new_vm.called)
|
||||||
mock_import_root_img.assert_called_once_with(self.app.domains[
|
mock_import_root_img.assert_called_once_with(self.app.domains[
|
||||||
'test-vm'], self.source_dir.name)
|
'test-vm'], self.source_dir.name)
|
||||||
|
mock_reset_private_img.assert_called_once_with(self.app.domains[
|
||||||
|
'test-vm'])
|
||||||
mock_import_appmenus.assert_called_once_with(self.app.domains[
|
mock_import_appmenus.assert_called_once_with(self.app.domains[
|
||||||
'test-vm'], self.source_dir.name)
|
'test-vm'], self.source_dir.name)
|
||||||
if qubesadmin.tools.qvm_template_postprocess.have_events:
|
if qubesadmin.tools.qvm_template_postprocess.have_events:
|
||||||
|
@ -122,6 +122,12 @@ def import_root_img(vm, source_dir):
|
|||||||
root_size, str(err)))
|
root_size, str(err)))
|
||||||
|
|
||||||
|
|
||||||
|
def reset_private_img(vm):
|
||||||
|
'''Clear private volume'''
|
||||||
|
with open('/dev/null', 'rb') as null:
|
||||||
|
vm.volumes['private'].import_data(stream=null)
|
||||||
|
|
||||||
|
|
||||||
def import_appmenus(vm, source_dir):
|
def import_appmenus(vm, source_dir):
|
||||||
'''Import appmenus settings into VM object (later: GUI VM)'''
|
'''Import appmenus settings into VM object (later: GUI VM)'''
|
||||||
if os.getuid() == 0:
|
if os.getuid() == 0:
|
||||||
@ -232,6 +238,9 @@ def post_install(args):
|
|||||||
if vm_created:
|
if vm_created:
|
||||||
del app.domains[vm.name]
|
del app.domains[vm.name]
|
||||||
raise
|
raise
|
||||||
|
if not vm_created:
|
||||||
|
vm.log.info('Clearing private volume')
|
||||||
|
reset_private_img(vm)
|
||||||
vm.installed_by_rpm = True
|
vm.installed_by_rpm = True
|
||||||
import_appmenus(vm, args.dir)
|
import_appmenus(vm, args.dir)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user