Skip to content

Commit

Permalink
qrexec-client: handle failed service exec
Browse files Browse the repository at this point in the history
Otherwise, qrexec-client just hangs when it fails to spawn a
process, or connect to a socket service.

This corresponds to the fix for qrexec-agent in commit
95fa4bb.
  • Loading branch information
pwmarcz committed Mar 28, 2020
1 parent 97373fa commit 9883543
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 5 deletions.
32 changes: 27 additions & 5 deletions daemon/qrexec-client.c
Original file line number Diff line number Diff line change
Expand Up @@ -252,20 +252,37 @@ static void wait_for_session_maybe(char *cmdline)
destroy_qrexec_parsed_command(cmd);
}

static void prepare_local_fds(char *cmdline, struct buffer *stdin_buffer)
static int prepare_local_fds(char *cmdline, struct buffer *stdin_buffer)
{
if (stdin_buffer == NULL)
abort();
if (!cmdline) {
local_stdin_fd = 1;
local_stdout_fd = 0;
return;
return 0;
}
signal(SIGCHLD, sigchld_handler);
execute_qubes_rpc_command(cmdline, &local_pid, &local_stdin_fd, &local_stdout_fd,
return execute_qubes_rpc_command(cmdline, &local_pid, &local_stdin_fd, &local_stdout_fd,
NULL, false, stdin_buffer);
}

// See also qrexec-agent/qrexec-agent-data.c
static _Noreturn void handle_failed_exec(libvchan_t *data_vchan)
{
int exit_code = 127;
struct msg_header hdr = {
.type = MSG_DATA_STDOUT,
.len = 0,
};

LOG(ERROR, "failed to spawn process");
libvchan_send(data_vchan, &hdr, sizeof(hdr));
send_exit_code(data_vchan, exit_code);
libvchan_close(data_vchan);

exit(exit_code);
}

/* ask the daemon to allocate vchan port */
static void negotiate_connection_params(int s, int other_domid, unsigned type,
void *cmdline_param, int cmdline_size,
Expand Down Expand Up @@ -491,6 +508,7 @@ int main(int argc, char **argv)
int connection_timeout = 5;
struct service_params svc_params;
int data_protocol_version;
int prepare_ret;

setup_logging("qrexec-client");

Expand Down Expand Up @@ -572,7 +590,7 @@ int main(int argc, char **argv)
struct buffer stdin_buffer;
buffer_init(&stdin_buffer);
wait_for_session_maybe(remote_cmdline);
prepare_local_fds(remote_cmdline, &stdin_buffer);
prepare_ret = prepare_local_fds(remote_cmdline, &stdin_buffer);
if (connect_existing) {
void (*old_handler)(int);

Expand All @@ -595,6 +613,8 @@ int main(int argc, char **argv)
data_protocol_version = handle_agent_handshake(data_vchan, connect_existing);
if (data_protocol_version < 0)
exit(1);
if (prepare_ret < 0)
handle_failed_exec(data_vchan);
select_loop(data_vchan, data_protocol_version, &stdin_buffer);
} else {
msg_type = just_exec ? MSG_JUST_EXEC : MSG_EXEC_CMDLINE;
Expand All @@ -615,7 +635,7 @@ int main(int argc, char **argv)
set_remote_domain(domname);
struct buffer stdin_buffer;
buffer_init(&stdin_buffer);
prepare_local_fds(local_cmdline, &stdin_buffer);
prepare_ret = prepare_local_fds(local_cmdline, &stdin_buffer);
if (connect_existing) {
s = connect_unix_socket(src_domain_name);
send_service_connect(s, request_id, data_domain, data_port);
Expand All @@ -642,6 +662,8 @@ int main(int argc, char **argv)
data_protocol_version = handle_agent_handshake(data_vchan, 0);
if (data_protocol_version < 0)
exit(1);
if (prepare_ret < 0)
handle_failed_exec(data_vchan);
select_loop(data_vchan, data_protocol_version, &stdin_buffer);
}
}
Expand Down
12 changes: 12 additions & 0 deletions qrexec/tests/socket/daemon.py
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,18 @@ def test_run_dom0_service_exec(self):
self.client.wait()
self.assertEqual(self.client.returncode, 0)

def test_run_dom0_service_failed(self):
# qubes.Service does not exist
cmd = 'QUBESRPC qubes.Service+arg src_domain name src_domain'
source = self.connect_service_request(cmd)

self.assertEqual(source.recv_all_messages(), [
(qrexec.MSG_DATA_STDOUT, b''),
(qrexec.MSG_DATA_EXIT_CODE, struct.pack('<L', 127)),
])
self.client.wait()
self.assertEqual(self.client.returncode, 127)

def test_run_dom0_service_wait_for_session(self):
log = os.path.join(self.tempdir, 'wait-for-session.log')
util.make_executable_service(self.tempdir, 'rpc', 'qubes.WaitForSession', '''\
Expand Down

0 comments on commit 9883543

Please sign in to comment.