Skip to content

Commit 9401273

Browse files
committed
Merge remote-tracking branch 'origin/pr/143'
* origin/pr/143: Don't close file descriptor 0 Use libvchan_client_init_async() instead of parent process timeout Avoid using signal() to establish a signal handler Use SOCK_CLOEXEC instead of setting O_CLOEXEC manually Use a pipe instead of signals to notify readiness Use sigemptyset() to initialize signal sets Avoid using alarm(2) for timeouts Add exit codes to qrexec.h
2 parents b0c56f1 + a5de843 commit 9401273

15 files changed

+210
-189
lines changed

agent/qrexec-agent-data.c

+11-67
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,14 @@ static void sigusr1_handler(int __attribute__((__unused__))x)
7474
void prepare_child_env(void) {
7575
char pid_s[10];
7676

77-
signal(SIGCHLD, sigchld_handler);
78-
signal(SIGUSR1, sigusr1_handler);
77+
struct sigaction action = {
78+
.sa_handler = sigchld_handler,
79+
.sa_flags = 0,
80+
};
81+
sigemptyset(&action.sa_mask);
82+
if (sigaction(SIGCHLD, &action, NULL)) abort();
83+
action.sa_handler = sigusr1_handler;
84+
if (sigaction(SIGUSR1, &action, NULL)) abort();
7985
int res = snprintf(pid_s, sizeof(pid_s), "%d", getpid());
8086
if (res < 0) abort();
8187
if (res >= (int)sizeof(pid_s)) abort();
@@ -160,69 +166,6 @@ static int handle_just_exec(struct qrexec_parsed_command *cmd)
160166
return 0;
161167
}
162168

163-
static const long BILLION_NANOSECONDS = 1000000000L;
164-
165-
static int wait_for_vchan_connection_with_timeout(
166-
libvchan_t *conn, int wait_fd, bool is_server, time_t timeout) {
167-
struct timespec end_tp, now_tp, timeout_tp;
168-
169-
if (timeout && clock_gettime(CLOCK_MONOTONIC, &end_tp)) {
170-
PERROR("clock_gettime");
171-
return -1;
172-
}
173-
assert(end_tp.tv_nsec >= 0 && end_tp.tv_nsec < BILLION_NANOSECONDS);
174-
end_tp.tv_sec += timeout;
175-
while (true) {
176-
bool did_timeout = true;
177-
struct pollfd fds = { .fd = wait_fd, .events = POLLIN | POLLHUP, .revents = 0 };
178-
179-
/* calculate how much time left until connection timeout expire */
180-
if (clock_gettime(CLOCK_MONOTONIC, &now_tp)) {
181-
PERROR("clock_gettime");
182-
return -1;
183-
}
184-
assert(now_tp.tv_nsec >= 0 && now_tp.tv_nsec < BILLION_NANOSECONDS);
185-
if (now_tp.tv_sec <= end_tp.tv_sec) {
186-
timeout_tp.tv_sec = end_tp.tv_sec - now_tp.tv_sec;
187-
timeout_tp.tv_nsec = end_tp.tv_nsec - now_tp.tv_nsec;
188-
if (timeout_tp.tv_nsec < 0) {
189-
timeout_tp.tv_nsec += BILLION_NANOSECONDS;
190-
timeout_tp.tv_sec--;
191-
}
192-
did_timeout = timeout_tp.tv_sec < 0;
193-
}
194-
switch (did_timeout ? 0 : ppoll(&fds, 1, &timeout_tp, NULL)) {
195-
case -1:
196-
if (errno == EINTR)
197-
break;
198-
LOG(ERROR, "vchan connection error");
199-
return -1;
200-
case 0:
201-
LOG(ERROR, "vchan connection timeout");
202-
return -1;
203-
case 1:
204-
break;
205-
default:
206-
abort();
207-
}
208-
if (fds.revents & POLLIN) {
209-
if (is_server) {
210-
libvchan_wait(conn);
211-
return 0;
212-
} else {
213-
int connect_ret = libvchan_client_init_async_finish(conn, true);
214-
215-
if (connect_ret < 0) {
216-
LOG(ERROR, "vchan connection error");
217-
return -1;
218-
} else if (connect_ret == 0) {
219-
return 0;
220-
}
221-
}
222-
}
223-
}
224-
}
225-
226169

227170
/* Behaviour depends on type parameter:
228171
* MSG_JUST_EXEC - connect to vchan server, fork+exec process given by cmdline
@@ -263,7 +206,8 @@ static int handle_new_process_common(
263206
LOG(ERROR, "Data vchan connection failed");
264207
exit(1);
265208
}
266-
if (wait_for_vchan_connection_with_timeout(data_vchan, wait_fd, false, connection_timeout) < 0) {
209+
if (qubes_wait_for_vchan_connection_with_timeout(
210+
data_vchan, wait_fd, false, connection_timeout) < 0) {
267211
LOG(ERROR, "Data vchan connection failed");
268212
exit(1);
269213
}
@@ -391,7 +335,7 @@ int handle_data_client(
391335
LOG(ERROR, "Data vchan connection failed");
392336
exit(1);
393337
}
394-
if (wait_for_vchan_connection_with_timeout(
338+
if (qubes_wait_for_vchan_connection_with_timeout(
395339
data_vchan, libvchan_fd_for_select(data_vchan), true, connection_timeout) < 0) {
396340
LOG(ERROR, "Data vchan connection failed");
397341
exit(1);

agent/qrexec-agent.c

+8-2
Original file line numberDiff line numberDiff line change
@@ -928,8 +928,14 @@ int main(int argc, char **argv)
928928
}
929929

930930
init();
931-
signal(SIGCHLD, sigchld_handler);
932-
signal(SIGTERM, sigterm_handler);
931+
struct sigaction action = {
932+
.sa_handler = sigchld_handler,
933+
.sa_flags = SA_RESTART,
934+
};
935+
sigemptyset(&action.sa_mask);
936+
sigaction(SIGCHLD, &action, NULL);
937+
action.sa_handler = sigterm_handler;
938+
sigaction(SIGTERM, &action, NULL);
933939
signal(SIGPIPE, SIG_IGN);
934940

935941
sigemptyset(&selectmask);

agent/qrexec-fork-server.c

-4
Original file line numberDiff line numberDiff line change
@@ -124,10 +124,6 @@ int main(int argc, char **argv) {
124124
}
125125

126126
s = get_server_socket(socket_path);
127-
if (fcntl(s, F_SETFD, O_CLOEXEC) < 0) {
128-
PERROR("fcntl");
129-
exit(1);
130-
}
131127
/* fork into background */
132128
switch (fork()) {
133129
case -1:

daemon/qrexec-client.c

+9-53
Original file line numberDiff line numberDiff line change
@@ -143,57 +143,6 @@ static void parse_connect(char *str, char **request_id,
143143
exit(1);
144144
}
145145

146-
static const long BILLION_NANOSECONDS = 1000000000L;
147-
148-
static void wait_for_vchan_client_with_timeout(libvchan_t *conn, time_t timeout) {
149-
struct timespec end_tp, now_tp, timeout_tp;
150-
151-
if (timeout && clock_gettime(CLOCK_MONOTONIC, &end_tp)) {
152-
PERROR("clock_gettime");
153-
exit(1);
154-
}
155-
assert(end_tp.tv_nsec >= 0 && end_tp.tv_nsec < BILLION_NANOSECONDS);
156-
end_tp.tv_sec += timeout;
157-
int const fd = libvchan_fd_for_select(conn);
158-
while (conn && libvchan_is_open(conn) == VCHAN_WAITING) {
159-
if (timeout) {
160-
bool did_timeout = true;
161-
struct pollfd fds = { .fd = fd, .events = POLLIN | POLLHUP, .revents = 0 };
162-
163-
/* calculate how much time left until connection timeout expire */
164-
if (clock_gettime(CLOCK_MONOTONIC, &now_tp)) {
165-
PERROR("clock_gettime");
166-
exit(1);
167-
}
168-
assert(now_tp.tv_nsec >= 0 && now_tp.tv_nsec < BILLION_NANOSECONDS);
169-
if (now_tp.tv_sec <= end_tp.tv_sec) {
170-
timeout_tp.tv_sec = end_tp.tv_sec - now_tp.tv_sec;
171-
timeout_tp.tv_nsec = end_tp.tv_nsec - now_tp.tv_nsec;
172-
if (timeout_tp.tv_nsec < 0) {
173-
timeout_tp.tv_nsec += BILLION_NANOSECONDS;
174-
timeout_tp.tv_sec--;
175-
}
176-
did_timeout = timeout_tp.tv_sec < 0;
177-
}
178-
switch (did_timeout ? 0 : ppoll(&fds, 1, &timeout_tp, NULL)) {
179-
case -1:
180-
if (errno == EINTR)
181-
break;
182-
LOG(ERROR, "vchan connection error");
183-
exit(1);
184-
case 0:
185-
LOG(ERROR, "vchan connection timeout");
186-
exit(1);
187-
case 1:
188-
break;
189-
default:
190-
abort();
191-
}
192-
}
193-
libvchan_wait(conn);
194-
}
195-
}
196-
197146
static size_t compute_service_length(const char *const remote_cmdline, const char *const prog_name) {
198147
const size_t service_length = strlen(remote_cmdline) + 1;
199148
if (service_length < 2 || service_length > MAX_QREXEC_CMD_LEN) {
@@ -365,9 +314,16 @@ int main(int argc, char **argv)
365314
VCHAN_BUFFER_SIZE, VCHAN_BUFFER_SIZE);
366315
if (!data_vchan) {
367316
LOG(ERROR, "Failed to start data vchan server");
368-
exit(1);
317+
rc = QREXEC_EXIT_PROBLEM;
318+
goto cleanup;
319+
}
320+
int fd = libvchan_fd_for_select(data_vchan);
321+
if (qubes_wait_for_vchan_connection_with_timeout(
322+
data_vchan, fd, true, connection_timeout) < 0) {
323+
LOG(ERROR, "qrexec connection timeout");
324+
rc = QREXEC_EXIT_PROBLEM;
325+
goto cleanup;
369326
}
370-
wait_for_vchan_client_with_timeout(data_vchan, connection_timeout);
371327
struct handshake_params params = {
372328
.data_vchan = data_vchan,
373329
.stdin_buffer = &stdin_buffer,

daemon/qrexec-daemon-common.c

+18-17
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,6 @@ int handle_agent_handshake(libvchan_t *vchan, bool remote_send_first)
220220
static void sigchld_handler(int x __attribute__((__unused__)))
221221
{
222222
sigchld = 1;
223-
signal(SIGCHLD, sigchld_handler);
224223
}
225224

226225
/* See also qrexec-agent.c:wait_for_session_maybe() */
@@ -272,7 +271,12 @@ int prepare_local_fds(struct qrexec_parsed_command *command, struct buffer *stdi
272271
{
273272
if (stdin_buffer == NULL)
274273
abort();
275-
if (signal(SIGCHLD, sigchld_handler) == SIG_ERR)
274+
struct sigaction action = {
275+
.sa_handler = sigchld_handler,
276+
.sa_flags = 0,
277+
};
278+
sigemptyset(&action.sa_mask);
279+
if (sigaction(SIGCHLD, &action, NULL))
276280
return 126;
277281
return execute_parsed_qubes_rpc_command(command, &local_pid, &local_stdin_fd, &local_stdout_fd,
278282
NULL, stdin_buffer);
@@ -331,12 +335,6 @@ static int select_loop(struct handshake_params *params)
331335
return (params->exit_with_code ? exit_code : 0);
332336
}
333337

334-
static void sigalrm_handler(int x __attribute__((__unused__)))
335-
{
336-
LOG(ERROR, "vchan connection timeout");
337-
_exit(1);
338-
}
339-
340338
int run_qrexec_to_dom0(const struct service_params *svc_params,
341339
int src_domain_id,
342340
const char *src_domain_name,
@@ -375,15 +373,18 @@ int run_qrexec_to_dom0(const struct service_params *svc_params,
375373
} else {
376374
prepare_ret = prepare_local_fds(command, &stdin_buffer);
377375
}
378-
void (*old_handler)(int);
379-
380-
/* libvchan_client_init is blocking and does not support connection
381-
* timeout, so use alarm(2) for that... */
382-
old_handler = signal(SIGALRM, sigalrm_handler);
383-
alarm(connection_timeout);
384-
data_vchan = libvchan_client_init(data_domain, data_port);
385-
alarm(0);
386-
signal(SIGALRM, old_handler);
376+
int wait_fd;
377+
data_vchan = libvchan_client_init_async(data_domain, data_port, &wait_fd);
378+
if (!data_vchan) {
379+
LOG(ERROR, "Cannot create data vchan connection");
380+
return QREXEC_EXIT_PROBLEM;
381+
}
382+
if (qubes_wait_for_vchan_connection_with_timeout(
383+
data_vchan, wait_fd, false, connection_timeout) < 0) {
384+
LOG(ERROR, "qrexec connection timeout");
385+
return QREXEC_EXIT_PROBLEM;
386+
}
387+
387388
struct handshake_params params = {
388389
.data_vchan = data_vchan,
389390
.stdin_buffer = &stdin_buffer,

0 commit comments

Comments
 (0)