From 48f10a79c94918ec62e8969c91ad4634be1a55db Mon Sep 17 00:00:00 2001 From: Wojtek Porczyk Date: Fri, 17 Feb 2017 15:48:22 +0100 Subject: [PATCH] qubes/tools/qubesd: add response header QubesOS/qubes-issues#2622 --- ci/pylintrc | 2 +- qubes/tools/qubesd.py | 48 ++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/ci/pylintrc b/ci/pylintrc index f16a9aa3..08554553 100644 --- a/ci/pylintrc +++ b/ci/pylintrc @@ -72,7 +72,7 @@ variable-rgx=[a-z_][a-z0-9_]{2,30}$ inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ # Good variable names which should always be accepted, separated by a comma -good-names=e,i,j,k,m,p,ex,Run,_,log,vm,xc,xs,ip,fd,fh,rw,st,tb,cb,ff +good-names=e,i,j,k,m,p,v,ex,Run,_,log,vm,xc,xs,ip,fd,fh,rw,st,tb,cb,ff # Bad variable names which should always be refused, separated by a comma bad-names=foo,bar,baz,toto,tutu,tata diff --git a/qubes/tools/qubesd.py b/qubes/tools/qubesd.py index 7cfd0de3..4217a3af 100644 --- a/qubes/tools/qubesd.py +++ b/qubes/tools/qubesd.py @@ -5,6 +5,8 @@ import functools import io import os import signal +import struct +import traceback import qubes import qubes.libvirtaio @@ -14,16 +16,17 @@ import qubes.vm.qubesvm QUBESD_SOCK = '/var/run/qubesd.sock' - class QubesDaemonProtocol(asyncio.Protocol): buffer_size = 65536 + header = struct.Struct('!H') - def __init__(self, *args, app, **kwargs): + def __init__(self, *args, app, debug=False, **kwargs): super().__init__(*args, **kwargs) self.app = app self.untrusted_buffer = io.BytesIO() self.len_untrusted_buffer = 0 self.transport = None + self.debug = debug def connection_made(self, transport): print('connection_made()') @@ -74,6 +77,12 @@ class QubesDaemonProtocol(asyncio.Protocol): 'with payload of %d bytes', method, arg, src, dest, len(untrusted_payload)) + except qubes.exc.QubesException as err: + self.send_exception(err) + self.transport.write_eof() + self.transport.close() + return + except Exception: # pylint: disable=broad-except self.app.log.exception( 'unhandled exception while calling ' @@ -81,7 +90,7 @@ class QubesDaemonProtocol(asyncio.Protocol): src, method, dest, arg, len(untrusted_payload)) else: - self.transport.write(response.encode('ascii')) + self.send_response(response) try: self.transport.write_eof() except NotImplementedError: @@ -94,6 +103,39 @@ class QubesDaemonProtocol(asyncio.Protocol): self.transport.abort() + def send_header(self, *args): + self.transport.write(self.header.pack(*args)) + + def send_response(self, content): + self.send_header(0x30) + self.transport.write(content.encode('utf-8')) + + def send_event(self, subject, event, **kwargs): + self.send_header(0x31) + + if subject is not self.app: + self.transport.write(subject.name.encode('ascii')) + self.transport.write(b'\0') + + self.transport.write(event.encode('ascii') + b'\0') + + for k, v in kwargs.items(): + self.transport.write('{}\0{}\0'.format(k, str(v)).encode('ascii')) + self.transport.write(b'\0') + + def send_exception(self, exc): + self.send_header(0x32) + + self.transport.write(type(exc).__name__ + b'\0') + + if self.debug: + self.transport.write(''.join(traceback.format_exception( + type(exc), exc, exc.__traceback__)).encode('utf-8')) + self.transport.write(b'\0') + + self.transport.write(str(exc).encode('utf-8') + b'\0') + + def sighandler(loop, signame, server): print('caught {}, exiting'.format(signame)) server.close()