diff --git a/libqrexec/process_io.c b/libqrexec/process_io.c index c1dd8714..b0524876 100644 --- a/libqrexec/process_io.c +++ b/libqrexec/process_io.c @@ -346,7 +346,16 @@ int qrexec_process_io(const struct process_io_request *req, vchan, stdout_fd, stdout_msg_type, &prefix, &remote_buffer)) { case REMOTE_ERROR: - handle_vchan_error("send(handle_input stdout)"); + if (!is_service && remote_status == -1) { + /* Even if sending fails, still try to read remaining + * data, if any - especially the exit code. But don't + * send anything anymore. + */ + LOG(ERROR, "Error while vchan send (handle_input stdout), reading remaining data"); + close_stdout(); + } else { + handle_vchan_error("send(handle_input stdout)"); + } break; case REMOTE_EOF: close_stdout(); diff --git a/qrexec/tests/socket/daemon.py b/qrexec/tests/socket/daemon.py index 2b6b9dea..d561e740 100644 --- a/qrexec/tests/socket/daemon.py +++ b/qrexec/tests/socket/daemon.py @@ -28,6 +28,7 @@ import time import itertools import socket +import signal import psutil import pytest @@ -664,6 +665,7 @@ def start_client(self, args): self.client = subprocess.Popen( cmd, env=env, + stdin=subprocess.PIPE, stdout=subprocess.PIPE, ) self.addCleanup(self.stop_client) @@ -744,6 +746,65 @@ def test_run_vm_command_from_dom0(self): self.client.wait() self.assertEqual(self.client.returncode, 42) + def test_run_vm_command_from_dom0_reject_stdin(self): + """Test if qrexec-client properly returns remote exit code even if + service didn't read all of stdin""" + cmd = "user:command" + target_domain_name = "target_domain" + target_domain_uuid = "d95e1147-2d82-4595-90bb-5a7500cc3196" + target_domain = 42 + target_port = 513 + + target_daemon = self.connect_daemon( + target_domain, target_domain_name, target_domain_uuid + ) + self.start_client(["-d", target_domain_name, cmd]) + target_daemon.accept() + target_daemon.handshake() + + # negotiate_connection_params + self.assertEqual( + target_daemon.recv_message(), + ( + qrexec.MSG_EXEC_CMDLINE, + struct.pack("