qubesd: add second socket for in-dom0 internal calls
This socket (and commands) are not exposed to untrusted input, so no need to extensive sanitization. Also, there is no need to provide a stable API here, as those methods are used internally only. QubesOS/qubes-issues#853
This commit is contained in:
parent
c9b5d0ab15
commit
83526a28d3
84
qubes/mgmtinternal.py
Normal file
84
qubes/mgmtinternal.py
Normal file
@ -0,0 +1,84 @@
|
||||
# -*- encoding: utf8 -*-
|
||||
#
|
||||
# The Qubes OS Project, http://www.qubes-os.org
|
||||
#
|
||||
# Copyright (C) 2017 Marek Marczykowski-Górecki
|
||||
# <marmarek@invisiblethingslab.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
''' Internal interface for dom0 components to communicate with qubesd. '''
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
|
||||
import qubes.mgmt
|
||||
import qubes.vm.dispvm
|
||||
|
||||
api = qubes.mgmt.api
|
||||
|
||||
|
||||
class QubesInternalMgmt(qubes.mgmt.AbstractQubesMgmt):
|
||||
''' Communication interface for dom0 components,
|
||||
by design the input here is trusted.'''
|
||||
#
|
||||
# PRIVATE METHODS, not to be called via RPC
|
||||
#
|
||||
|
||||
#
|
||||
# ACTUAL RPC CALLS
|
||||
#
|
||||
|
||||
@api('mgmtinternal.GetSystemInfo', no_payload=True)
|
||||
@asyncio.coroutine
|
||||
def getsysteminfo(self):
|
||||
assert self.dest.name == 'dom0'
|
||||
assert not self.arg
|
||||
|
||||
system_info = {'domains': {
|
||||
domain.name: {
|
||||
'tags': list(domain.tags),
|
||||
'type': domain.__class__.__name__,
|
||||
'dispvm_allowed': getattr(domain, 'dispvm_allowed', False),
|
||||
'default_dispvm': (str(domain.default_dispvm) if
|
||||
domain.default_dispvm else None),
|
||||
'icon': str(domain.label.icon),
|
||||
} for domain in self.app.domains
|
||||
}}
|
||||
|
||||
return json.dumps(system_info)
|
||||
|
||||
@api('mgmtinternal.vm.Start', no_payload=True)
|
||||
@asyncio.coroutine
|
||||
def start(self):
|
||||
assert not self.arg
|
||||
|
||||
yield from self.dest.start()
|
||||
|
||||
@api('mgmtinternal.vm.Create.DispVM', no_payload=True)
|
||||
@asyncio.coroutine
|
||||
def create_dispvm(self):
|
||||
assert not self.arg
|
||||
|
||||
# TODO convert to coroutine
|
||||
dispvm = qubes.vm.dispvm.DispVM.from_appvm(self.dest)
|
||||
return dispvm.name
|
||||
|
||||
@api('mgmtinternal.vm.CleanupDispVM', no_payload=True)
|
||||
@asyncio.coroutine
|
||||
def cleanup_dispvm(self):
|
||||
assert not self.arg
|
||||
|
||||
# TODO convert to coroutine
|
||||
self.dest.cleanup()
|
@ -13,17 +13,20 @@ import libvirtaio
|
||||
|
||||
import qubes
|
||||
import qubes.mgmt
|
||||
import qubes.mgmtinternal
|
||||
import qubes.utils
|
||||
import qubes.vm.qubesvm
|
||||
|
||||
QUBESD_SOCK = '/var/run/qubesd.sock'
|
||||
QUBESD_INTERNAL_SOCK = '/var/run/qubesd.internal.sock'
|
||||
|
||||
class QubesDaemonProtocol(asyncio.Protocol):
|
||||
buffer_size = 65536
|
||||
header = struct.Struct('Bx')
|
||||
|
||||
def __init__(self, *args, app, debug=False, **kwargs):
|
||||
def __init__(self, handler, *args, app, debug=False, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.handler = handler
|
||||
self.app = app
|
||||
self.untrusted_buffer = io.BytesIO()
|
||||
self.len_untrusted_buffer = 0
|
||||
@ -69,7 +72,7 @@ class QubesDaemonProtocol(asyncio.Protocol):
|
||||
@asyncio.coroutine
|
||||
def respond(self, src, method, dest, arg, *, untrusted_payload):
|
||||
try:
|
||||
mgmt = qubes.mgmt.QubesMgmt(self.app, src, method, dest, arg)
|
||||
mgmt = self.handler(self.app, src, method, dest, arg)
|
||||
response = yield from mgmt.execute(
|
||||
untrusted_payload=untrusted_payload)
|
||||
|
||||
@ -147,9 +150,10 @@ class QubesDaemonProtocol(asyncio.Protocol):
|
||||
self.transport.write(str(exc).encode('utf-8') + b'\0')
|
||||
|
||||
|
||||
def sighandler(loop, signame, server):
|
||||
def sighandler(loop, signame, server, server_internal):
|
||||
print('caught {}, exiting'.format(signame))
|
||||
server.close()
|
||||
server_internal.close()
|
||||
loop.stop()
|
||||
|
||||
parser = qubes.tools.QubesArgumentParser(description='Qubes OS daemon')
|
||||
@ -166,20 +170,35 @@ def main(args=None):
|
||||
pass
|
||||
old_umask = os.umask(0o007)
|
||||
server = loop.run_until_complete(loop.create_unix_server(
|
||||
functools.partial(QubesDaemonProtocol, app=args.app), QUBESD_SOCK))
|
||||
functools.partial(QubesDaemonProtocol, qubes.mgmt.QubesMgmt,
|
||||
app=args.app), QUBESD_SOCK))
|
||||
shutil.chown(QUBESD_SOCK, group='qubes')
|
||||
|
||||
try:
|
||||
os.unlink(QUBESD_INTERNAL_SOCK)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
server_internal = loop.run_until_complete(loop.create_unix_server(
|
||||
functools.partial(QubesDaemonProtocol,
|
||||
qubes.mgmtinternal.QubesInternalMgmt,
|
||||
app=args.app), QUBESD_INTERNAL_SOCK))
|
||||
shutil.chown(QUBESD_INTERNAL_SOCK, group='qubes')
|
||||
|
||||
os.umask(old_umask)
|
||||
del old_umask
|
||||
|
||||
for signame in ('SIGINT', 'SIGTERM'):
|
||||
loop.add_signal_handler(getattr(signal, signame),
|
||||
sighandler, loop, signame, server)
|
||||
sighandler, loop, signame, server, server_internal)
|
||||
|
||||
qubes.utils.systemd_notify()
|
||||
|
||||
try:
|
||||
loop.run_forever()
|
||||
loop.run_until_complete(server.wait_closed())
|
||||
loop.run_until_complete(asyncio.wait([
|
||||
server.wait_closed(),
|
||||
server_internal.wait_closed(),
|
||||
]))
|
||||
finally:
|
||||
loop.close()
|
||||
|
||||
|
@ -643,4 +643,4 @@ def get_system_info():
|
||||
'''
|
||||
|
||||
system_info = qubesd_call('dom0', 'mgmtinternal.GetSystemInfo')
|
||||
return json.loads(system_info)
|
||||
return json.loads(system_info.decode('utf-8'))
|
||||
|
@ -234,6 +234,7 @@ fi
|
||||
%{python3_sitelib}/qubes/firewall.py
|
||||
%{python3_sitelib}/qubes/log.py
|
||||
%{python3_sitelib}/qubes/mgmt.py
|
||||
%{python3_sitelib}/qubes/mgmtinternal.py
|
||||
%{python3_sitelib}/qubes/rngdoc.py
|
||||
%{python3_sitelib}/qubes/tarwriter.py
|
||||
%{python3_sitelib}/qubes/utils.py
|
||||
|
Loading…
Reference in New Issue
Block a user