From 0701529b55d1f831c179aa2dd5bf0588d6983953 Mon Sep 17 00:00:00 2001 From: Demi Marie Obenour Date: Tue, 21 May 2024 21:38:58 -0400 Subject: [PATCH] Send EOF whenever closing stdout This is expected by the protocol. --- libqrexec/process_io.c | 5 +++++ qrexec/tests/socket/agent.py | 37 ++++++++++++++++++++++++++++++++++-- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/libqrexec/process_io.c b/libqrexec/process_io.c index f100fc72..79df8bbf 100644 --- a/libqrexec/process_io.c +++ b/libqrexec/process_io.c @@ -333,6 +333,11 @@ int qrexec_process_io(const struct process_io_request *req, * local FDs. However, don't exit yet, because there might * still be some data in stdin_buf waiting to be flushed. */ + if (stdout_fd != -1) { + /* Send EOF */ + struct msg_header hdr = { .type = stdout_msg_type, .len = 0, }; + libvchan_send(vchan, &hdr, (int)sizeof(hdr)); + } close_stdout(); close_stderr(stderr_fd); stderr_fd = -1; diff --git a/qrexec/tests/socket/agent.py b/qrexec/tests/socket/agent.py index 32260a05..af9c15d7 100644 --- a/qrexec/tests/socket/agent.py +++ b/qrexec/tests/socket/agent.py @@ -1413,6 +1413,37 @@ def test_run_client_bidirectional_shutdown(self): remote.close() local.close() + def test_run_client_bidirectional_shutdown_early_exit(self): + try: + remote, local = socket.socketpair() + target_client = self.run_service(stdio=remote) + initial_data = b"stdout data\n" + target_client.send_message(qrexec.MSG_DATA_STDOUT, initial_data) + # FIXME: data can be received in multiple messages + self.assertEqual(local.recv(len(initial_data)), initial_data) + initial_data = b"stdin data\n" + local.sendall(initial_data) + self.assertStdoutMessages(target_client, initial_data, qrexec.MSG_DATA_STDIN) + target_client.send_message(qrexec.MSG_DATA_STDOUT, b"") + # Check that EOF got propagated on this side too, even though + # we still have a reference to the socket. This indicates that + # qrexec-client-vm shut down the socket for writing. + self.assertEqual(local.recv(1), b"") + with self.assertRaises(BrokenPipeError): + remote.send(b"a") + target_client.send_message( + qrexec.MSG_DATA_EXIT_CODE, struct.pack("