Skip to content

Commit

Permalink
Make qubesd connected directly as an socket qrexec service
Browse files Browse the repository at this point in the history
Remove intermediate qubesd-query-fast proxy process.
This requires changing socket protocol to match what qrexec is sending
in the header.

Fixes QubesOS/qubes-issues#3293
  • Loading branch information
marmarek committed Apr 20, 2020
1 parent 6d19496 commit 3ce4a43
Show file tree
Hide file tree
Showing 4 changed files with 24 additions and 13 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ endif
install -m 0755 qvm-tools/qvm-sync-clock $(DESTDIR)/usr/bin/qvm-sync-clock
install -m 0755 qvm-tools/qvm-console-dispvm $(DESTDIR)/usr/bin/qvm-console-dispvm
for method in $(ADMIN_API_METHODS_SIMPLE); do \
ln -s ../../usr/libexec/qubes/qubesd-query-fast \
ln -s ../../var/run/qubesd.sock \
$(DESTDIR)/etc/qubes-rpc/$$method || exit 1; \
done
install qubes-rpc/admin.vm.volume.Import $(DESTDIR)/etc/qubes-rpc/
Expand Down
14 changes: 12 additions & 2 deletions qubes/api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,8 +252,18 @@ def data_received(self, untrusted_data): # pylint: disable=arguments-differ

def eof_received(self):
try:
src, meth, dest, arg, untrusted_payload = \
self.untrusted_buffer.getvalue().split(b'\0', 4)
connection_params, untrusted_payload = \
self.untrusted_buffer.getvalue().split(b'\0', 1)
meth_arg, src, dest_type, dest = \
connection_params.split(b' ', 3)
if dest_type != b'name':
raise ValueError(
'got {} destination type, '
'while only explicit name supported'.format(dest_type))
if b'+' in meth_arg:
meth, arg = meth_arg.split(b'+', 1)
else:
meth, arg = meth_arg, b''
except ValueError:
self.app.log.warning('framing error')
self.transport.abort()
Expand Down
16 changes: 8 additions & 8 deletions qubes/tests/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,18 +118,18 @@ def tearDown(self):
super(TC_00_QubesDaemonProtocol, self).tearDown()

def test_000_message_ok(self):
self.writer.write(b'dom0\0mgmt.success\0dom0\0arg\0payload')
self.writer.write(b'mgmt.success+arg src name dest\0payload')
self.writer.write_eof()
with self.assertNotRaises(asyncio.TimeoutError):
response = self.loop.run_until_complete(
asyncio.wait_for(self.reader.read(), 1))
self.assertEqual(response,
b"0\0src: b'dom0', dest: b'dom0', arg: b'arg', payload: b'payload'")
b"0\0src: b'src', dest: b'dest', arg: b'arg', payload: b'payload'")

def test_001_message_ok_in_parts(self):
self.writer.write(b'dom0\0mgmt.')
self.writer.write(b'mgmt.success+arg')
self.loop.run_until_complete(self.writer.drain())
self.writer.write(b'success\0dom0\0arg\0payload')
self.writer.write(b' dom0 name dom0\0payload')
self.writer.write_eof()
with self.assertNotRaises(asyncio.TimeoutError):
response = self.loop.run_until_complete(
Expand All @@ -138,31 +138,31 @@ def test_001_message_ok_in_parts(self):
b"0\0src: b'dom0', dest: b'dom0', arg: b'arg', payload: b'payload'")

def test_002_message_ok_empty(self):
self.writer.write(b'dom0\0mgmt.success_none\0dom0\0arg\0payload')
self.writer.write(b'mgmt.success_none+arg dom0 name dom0\0payload')
self.writer.write_eof()
with self.assertNotRaises(asyncio.TimeoutError):
response = self.loop.run_until_complete(
asyncio.wait_for(self.reader.read(), 1))
self.assertEqual(response, b"0\0")

def test_003_exception_qubes(self):
self.writer.write(b'dom0\0mgmt.qubesexception\0dom0\0arg\0payload')
self.writer.write(b'mgmt.qubesexception+arg dom0 name dom0\0payload')
self.writer.write_eof()
with self.assertNotRaises(asyncio.TimeoutError):
response = self.loop.run_until_complete(
asyncio.wait_for(self.reader.read(), 1))
self.assertEqual(response, b"2\0QubesException\0\0qubes-exception\0")

def test_004_exception_generic(self):
self.writer.write(b'dom0\0mgmt.exception\0dom0\0arg\0payload')
self.writer.write(b'mgmt.exception+arg dom0 name dom0\0payload')
self.writer.write_eof()
with self.assertNotRaises(asyncio.TimeoutError):
response = self.loop.run_until_complete(
asyncio.wait_for(self.reader.read(), 1))
self.assertEqual(response, b"")

def test_005_event(self):
self.writer.write(b'dom0\0mgmt.event\0dom0\0arg\0payload')
self.writer.write(b'mgmt.event+arg dom0 name dom0\0payload')
self.writer.write_eof()
with self.assertNotRaises(asyncio.TimeoutError):
response = self.loop.run_until_complete(
Expand Down
5 changes: 3 additions & 2 deletions qubes/tools/qubesd_query.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,9 @@ def main(args=None):
payload = sys.stdin.buffer.read() if args.payload else b''
# pylint: enable=no-member

coro = asyncio.ensure_future(qubesd_client(args.socket, payload,
args.src, args.method, args.dest, args.arg))
coro = asyncio.ensure_future(qubesd_client(
args.socket, payload,
f'{args.method}+{args.arg} {args.src} name {args.dest}'))

for signame in ('SIGINT', 'SIGTERM'):
loop.add_signal_handler(getattr(signal, signame),
Expand Down

0 comments on commit 3ce4a43

Please sign in to comment.