From 31e412f3e506a7dc067e90d608e489e089207db1 Mon Sep 17 00:00:00 2001 From: Demi Marie Obenour Date: Thu, 18 Apr 2024 20:28:10 -0400 Subject: [PATCH] Treat zero timeout as infinite The other possible behavior (instantly failing the service call) is not useful. Fixes: QubesOS/qubes-issues#9126 Fixes: c664954bf06a ("Avoid using alarm(2) for timeouts") --- libqrexec/vchan_timeout.c | 30 ++++++++++++++++-------------- qrexec/tests/socket/daemon.py | 5 +++-- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/libqrexec/vchan_timeout.c b/libqrexec/vchan_timeout.c index e15a8a0c..5d346ac4 100644 --- a/libqrexec/vchan_timeout.c +++ b/libqrexec/vchan_timeout.c @@ -16,25 +16,27 @@ int qubes_wait_for_vchan_connection_with_timeout( assert(end_tp.tv_nsec >= 0 && end_tp.tv_nsec < BILLION_NANOSECONDS); end_tp.tv_sec += timeout; for (;;) { - bool did_timeout = true; struct pollfd fds = { .fd = wait_fd, .events = POLLIN | POLLHUP, .revents = 0 }; + bool did_timeout = timeout > 0; /* calculate how much time left until connection timeout expire */ - if (clock_gettime(CLOCK_MONOTONIC, &now_tp)) { - PERROR("clock_gettime"); - return -1; - } - assert(now_tp.tv_nsec >= 0 && now_tp.tv_nsec < BILLION_NANOSECONDS); - if (now_tp.tv_sec <= end_tp.tv_sec) { - timeout_tp.tv_sec = end_tp.tv_sec - now_tp.tv_sec; - timeout_tp.tv_nsec = end_tp.tv_nsec - now_tp.tv_nsec; - if (timeout_tp.tv_nsec < 0) { - timeout_tp.tv_nsec += BILLION_NANOSECONDS; - timeout_tp.tv_sec--; + if (did_timeout) { + if (clock_gettime(CLOCK_MONOTONIC, &now_tp)) { + PERROR("clock_gettime"); + return -1; + } + assert(now_tp.tv_nsec >= 0 && now_tp.tv_nsec < BILLION_NANOSECONDS); + if (now_tp.tv_sec <= end_tp.tv_sec) { + timeout_tp.tv_sec = end_tp.tv_sec - now_tp.tv_sec; + timeout_tp.tv_nsec = end_tp.tv_nsec - now_tp.tv_nsec; + if (timeout_tp.tv_nsec < 0) { + timeout_tp.tv_nsec += BILLION_NANOSECONDS; + timeout_tp.tv_sec--; + } + did_timeout = timeout_tp.tv_sec < 0; } - did_timeout = timeout_tp.tv_sec < 0; } - switch (did_timeout ? 0 : ppoll(&fds, 1, &timeout_tp, NULL)) { + switch (did_timeout ? 0 : ppoll(&fds, 1, timeout > 0 ? &timeout_tp : NULL, NULL)) { case -1: if (errno == EINTR) break; diff --git a/qrexec/tests/socket/daemon.py b/qrexec/tests/socket/daemon.py index 94b3c7a6..1ef4638f 100644 --- a/qrexec/tests/socket/daemon.py +++ b/qrexec/tests/socket/daemon.py @@ -734,7 +734,7 @@ def test_run_vm_command_and_connect_vm(self): self.client.wait() self.assertEqual(self.client.returncode, 0) - def connect_service_request(self, cmd): + def connect_service_request(self, cmd, timeout=None): request_id = "SOCKET11" src_domain_name = "src_domain" src_domain = 43 @@ -749,6 +749,7 @@ def connect_service_request(self, cmd): "dom0", "-c", "{},{},{}".format(request_id, src_domain_name, src_domain), + *([f"-w{timeout}"] if timeout is not None else []), cmd, ] ) @@ -1010,7 +1011,7 @@ def test_run_dom0_service_socket_shutdown_rd(self): server = qrexec.socket_server(socket_path) self.addCleanup(server.close) cmd = "QUBESRPC qubes.SocketService+arg src_domain name src_domain" - source = self.connect_service_request(cmd) + source = self.connect_service_request(cmd, timeout=0) server.accept() header = cmd[len("QUBESRPC ") :].encode() + b"\0"