Support qubes.VMExec call

The feature is advertised by core-agent so that it can be used
instead of VMShell.

See QubesOS/qubes-issues#4850.
This commit is contained in:
Pawel Marczewski 2020-01-24 16:52:39 +01:00
parent 0a66a0c7dd
commit 08d83fb241
No known key found for this signature in database
GPG Key ID: DE42EE9B14F96465
5 changed files with 50 additions and 13 deletions

View File

@ -178,6 +178,7 @@ endif
cp qubes-rpc-policy/qubes.OpenURL.policy $(DESTDIR)/etc/qubes-rpc/policy/qubes.OpenURL cp qubes-rpc-policy/qubes.OpenURL.policy $(DESTDIR)/etc/qubes-rpc/policy/qubes.OpenURL
cp qubes-rpc-policy/qubes.VMShell.policy $(DESTDIR)/etc/qubes-rpc/policy/qubes.VMShell cp qubes-rpc-policy/qubes.VMShell.policy $(DESTDIR)/etc/qubes-rpc/policy/qubes.VMShell
cp qubes-rpc-policy/qubes.VMRootShell.policy $(DESTDIR)/etc/qubes-rpc/policy/qubes.VMRootShell cp qubes-rpc-policy/qubes.VMRootShell.policy $(DESTDIR)/etc/qubes-rpc/policy/qubes.VMRootShell
cp qubes-rpc-policy/qubes.VMExec.policy $(DESTDIR)/etc/qubes-rpc/policy/qubes.VMExec
cp qubes-rpc-policy/qubes.NotifyUpdates.policy $(DESTDIR)/etc/qubes-rpc/policy/qubes.NotifyUpdates cp qubes-rpc-policy/qubes.NotifyUpdates.policy $(DESTDIR)/etc/qubes-rpc/policy/qubes.NotifyUpdates
cp qubes-rpc-policy/qubes.NotifyTools.policy $(DESTDIR)/etc/qubes-rpc/policy/qubes.NotifyTools cp qubes-rpc-policy/qubes.NotifyTools.policy $(DESTDIR)/etc/qubes-rpc/policy/qubes.NotifyTools
cp qubes-rpc-policy/qubes.GetImageRGBA.policy $(DESTDIR)/etc/qubes-rpc/policy/qubes.GetImageRGBA cp qubes-rpc-policy/qubes.GetImageRGBA.policy $(DESTDIR)/etc/qubes-rpc/policy/qubes.GetImageRGBA
@ -186,7 +187,6 @@ endif
cp qubes-rpc-policy/qubes.NotifyUpdates.policy $(DESTDIR)/etc/qubes-rpc/policy/qubes.NotifyUpdates cp qubes-rpc-policy/qubes.NotifyUpdates.policy $(DESTDIR)/etc/qubes-rpc/policy/qubes.NotifyUpdates
cp qubes-rpc-policy/qubes.OpenInVM.policy $(DESTDIR)/etc/qubes-rpc/policy/qubes.OpenInVM cp qubes-rpc-policy/qubes.OpenInVM.policy $(DESTDIR)/etc/qubes-rpc/policy/qubes.OpenInVM
cp qubes-rpc-policy/qubes.StartApp.policy $(DESTDIR)/etc/qubes-rpc/policy/qubes.StartApp cp qubes-rpc-policy/qubes.StartApp.policy $(DESTDIR)/etc/qubes-rpc/policy/qubes.StartApp
cp qubes-rpc-policy/qubes.VMShell.policy $(DESTDIR)/etc/qubes-rpc/policy/qubes.VMShell
cp qubes-rpc-policy/qubes.UpdatesProxy.policy $(DESTDIR)/etc/qubes-rpc/policy/qubes.UpdatesProxy cp qubes-rpc-policy/qubes.UpdatesProxy.policy $(DESTDIR)/etc/qubes-rpc/policy/qubes.UpdatesProxy
cp qubes-rpc-policy/qubes.GetDate.policy $(DESTDIR)/etc/qubes-rpc/policy/qubes.GetDate cp qubes-rpc-policy/qubes.GetDate.policy $(DESTDIR)/etc/qubes-rpc/policy/qubes.GetDate
cp qubes-rpc-policy/qubes.ConnectTCP.policy $(DESTDIR)/etc/qubes-rpc/policy/qubes.ConnectTCP cp qubes-rpc-policy/qubes.ConnectTCP.policy $(DESTDIR)/etc/qubes-rpc/policy/qubes.ConnectTCP

View File

@ -0,0 +1,31 @@
## Note that policy parsing stops at the first match,
## so adding anything below "$anyvm $anyvm action" line will have no effect
## Please use a single # to start your custom comments
$anyvm $dispvm allow
$anyvm $anyvm deny
# WARNING: The qubes.VMExec service is dangerous and there are really few
# cases when it could be safely used. Especially when policy set to "ask" you
# have no way to know for sure what command(s) will be called. Compromissed
# source VM can substitute the command. Allowing one VM to execute
# qubes.VMExec over the other VM allows the former to TAKE FULL CONTROL over
# the later. In most cases this is not what we want!
#
# Instead we should be using task-specific qrexec services which provide
# assurance as to what program will be responding to the (untrusted) VM
# requests.
#
# It is, however, safe, in most cases, to allow ultimate control of the
# creating AppVM over the DisposableVM it creates as part of the qrexec service
# invocation. That's why by default we have "$anyvm $dispvm allow" rule. Note
# that it does _not_ allow any AppVM to execute qubes.VMExec service over any
# DispVM created in the system -- that would obviously be wrong. It only allows
# qubes.VMExec service access to the AppVM which creates the DispVM as part of
# this very service invocation.
#
# See e.g. this thread for some discussion:
# https://groups.google.com/d/msg/qubes-users/xnAByaL_bjI/3PjYdiTDW-0J
#
#

View File

@ -1,4 +1,4 @@
# -*- encoding: utf8 -*- # -*- encoding: utf-8 -*-
# #
# The Qubes OS Project, http://www.qubes-os.org # The Qubes OS Project, http://www.qubes-os.org
# #
@ -34,7 +34,8 @@ class CoreFeatures(qubes.ext.Extension):
return return
requested_features = {} requested_features = {}
for feature in ('qrexec', 'gui', 'gui-emulated', 'qubes-firewall'): for feature in (
'qrexec', 'gui', 'gui-emulated', 'qubes-firewall', 'vmexec'):
untrusted_value = untrusted_features.get(feature, None) untrusted_value = untrusted_features.get(feature, None)
if untrusted_value in ('1', '0'): if untrusted_value in ('1', '0'):
requested_features[feature] = bool(int(untrusted_value)) requested_features[feature] = bool(int(untrusted_value))
@ -53,7 +54,7 @@ class CoreFeatures(qubes.ext.Extension):
vm.features[feature] = requested_features[feature] vm.features[feature] = requested_features[feature]
# those features can be freely enabled or disabled by template # those features can be freely enabled or disabled by template
for feature in ('qubes-firewall',): for feature in ('qubes-firewall', 'vmexec'):
if feature in requested_features: if feature in requested_features:
vm.features[feature] = requested_features[feature] vm.features[feature] = requested_features[feature]

View File

@ -1,4 +1,4 @@
# -*- encoding: utf8 -*- # -*- encoding: utf-8 -*-
# #
# The Qubes OS Project, http://www.qubes-os.org # The Qubes OS Project, http://www.qubes-os.org
# #
@ -46,13 +46,15 @@ class TC_00_CoreFeatures(qubes.tests.QubesTestCase):
'gui': '1', 'gui': '1',
'version': '1', 'version': '1',
'default-user': 'user', 'default-user': 'user',
'qrexec': '1'})) 'qrexec': '1',
self.assertEqual(self.vm.mock_calls, [ 'vmexec': '1'}))
self.assertListEqual(self.vm.mock_calls, [
('features.get', ('qrexec', False), {}), ('features.get', ('qrexec', False), {}),
('features.__contains__', ('qrexec',), {}), ('features.__contains__', ('qrexec',), {}),
('features.__setitem__', ('qrexec', True), {}), ('features.__setitem__', ('qrexec', True), {}),
('features.__contains__', ('gui',), {}), ('features.__contains__', ('gui',), {}),
('features.__setitem__', ('gui', True), {}), ('features.__setitem__', ('gui', True), {}),
('features.__setitem__', ('vmexec', True), {}),
('features.get', ('qrexec', False), {}), ('features.get', ('qrexec', False), {}),
('fire_event_async', ('template-postinstall',), {}), ('fire_event_async', ('template-postinstall',), {}),
('fire_event_async().__iter__', (), {}), ('fire_event_async().__iter__', (), {}),
@ -66,13 +68,15 @@ class TC_00_CoreFeatures(qubes.tests.QubesTestCase):
'gui': '0', 'gui': '0',
'version': '1', 'version': '1',
'default-user': 'user', 'default-user': 'user',
'qrexec': '0'})) 'qrexec': '0',
self.assertEqual(self.vm.mock_calls, [ 'vmexec': '0'}))
self.assertListEqual(self.vm.mock_calls, [
('features.get', ('qrexec', False), {}), ('features.get', ('qrexec', False), {}),
('features.__contains__', ('qrexec',), {}), ('features.__contains__', ('qrexec',), {}),
('features.__setitem__', ('qrexec', False), {}), ('features.__setitem__', ('qrexec', False), {}),
('features.__contains__', ('gui',), {}), ('features.__contains__', ('gui',), {}),
('features.__setitem__', ('gui', False), {}), ('features.__setitem__', ('gui', False), {}),
('features.__setitem__', ('vmexec', False), {}),
('features.get', ('qrexec', False), {}), ('features.get', ('qrexec', False), {}),
]) ])
@ -84,7 +88,7 @@ class TC_00_CoreFeatures(qubes.tests.QubesTestCase):
'version': '1', 'version': '1',
'default-user': 'user', 'default-user': 'user',
})) }))
self.assertEqual(self.vm.mock_calls, [ self.assertListEqual(self.vm.mock_calls, [
('features.get', ('qrexec', False), {}), ('features.get', ('qrexec', False), {}),
('features.get', ('qrexec', False), {}), ('features.get', ('qrexec', False), {}),
]) ])
@ -98,7 +102,7 @@ class TC_00_CoreFeatures(qubes.tests.QubesTestCase):
'gui': '1', 'gui': '1',
'default-user': 'user', 'default-user': 'user',
})) }))
self.assertEqual(self.vm.mock_calls, [ self.assertListEqual(self.vm.mock_calls, [
('features.get', ('qrexec', False), {}), ('features.get', ('qrexec', False), {}),
('features.__contains__', ('qrexec',), {}), ('features.__contains__', ('qrexec',), {}),
('features.__setitem__', ('qrexec', True), {}), ('features.__setitem__', ('qrexec', True), {}),
@ -136,7 +140,7 @@ class TC_00_CoreFeatures(qubes.tests.QubesTestCase):
'gui': 'invalid', 'gui': 'invalid',
'default-user': 'user', 'default-user': 'user',
})) }))
self.assertEqual(self.vm.mock_calls, [ self.assertListEqual(self.vm.mock_calls, [
('features.get', ('qrexec', False), {}), ('features.get', ('qrexec', False), {}),
('features.__contains__', ('qrexec',), {}), ('features.__contains__', ('qrexec',), {}),
('features.__setitem__', ('qrexec', True), {}), ('features.__setitem__', ('qrexec', True), {}),
@ -171,7 +175,7 @@ class TC_00_CoreFeatures(qubes.tests.QubesTestCase):
'version': '1', 'version': '1',
'default-user': 'user', 'default-user': 'user',
'qrexec': '1'})) 'qrexec': '1'}))
self.assertEqual(self.vm.mock_calls, [ self.assertListEqual(self.vm.mock_calls, [
('features.get', ('qrexec', False), {}), ('features.get', ('qrexec', False), {}),
('features.__contains__', ('qrexec',), {}), ('features.__contains__', ('qrexec',), {}),
('features.__contains__', ('gui',), {}), ('features.__contains__', ('gui',), {}),

View File

@ -402,6 +402,7 @@ fi
%attr(0664,root,qubes) %config(noreplace) /etc/qubes-rpc/policy/qubes.StartApp %attr(0664,root,qubes) %config(noreplace) /etc/qubes-rpc/policy/qubes.StartApp
%attr(0664,root,qubes) %config(noreplace) /etc/qubes-rpc/policy/qubes.VMShell %attr(0664,root,qubes) %config(noreplace) /etc/qubes-rpc/policy/qubes.VMShell
%attr(0664,root,qubes) %config(noreplace) /etc/qubes-rpc/policy/qubes.VMRootShell %attr(0664,root,qubes) %config(noreplace) /etc/qubes-rpc/policy/qubes.VMRootShell
%attr(0664,root,qubes) %config(noreplace) /etc/qubes-rpc/policy/qubes.VMExec
%attr(0664,root,qubes) %config(noreplace) /etc/qubes-rpc/policy/qubes.UpdatesProxy %attr(0664,root,qubes) %config(noreplace) /etc/qubes-rpc/policy/qubes.UpdatesProxy
%attr(0664,root,qubes) %config(noreplace) /etc/qubes-rpc/policy/qubes.GetDate %attr(0664,root,qubes) %config(noreplace) /etc/qubes-rpc/policy/qubes.GetDate
%attr(0664,root,qubes) %config(noreplace) /etc/qubes-rpc/policy/policy.RegisterArgument %attr(0664,root,qubes) %config(noreplace) /etc/qubes-rpc/policy/policy.RegisterArgument