diff --git a/.travis.yml b/.travis.yml index f891263b..7f7f1e18 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,7 +24,7 @@ jobs: script: pylint qrexec - install: docker build -t qrexec-test ci env: DOCKER_RUN="docker run -v $TRAVIS_BUILD_DIR:$TRAVIS_BUILD_DIR -v /tmp/.X11-unix:/tmp/.X11-unix -w $TRAVIS_BUILD_DIR -e DISPLAY=$DISPLAY -- qrexec-test" - script: $DOCKER_RUN python3 -m coverage run -m unittest discover -s qrexec/tests -t . -p '*.py' -v + script: $DOCKER_RUN python3 -m coverage run -m pytest qrexec/tests -o python_files=*.py -v # - python: '3.7' # script: python -m coverage run -m unittest discover -s qrexec/tests -t . -p '*.py' -v - stage: deploy diff --git a/Makefile b/Makefile index c1f22a6c..b0dc5e34 100644 --- a/Makefile +++ b/Makefile @@ -38,6 +38,8 @@ install-dom0: install -d $(DESTDIR)/etc/qubes/policy.d -m 775 install -d $(DESTDIR)/etc/qubes/policy.d/include -m 775 install -t $(DESTDIR)/etc/qubes/policy.d -m 664 policy.d/* + install -d $(DESTDIR)/lib/systemd/system -m 755 + install -t $(DESTDIR)/lib/systemd/system -m 644 systemd/qubes-qrexec-policy-daemon.service .PHONY: install-dom0 @@ -48,7 +50,7 @@ all-vm: install-vm: $(MAKE) install -C agent install -d $(DESTDIR)/lib/systemd/system -m 755 - install -t $(DESTDIR)/lib/systemd/system -m 644 systemd/* + install -t $(DESTDIR)/lib/systemd/system -m 644 systemd/qubes-qrexec-agent.service install -m 0644 -D qubes-rpc-config/README $(DESTDIR)/etc/qubes/rpc-config/README # install -d $(DESTDIR)/etc/qubes-rpc -m 755 # install -t $(DESTDIR)/etc/qubes-rpc -m 755 qubes-rpc/* diff --git a/ci/requirements.txt b/ci/requirements.txt index e814f785..8ea0f8c0 100644 --- a/ci/requirements.txt +++ b/ci/requirements.txt @@ -5,3 +5,4 @@ pylint sphinx codecov pydbus +pytest-asyncio diff --git a/daemon/qrexec-daemon.c b/daemon/qrexec-daemon.c index 7a830c45..a9ca59b5 100644 --- a/daemon/qrexec-daemon.c +++ b/daemon/qrexec-daemon.c @@ -18,6 +18,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ +#define _GNU_SOURCE #include #include @@ -28,12 +29,17 @@ #include #include #include +#include +#include +#include #include #include #include "qrexec.h" #include "libqrexec-utils.h" #define QREXEC_MIN_VERSION QREXEC_PROTOCOL_V2 +#define QREXEC_SOCKET_PATH "/var/run/qubes/policy.sock" + enum client_state { CLIENT_INVALID = 0, // table slot not used @@ -678,6 +684,73 @@ static void sanitize_name(char * untrusted_s_signed, char *extra_allowed_chars) * Called when agent sends a message asking to execute a predefined command. */ +static int connect_daemon_socket( + const int remote_domain_id, + const char *remote_domain_name, + const char *target_domain, + const char *service_name, + const struct service_params *request_id +) { + int result; + int command_size; + char response[32]; + char *command; + int daemon_socket; + struct sockaddr_un daemon_socket_address = { + .sun_family = AF_UNIX, + .sun_path = QREXEC_SOCKET_PATH + }; + + daemon_socket = socket(AF_UNIX, SOCK_STREAM, 0); + if (daemon_socket < 0) { + perror("socket creation failed"); + return -1; + } + + result = connect(daemon_socket, (struct sockaddr *) &daemon_socket_address, + sizeof(daemon_socket_address)); + if (result < 0) { + perror("connection to socket failed"); + return -1; + } + + command_size = asprintf(&command, "domain_id=%d\n" + "source=%s\n" + "intended_target=%s\n" + "service_and_arg=%s\n" + "process_ident=%s\n\n", + remote_domain_id, remote_domain_name, target_domain, + service_name, request_id->ident); + if (command_size < 0) { + perror("failed to construct request"); + return -1; + } + + result = send(daemon_socket, command, command_size, 0); + free(command); + if (result < 0) { + perror("send to socket failed"); + return -1; + } + + result = recv(daemon_socket, response, sizeof(response), 0); + if (result < 0) { + perror("error reading from socket"); + return -1; + } + else { + if (!strncmp(response, "result=allow\n", sizeof("result=allow\n")-1)) { + return 0; + } else if (!strncmp(response, "result=deny\n", sizeof("result=deny\n")-1)) { + return 1; + } else { + warnx("invalid response"); + return -1; + } + } +} + + static void handle_execute_service( const int remote_domain_id, const char *remote_domain_name, @@ -686,6 +759,7 @@ static void handle_execute_service( const struct service_params *request_id) { int i; + int result; int policy_pending_slot; pid_t pid; char remote_domain_id_str[10]; @@ -708,6 +782,15 @@ static void handle_execute_service( policy_pending[policy_pending_slot].params = *request_id; return; } + + result = connect_daemon_socket(remote_domain_id, remote_domain_name, + target_domain, service_name, request_id); + if (result >= 0) { + _exit(result); + } else { + warnx("invalid response"); + } + for (i = 3; i < MAX_FDS; i++) close(i); signal(SIGCHLD, SIG_DFL); @@ -725,6 +808,7 @@ static void handle_execute_service( _exit(1); } + static void handle_connection_terminated() { struct exec_params untrusted_params, params; diff --git a/debian/qubes-core-qrexec.install b/debian/qubes-core-qrexec.install index 2bfb8563..e912ac6b 100644 --- a/debian/qubes-core-qrexec.install +++ b/debian/qubes-core-qrexec.install @@ -6,6 +6,7 @@ usr/bin/qrexec-fork-server usr/bin/qrexec-policy-graph usr/bin/qrexec-policy-restore usr/bin/qrexec-policy-exec +usr/bin/qrexec-policy-daemon usr/bin/qrexec-policy usr/bin/qrexec-policy-agent usr/bin/qubes-policy diff --git a/rpm_spec/qubes-qrexec-dom0.spec.in b/rpm_spec/qubes-qrexec-dom0.spec.in index 56d7742a..57ad4d3b 100644 --- a/rpm_spec/qubes-qrexec-dom0.spec.in +++ b/rpm_spec/qubes-qrexec-dom0.spec.in @@ -61,6 +61,21 @@ export BACKEND_VMM=@BACKEND_VMM@ make all-dom0 #make -C doc PYTHON=%{__python3} SPHINXBUILD=sphinx-build-%{python3_version} man +%post +%systemd_post qubes-qrexec-policy-daemon.service + +%preun +%systemd_preun qubes-qrexec-policy-daemon.service + +%posttrans +# when upgrading from R4.0, %%postun of qubes-qrexec-policy-daemon will revert +# %%post of this package. Redo the action in %%posttrans +%systemd_post qubes-qrexec-policy-daemon.service +# and then start it back +if systemctl is-enabled qubes-qrexec-policy-daemon.service >/dev/null 2>&1; then + systemctl start qubes-qrexec-policy-daemon.service +fi + %install make install-dom0 \ DESTDIR=$RPM_BUILD_ROOT \ @@ -96,5 +111,7 @@ rm -f %{name}-%{version} %{_sysconfdir}/qubes-rpc/policy.RegisterArgument +/lib/systemd/system/qubes-qrexec-policy-daemon.service + %changelog @CHANGELOG@ diff --git a/systemd/qubes-qrexec-policy-daemon.service b/systemd/qubes-qrexec-policy-daemon.service new file mode 100644 index 00000000..771374b2 --- /dev/null +++ b/systemd/qubes-qrexec-policy-daemon.service @@ -0,0 +1,7 @@ +[Unit] +Description=Qubes remote exec policy daemon +After=qubesd.service + +[Service] +Type=simple +ExecStart=/usr/bin/qrexec-policy-daemon