diff --git a/daemon/qrexec-daemon.c b/daemon/qrexec-daemon.c index 6da80767..f0267845 100644 --- a/daemon/qrexec-daemon.c +++ b/daemon/qrexec-daemon.c @@ -327,7 +327,6 @@ static void init(int xid) } } - close(0); if (!opt_direct) { snprintf(qrexec_error_log_name, sizeof(qrexec_error_log_name), @@ -625,25 +624,26 @@ static void handle_cmdline_message_from_client(int fd) static void handle_client_hello(int fd) { - struct msg_header hdr; - struct peer_info info; - - if (!read_all(fd, &hdr, sizeof hdr)) { + struct { + struct msg_header hdr; + struct peer_info info; + } data; + _Static_assert(sizeof data == sizeof(data.hdr) + sizeof(data.info), + "unexpected padding"); + + if (!read_all(fd, &data, sizeof data)) { terminate_client(fd); return; } - if (hdr.type != MSG_HELLO || hdr.len != sizeof(info)) { + if (data.hdr.type != MSG_HELLO || data.hdr.len != sizeof(data.info)) { LOG(ERROR, "Invalid HELLO packet received from client %d: " - "type %d, len %d", fd, hdr.type, hdr.len); + "type %d, len %d", fd, data.hdr.type, data.hdr.len); terminate_client(fd); return; } - if (!read_all(fd, &info, sizeof info)) { - terminate_client(fd); - return; - } - if (info.version != QREXEC_PROTOCOL_VERSION) { - LOG(ERROR, "Incompatible client protocol version (remote %d, local %d)", info.version, QREXEC_PROTOCOL_VERSION); + if (data.info.version != QREXEC_PROTOCOL_VERSION) { + LOG(ERROR, "Incompatible client protocol version (remote %d, local %d)", + data.info.version, QREXEC_PROTOCOL_VERSION); terminate_client(fd); return; } @@ -1484,6 +1484,18 @@ int main(int argc, char **argv) int i, opt; sigset_t selectmask; + { + int null_fd = open("/dev/null", O_RDONLY|O_NOCTTY); + if (null_fd < 0) + err(1, "open(%s)", "/dev/null"); + if (null_fd > 0) { + if (dup2(null_fd, 0) != 0) + err(1, "dup2(%d, 0)", null_fd); + if (null_fd > 2 && close(null_fd) != 0) + err(1, "close(%d)", null_fd); + } + } + setup_logging("qrexec-daemon"); while ((opt=getopt_long(argc, argv, "hqp:D", longopts, NULL)) != -1) { diff --git a/libqrexec/process_io.c b/libqrexec/process_io.c index 0525bdce..124370be 100644 --- a/libqrexec/process_io.c +++ b/libqrexec/process_io.c @@ -47,7 +47,7 @@ static _Noreturn void handle_vchan_error(const char *op) * don't care, because we created it) */ -static void close_stdin(int fd, bool restore_block) { +static void close_stdin(int fd, bool restore_block, bool close_fd) { if (fd == -1) return; @@ -55,16 +55,18 @@ static void close_stdin(int fd, bool restore_block) { set_block(fd); if (fd == 1) { - close(fd); - } else if (shutdown(fd, SHUT_WR) == -1) { - if (errno == ENOTSOCK) + if (close_fd) close(fd); - else + } else if (shutdown(fd, SHUT_WR) == -1) { + if (errno == ENOTSOCK) { + if (close_fd) + close(fd); + } else PERROR("shutdown close_stdin"); } } -static void close_stdout(int fd, bool restore_block) { +static void close_stdout(int fd, bool restore_block, bool close_fd) { if (fd == -1) return; @@ -72,11 +74,13 @@ static void close_stdout(int fd, bool restore_block) { set_block(fd); if (fd == 0) { - close(fd); - } else if (shutdown(fd, SHUT_RD) == -1) { - if (errno == ENOTSOCK) + if (close_fd) close(fd); - else + } else if (shutdown(fd, SHUT_RD) == -1) { + if (errno == ENOTSOCK) { + if (close_fd) + close(fd); + } else PERROR("shutdown close_stdout"); } } @@ -117,7 +121,7 @@ int process_io(const struct process_io_request *req) { pid_t local_status = -1; pid_t remote_status = -1; int stdout_msg_type = is_service ? MSG_DATA_STDOUT : MSG_DATA_STDIN; - bool use_stdio_socket = false; + bool use_stdio_socket = stdin_fd == stdout_fd; int ret; struct pollfd fds[FD_NUM]; @@ -134,8 +138,6 @@ int process_io(const struct process_io_request *req) { set_nonblock(stdin_fd); if (stdout_fd != stdin_fd) set_nonblock(stdout_fd); - else if ((stdout_fd = fcntl(stdin_fd, F_DUPFD_CLOEXEC, 3)) < 0) - abort(); // not worth handling running out of file descriptors if (stderr_fd >= 0) set_nonblock(stderr_fd); @@ -149,7 +151,7 @@ int process_io(const struct process_io_request *req) { else local_status = WEXITSTATUS(status); if (stdin_fd >= 0) { - close_stdin(stdin_fd, !use_stdio_socket); + close_stdin(stdin_fd, !use_stdio_socket, stdin_fd != stdout_fd); stdin_fd = -1; } } @@ -194,14 +196,12 @@ int process_io(const struct process_io_request *req) { } /* child signaled desire to use single socket for both stdin and stdout */ - if (sigusr1 && *sigusr1) { + if (sigusr1 && *sigusr1 && stdin_fd != stdout_fd) { if (stdout_fd != -1) { - do - errno = 0; - while (dup3(stdin_fd, stdout_fd, O_CLOEXEC) && - (errno == EINTR || errno == EBUSY)); - // other errors are fatal - if (errno) { + while (dup3(stdin_fd, stdout_fd, O_CLOEXEC) == -1) { + if (errno == EINTR || errno == EBUSY) + continue; + // other errors are fatal PERROR("dup3"); abort(); } @@ -265,7 +265,7 @@ int process_io(const struct process_io_request *req) { handle_vchan_error("wait"); if (stdin_fd >= 0 && fds[FD_STDIN].revents & (POLLHUP | POLLERR)) { - close_stdin(stdin_fd, !use_stdio_socket); + close_stdin(stdin_fd, !use_stdio_socket, stdin_fd != stdout_fd); stdin_fd = -1; } @@ -282,7 +282,7 @@ int process_io(const struct process_io_request *req) { handle_vchan_error("read"); break; case REMOTE_EOF: - close_stdin(stdin_fd, !use_stdio_socket); + close_stdin(stdin_fd, !use_stdio_socket, stdin_fd != stdout_fd); stdin_fd = -1; break; case REMOTE_EXITED: @@ -290,7 +290,7 @@ int 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. */ - close_stdout(stdout_fd, !use_stdio_socket); + close_stdout(stdout_fd, !use_stdio_socket, stdin_fd != stdout_fd); stdout_fd = -1; close_stderr(stderr_fd); stderr_fd = -1; @@ -304,7 +304,7 @@ int process_io(const struct process_io_request *req) { handle_vchan_error("send(handle_input stdout)"); break; case REMOTE_EOF: - close_stdout(stdout_fd, !use_stdio_socket); + close_stdout(stdout_fd, !use_stdio_socket, stdin_fd != stdout_fd); stdout_fd = -1; break; } @@ -325,8 +325,8 @@ int process_io(const struct process_io_request *req) { } /* make sure that all the pipes/sockets are closed, so the child process * (if any) will know that the connection is terminated */ - close_stdin(stdin_fd, true); - close_stdout(stdout_fd, true); + close_stdin(stdin_fd, true, stdin_fd != stdout_fd); + close_stdout(stdout_fd, true, true); close_stderr(stderr_fd); /* wait for local process, in case we exited early */