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
|
||||||
import qubes.mgmt
|
import qubes.mgmt
|
||||||
|
import qubes.mgmtinternal
|
||||||
import qubes.utils
|
import qubes.utils
|
||||||
import qubes.vm.qubesvm
|
import qubes.vm.qubesvm
|
||||||
|
|
||||||
QUBESD_SOCK = '/var/run/qubesd.sock'
|
QUBESD_SOCK = '/var/run/qubesd.sock'
|
||||||
|
QUBESD_INTERNAL_SOCK = '/var/run/qubesd.internal.sock'
|
||||||
|
|
||||||
class QubesDaemonProtocol(asyncio.Protocol):
|
class QubesDaemonProtocol(asyncio.Protocol):
|
||||||
buffer_size = 65536
|
buffer_size = 65536
|
||||||
header = struct.Struct('Bx')
|
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)
|
super().__init__(*args, **kwargs)
|
||||||
|
self.handler = handler
|
||||||
self.app = app
|
self.app = app
|
||||||
self.untrusted_buffer = io.BytesIO()
|
self.untrusted_buffer = io.BytesIO()
|
||||||
self.len_untrusted_buffer = 0
|
self.len_untrusted_buffer = 0
|
||||||
@ -69,7 +72,7 @@ class QubesDaemonProtocol(asyncio.Protocol):
|
|||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def respond(self, src, method, dest, arg, *, untrusted_payload):
|
def respond(self, src, method, dest, arg, *, untrusted_payload):
|
||||||
try:
|
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(
|
response = yield from mgmt.execute(
|
||||||
untrusted_payload=untrusted_payload)
|
untrusted_payload=untrusted_payload)
|
||||||
|
|
||||||
@ -147,9 +150,10 @@ class QubesDaemonProtocol(asyncio.Protocol):
|
|||||||
self.transport.write(str(exc).encode('utf-8') + b'\0')
|
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))
|
print('caught {}, exiting'.format(signame))
|
||||||
server.close()
|
server.close()
|
||||||
|
server_internal.close()
|
||||||
loop.stop()
|
loop.stop()
|
||||||
|
|
||||||
parser = qubes.tools.QubesArgumentParser(description='Qubes OS daemon')
|
parser = qubes.tools.QubesArgumentParser(description='Qubes OS daemon')
|
||||||
@ -166,20 +170,35 @@ def main(args=None):
|
|||||||
pass
|
pass
|
||||||
old_umask = os.umask(0o007)
|
old_umask = os.umask(0o007)
|
||||||
server = loop.run_until_complete(loop.create_unix_server(
|
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')
|
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)
|
os.umask(old_umask)
|
||||||
del old_umask
|
del old_umask
|
||||||
|
|
||||||
for signame in ('SIGINT', 'SIGTERM'):
|
for signame in ('SIGINT', 'SIGTERM'):
|
||||||
loop.add_signal_handler(getattr(signal, signame),
|
loop.add_signal_handler(getattr(signal, signame),
|
||||||
sighandler, loop, signame, server)
|
sighandler, loop, signame, server, server_internal)
|
||||||
|
|
||||||
qubes.utils.systemd_notify()
|
qubes.utils.systemd_notify()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
loop.run_forever()
|
loop.run_forever()
|
||||||
loop.run_until_complete(server.wait_closed())
|
loop.run_until_complete(asyncio.wait([
|
||||||
|
server.wait_closed(),
|
||||||
|
server_internal.wait_closed(),
|
||||||
|
]))
|
||||||
finally:
|
finally:
|
||||||
loop.close()
|
loop.close()
|
||||||
|
|
||||||
|
@ -643,4 +643,4 @@ def get_system_info():
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
system_info = qubesd_call('dom0', 'mgmtinternal.GetSystemInfo')
|
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/firewall.py
|
||||||
%{python3_sitelib}/qubes/log.py
|
%{python3_sitelib}/qubes/log.py
|
||||||
%{python3_sitelib}/qubes/mgmt.py
|
%{python3_sitelib}/qubes/mgmt.py
|
||||||
|
%{python3_sitelib}/qubes/mgmtinternal.py
|
||||||
%{python3_sitelib}/qubes/rngdoc.py
|
%{python3_sitelib}/qubes/rngdoc.py
|
||||||
%{python3_sitelib}/qubes/tarwriter.py
|
%{python3_sitelib}/qubes/tarwriter.py
|
||||||
%{python3_sitelib}/qubes/utils.py
|
%{python3_sitelib}/qubes/utils.py
|
||||||
|
Loading…
Reference in New Issue
Block a user