Make qrexec_client wait for its local child before exiting

If we do not wait and exit imemdiately, qrexec_daemon will decrease
the children count and continue spawning processes, while e.g.
qfile-daemon still waits for kdialog - so dom0 will be DoSed by
multiple processes.
This commit is contained in:
Rafal Wojtczuk 2011-03-16 14:52:35 +01:00
parent 27cfd6111a
commit 769eedd33a

View File

@ -26,6 +26,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <ioall.h> #include <ioall.h>
#include <sys/wait.h>
#include "qrexec.h" #include "qrexec.h"
#include "buffer.h" #include "buffer.h"
#include "glue.h" #include "glue.h"
@ -58,6 +59,18 @@ void do_exec(char *prog)
int local_stdin_fd, local_stdout_fd; int local_stdin_fd, local_stdout_fd;
void do_exit(int code)
{
int status;
// sever communication lines; wait for child, if any
// so that qrexec-daemon can count (recursively) spawned processes correctly
close(local_stdin_fd);
close(local_stdout_fd);
waitpid(-1, &status, 0);
exit(code);
}
void prepare_local_fds(char *cmdline) void prepare_local_fds(char *cmdline)
{ {
int pid; int pid;
@ -79,7 +92,7 @@ void send_cmdline(int s, int type, char *cmdline)
if (!write_all(s, &hdr, sizeof(hdr)) if (!write_all(s, &hdr, sizeof(hdr))
|| !write_all(s, cmdline, hdr.len)) { || !write_all(s, cmdline, hdr.len)) {
perror("write daemon"); perror("write daemon");
exit(1); do_exit(1);
} }
} }
@ -90,7 +103,7 @@ void handle_input(int s)
ret = read(local_stdout_fd, buf, sizeof(buf)); ret = read(local_stdout_fd, buf, sizeof(buf));
if (ret < 0) { if (ret < 0) {
perror("read"); perror("read");
exit(1); do_exit(1);
} }
if (ret == 0) { if (ret == 0) {
local_stdout_fd = -1; local_stdout_fd = -1;
@ -98,7 +111,7 @@ void handle_input(int s)
} }
if (!write_all(s, buf, ret)) { if (!write_all(s, buf, ret)) {
perror("write daemon"); perror("write daemon");
exit(1); do_exit(1);
} }
} }
@ -110,15 +123,15 @@ void handle_daemon_data(int s)
if (!read_all(s, &hdr, sizeof hdr)) { if (!read_all(s, &hdr, sizeof hdr)) {
perror("read daemon"); perror("read daemon");
exit(1); do_exit(1);
} }
if (hdr.len > MAX_DATA_CHUNK) { if (hdr.len > MAX_DATA_CHUNK) {
fprintf(stderr, "client_header.len=%d\n", hdr.len); fprintf(stderr, "client_header.len=%d\n", hdr.len);
exit(1); do_exit(1);
} }
if (!read_all(s, buf, hdr.len)) { if (!read_all(s, buf, hdr.len)) {
perror("read daemon"); perror("read daemon");
exit(1); do_exit(1);
} }
switch (hdr.type) { switch (hdr.type) {
@ -127,7 +140,7 @@ void handle_daemon_data(int s)
close(local_stdin_fd); close(local_stdin_fd);
else if (!write_all(local_stdin_fd, buf, hdr.len)) { else if (!write_all(local_stdin_fd, buf, hdr.len)) {
perror("write local stdout"); perror("write local stdout");
exit(1); do_exit(1);
} }
break; break;
case MSG_SERVER_TO_CLIENT_STDERR: case MSG_SERVER_TO_CLIENT_STDERR:
@ -136,13 +149,13 @@ void handle_daemon_data(int s)
case MSG_SERVER_TO_CLIENT_EXIT_CODE: case MSG_SERVER_TO_CLIENT_EXIT_CODE:
status = *(unsigned int *) buf; status = *(unsigned int *) buf;
if (WIFEXITED(status)) if (WIFEXITED(status))
exit(WEXITSTATUS(status)); do_exit(WEXITSTATUS(status));
else else
exit(255); do_exit(255);
break; break;
default: default:
fprintf(stderr, "unknown msg %d\n", hdr.type); fprintf(stderr, "unknown msg %d\n", hdr.type);
exit(1); do_exit(1);
} }
} }
@ -160,7 +173,7 @@ void handle_daemon_only_until_writable(s)
if (select(s + 1, &rdset, &wrset, NULL, NULL) < 0) { if (select(s + 1, &rdset, &wrset, NULL, NULL) < 0) {
perror("select"); perror("select");
exit(1); do_exit(1);
} }
if (FD_ISSET(s, &rdset)) if (FD_ISSET(s, &rdset))
handle_daemon_data(s); handle_daemon_data(s);
@ -183,7 +196,7 @@ void select_loop(int s)
} }
if (select(max + 1, &select_set, NULL, NULL, NULL) < 0) { if (select(max + 1, &select_set, NULL, NULL, NULL) < 0) {
perror("select"); perror("select");
exit(1); do_exit(1);
} }
if (FD_ISSET(s, &select_set)) if (FD_ISSET(s, &select_set))
handle_daemon_data(s); handle_daemon_data(s);