diff --git a/daemon/Makefile b/daemon/Makefile index ce61d83d..d3946d41 100644 --- a/daemon/Makefile +++ b/daemon/Makefile @@ -4,7 +4,8 @@ override QUBES_CFLAGS:=-I../libqrexec -g -O2 -Wall -Wextra -Werror -fPIC \ $(shell pkg-config --cflags $(VCHAN_PKG)) -fstack-protector \ -D_FORTIFY_SOURCE=2 -fstack-protector-strong -std=gnu11 -D_POSIX_C_SOURCE=200809L \ -D_GNU_SOURCE $(CFLAGS) \ - -Wstrict-prototypes -Wold-style-definition -Wmissing-declarations + -Wstrict-prototypes -Wold-style-definition -Wmissing-declarations \ + -fvisibility=hidden override LDFLAGS += -pie -Wl,-z,relro,-z,now -L../libqrexec override LDLIBS += $(shell pkg-config --libs $(VCHAN_PKG)) -lqrexec-utils @@ -22,8 +23,8 @@ install: all ln -sf ../../bin/qrexec-client $(DESTDIR)/usr/lib/qubes/qrexec-client .PHONY: all clean install -qrexec-daemon qrexec-client: %: %.o - $(CC) $(LDFLAGS) -pie -g -o $@ $< $(LDLIBS) +qrexec-daemon qrexec-client: %: %.o qrexec-daemon-common.o + $(CC) $(LDFLAGS) -pie -g -o $@ $^ $(LDLIBS) %.o: %.c $(CC) $< -c -o $@ $(QUBES_CFLAGS) -MD -MP -MF $@.dep diff --git a/daemon/qrexec-client.c b/daemon/qrexec-client.c index e0d6eb66..ab738a39 100644 --- a/daemon/qrexec-client.c +++ b/daemon/qrexec-client.c @@ -39,6 +39,7 @@ #include #include "libqrexec-utils.h" +#include "qrexec-daemon-common.h" // whether qrexec-client should replace problematic bytes with _ before printing the output static bool replace_chars_stdout = false; @@ -58,8 +59,6 @@ static bool is_service = false; static volatile sig_atomic_t sigchld = 0; -static const char *socket_dir = QREXEC_DAEMON_SOCKET_DIR; - extern char **environ; static char *xstrdup(const char *arg) { @@ -128,75 +127,6 @@ static int handle_agent_handshake(libvchan_t *vchan, bool remote_send_first) return data_protocol_version; } -static int handle_daemon_handshake(int fd) -{ - struct msg_header hdr; - struct peer_info info; - - /* daemon send MSG_HELLO first */ - if (!read_all(fd, &hdr, sizeof(hdr))) { - PERROR("daemon handshake"); - return -1; - } - if (hdr.type != MSG_HELLO || hdr.len != sizeof(info)) { - LOG(ERROR, "Invalid daemon MSG_HELLO"); - return -1; - } - if (!read_all(fd, &info, sizeof(info))) { - PERROR("daemon handshake"); - return -1; - } - - if (info.version != QREXEC_PROTOCOL_VERSION) { - LOG(ERROR, "Incompatible daemon protocol version " - "(daemon %d, client %d)", - info.version, QREXEC_PROTOCOL_VERSION); - return -1; - } - - hdr.type = MSG_HELLO; - hdr.len = sizeof(info); - info.version = QREXEC_PROTOCOL_VERSION; - - if (!write_all(fd, &hdr, sizeof(hdr))) { - LOG(ERROR, "Failed to send MSG_HELLO hdr to daemon"); - return -1; - } - if (!write_all(fd, &info, sizeof(info))) { - LOG(ERROR, "Failed to send MSG_HELLO to daemon"); - return -1; - } - return 0; -} - -static int connect_unix_socket(const char *domname) -{ - int s, len, res; - struct sockaddr_un remote; - - if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { - PERROR("socket"); - return -1; - } - - remote.sun_family = AF_UNIX; - res = snprintf(remote.sun_path, sizeof remote.sun_path, - "%s/qrexec.%s", socket_dir, domname); - if (res < 0) - err(1, "snprintf"); - if (res >= (int)sizeof(remote.sun_path)) - errx(1, "%s/qrexec.%s is too long for AF_UNIX socket path", - socket_dir, domname); - len = (size_t)res + 1 + offsetof(struct sockaddr_un, sun_path); - if (connect(s, (struct sockaddr *) &remote, len) == -1) { - PERROR("connect"); - exit(1); - } - if (handle_daemon_handshake(s) < 0) - exit(1); - return s; -} - static void sigchld_handler(int x __attribute__((__unused__))) { sigchld = 1; @@ -312,66 +242,6 @@ static _Noreturn void handle_failed_exec(libvchan_t *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, - int *data_domain, int *data_port) -{ - struct msg_header hdr; - struct exec_params params; - hdr.type = type; - hdr.len = sizeof(params) + cmdline_size; - params.connect_domain = other_domid; - params.connect_port = 0; - if (!write_all(s, &hdr, sizeof(hdr)) - || !write_all(s, ¶ms, sizeof(params)) - || !write_all(s, cmdline_param, cmdline_size)) { - PERROR("write daemon"); - exit(1); - } - /* the daemon will respond with the same message with connect_port filled - * and empty cmdline */ - if (!read_all(s, &hdr, sizeof(hdr))) { - PERROR("read daemon"); - exit(1); - } - assert(hdr.type == type); - if (hdr.len != sizeof(params)) { - LOG(ERROR, "Invalid response for 0x%x", type); - exit(1); - } - if (!read_all(s, ¶ms, sizeof(params))) { - PERROR("read daemon"); - exit(1); - } - *data_port = params.connect_port; - *data_domain = params.connect_domain; -} - -static void send_service_connect(int s, char *conn_ident, - int connect_domain, int connect_port) -{ - struct msg_header hdr; - struct exec_params exec_params; - struct service_params srv_params; - - hdr.type = MSG_SERVICE_CONNECT; - hdr.len = sizeof(exec_params) + sizeof(srv_params); - - exec_params.connect_domain = connect_domain; - exec_params.connect_port = connect_port; - strncpy(srv_params.ident, conn_ident, sizeof(srv_params.ident) - 1); - srv_params.ident[sizeof(srv_params.ident) - 1] = '\0'; - - if (!write_all(s, &hdr, sizeof(hdr)) - || !write_all(s, &exec_params, sizeof(exec_params)) - || !write_all(s, &srv_params, sizeof(srv_params))) { - PERROR("write daemon"); - exit(1); - } -} - static void select_loop(libvchan_t *vchan, int data_protocol_version, struct buffer *stdin_buf) { struct process_io_request req = { 0 }; @@ -560,7 +430,7 @@ int main(int argc, char **argv) int data_domain; int s; bool just_exec = false; - int wait_connection_end = 0; + int wait_connection_end = -1; char *local_cmdline = NULL; char *remote_cmdline = NULL; char *request_id = NULL; @@ -570,6 +440,7 @@ int main(int argc, char **argv) struct service_params svc_params; int prepare_ret; bool kill = false; + int rc = 126; if (argc < 3) { // certainly too few arguments @@ -636,13 +507,6 @@ int main(int argc, char **argv) usage(argv[0]); } - char src_domain_id_str[11]; - { - int snprintf_res = snprintf(src_domain_id_str, sizeof(src_domain_id_str), "%d", src_domain_id); - if (snprintf_res < 0 || snprintf_res >= (int)sizeof(src_domain_id_str)) - err(1, "snprintf()"); - } - if (strcmp(domname, "dom0") == 0 || strcmp(domname, "@adminvm") == 0) { if (request_id == NULL) { fprintf(stderr, "ERROR: when target domain is 'dom0', -c must be specified\n"); @@ -655,14 +519,19 @@ int main(int argc, char **argv) abort(); } set_remote_domain(src_domain_name); - s = connect_unix_socket(src_domain_id_str); - negotiate_connection_params(s, + s = connect_unix_socket_by_id(src_domain_id); + if (s < 0) { + goto cleanup; + } + if (!negotiate_connection_params(s, 0, /* dom0 */ MSG_SERVICE_CONNECT, (void*)&svc_params, sizeof(svc_params), &data_domain, - &data_port); + &data_port)) { + goto cleanup; + } struct buffer stdin_buffer; buffer_init(&stdin_buffer); @@ -684,30 +553,39 @@ int main(int argc, char **argv) handshake_and_go(data_vchan, &stdin_buffer, true, prepare_ret); } else { s = connect_unix_socket(domname); - negotiate_connection_params(s, + if (!negotiate_connection_params(s, src_domain_id, just_exec ? MSG_JUST_EXEC : MSG_EXEC_CMDLINE, remote_cmdline, compute_service_length(remote_cmdline, argv[0]), &data_domain, - &data_port); - if (wait_connection_end && request_id) - /* save socket fd, 's' will be reused for the other qrexec-daemon - * connection */ - wait_connection_end = s; - else - close(s); + &data_port)) { + goto cleanup; + } if (request_id) { - s = connect_unix_socket(src_domain_id_str); - send_service_connect(s, request_id, data_domain, data_port); + if (wait_connection_end != -1) { + /* save socket fd, 's' will be reused for the other qrexec-daemon + * connection */ + wait_connection_end = s; + } else { + close(s); + } + s = connect_unix_socket_by_id(src_domain_id); + if (s == -1) { + goto cleanup; + } + if (!send_service_connect(s, request_id, data_domain, data_port)) { + goto cleanup; + } close(s); - if (wait_connection_end) { + if (wait_connection_end != -1) { /* wait for EOF */ struct pollfd fds[1] = { { .fd = wait_connection_end, .events = POLLIN | POLLHUP, .revents = 0 }, }; poll(fds, 1, -1); } + rc = 0; } else { set_remote_domain(domname); struct buffer stdin_buffer; @@ -724,12 +602,13 @@ int main(int argc, char **argv) } } +cleanup: if (kill && domname) { size_t l; qubesd_call(domname, "admin.vm.Kill", "", &l); } - return 0; + return rc; } // vim:ts=4:sw=4:et: diff --git a/daemon/qrexec-daemon-common.c b/daemon/qrexec-daemon-common.c new file mode 100644 index 00000000..7ac2cbdf --- /dev/null +++ b/daemon/qrexec-daemon-common.c @@ -0,0 +1,152 @@ +#include +#include +#include +#include +#include + +#include "qrexec.h" +#include "libqrexec-utils.h" +#include "qrexec-daemon-common.h" + +const char *socket_dir = QREXEC_DAEMON_SOCKET_DIR; + +/* ask the daemon to allocate vchan port */ +bool negotiate_connection_params(int s, int other_domid, unsigned type, + void *cmdline_param, int cmdline_size, + int *data_domain, int *data_port) +{ + struct msg_header hdr; + struct exec_params params; + hdr.type = type; + hdr.len = sizeof(params) + cmdline_size; + params.connect_domain = other_domid; + params.connect_port = 0; + if (!write_all(s, &hdr, sizeof(hdr)) + || !write_all(s, ¶ms, sizeof(params)) + || !write_all(s, cmdline_param, cmdline_size)) { + PERROR("write daemon"); + return false; + } + /* the daemon will respond with the same message with connect_port filled + * and empty cmdline */ + if (!read_all(s, &hdr, sizeof(hdr))) { + PERROR("read daemon"); + return false; + } + assert(hdr.type == type); + if (hdr.len != sizeof(params)) { + LOG(ERROR, "Invalid response for 0x%x", type); + return false; + } + if (!read_all(s, ¶ms, sizeof(params))) { + PERROR("read daemon"); + return false; + } + *data_port = params.connect_port; + *data_domain = params.connect_domain; + return true; +} + +int handle_daemon_handshake(int fd) +{ + struct msg_header hdr; + struct peer_info info; + + /* daemon send MSG_HELLO first */ + if (!read_all(fd, &hdr, sizeof(hdr))) { + PERROR("daemon handshake"); + return -1; + } + if (hdr.type != MSG_HELLO || hdr.len != sizeof(info)) { + LOG(ERROR, "Invalid daemon MSG_HELLO"); + return -1; + } + if (!read_all(fd, &info, sizeof(info))) { + PERROR("daemon handshake"); + return -1; + } + + if (info.version != QREXEC_PROTOCOL_VERSION) { + LOG(ERROR, "Incompatible daemon protocol version " + "(daemon %d, client %d)", + info.version, QREXEC_PROTOCOL_VERSION); + return -1; + } + + hdr.type = MSG_HELLO; + hdr.len = sizeof(info); + info.version = QREXEC_PROTOCOL_VERSION; + + if (!write_all(fd, &hdr, sizeof(hdr))) { + LOG(ERROR, "Failed to send MSG_HELLO hdr to daemon"); + return -1; + } + if (!write_all(fd, &info, sizeof(info))) { + LOG(ERROR, "Failed to send MSG_HELLO to daemon"); + return -1; + } + return 0; +} + +int connect_unix_socket_by_id(unsigned int domid) +{ + char id_str[11]; + int snprintf_res = snprintf(id_str, sizeof(id_str), "%u", domid); + if (snprintf_res < 0 || snprintf_res >= (int)sizeof(id_str)) + abort(); + return connect_unix_socket(id_str); +} + +int connect_unix_socket(const char *domname) +{ + int s, len, res; + struct sockaddr_un remote; + + if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + LOG(ERROR, "socket() failed: %m"); + return -1; + } + + remote.sun_family = AF_UNIX; + res = snprintf(remote.sun_path, sizeof remote.sun_path, + "%s/qrexec.%s", socket_dir, domname); + if (res < 0) + abort(); + if (res >= (int)sizeof(remote.sun_path)) { + LOG(ERROR, "%s/qrexec.%s is too long for AF_UNIX socket path", + socket_dir, domname); + return -1; + } + len = (size_t)res + 1 + offsetof(struct sockaddr_un, sun_path); + if (connect(s, (struct sockaddr *) &remote, len) == -1) { + LOG(ERROR, "connect %s", remote.sun_path); + return -1; + } + if (handle_daemon_handshake(s) < 0) + return -1; + return s; +} + +bool send_service_connect(int s, const char *conn_ident, + int connect_domain, int connect_port) +{ + struct msg_header hdr; + struct exec_params exec_params; + struct service_params srv_params; + + hdr.type = MSG_SERVICE_CONNECT; + hdr.len = sizeof(exec_params) + sizeof(srv_params); + + exec_params.connect_domain = connect_domain; + exec_params.connect_port = connect_port; + strncpy(srv_params.ident, conn_ident, sizeof(srv_params.ident) - 1); + srv_params.ident[sizeof(srv_params.ident) - 1] = '\0'; + + if (!write_all(s, &hdr, sizeof(hdr)) + || !write_all(s, &exec_params, sizeof(exec_params)) + || !write_all(s, &srv_params, sizeof(srv_params))) { + PERROR("write daemon"); + return false; + } + return true; +} diff --git a/daemon/qrexec-daemon-common.h b/daemon/qrexec-daemon-common.h new file mode 100644 index 00000000..b670a1ef --- /dev/null +++ b/daemon/qrexec-daemon-common.h @@ -0,0 +1,14 @@ +extern const char *socket_dir; +__attribute__((warn_unused_result)) +int connect_unix_socket_by_id(unsigned int domid); +__attribute__((warn_unused_result)) +int connect_unix_socket(const char *domname); +__attribute__((warn_unused_result)) +int handle_daemon_handshake(int fd); +__attribute__((warn_unused_result)) +bool negotiate_connection_params(int s, int other_domid, unsigned type, + void *cmdline_param, int cmdline_size, + int *data_domain, int *data_port); +__attribute__((warn_unused_result)) +bool send_service_connect(int s, const char *conn_ident, + int connect_domain, int connect_port); diff --git a/daemon/qrexec-daemon.c b/daemon/qrexec-daemon.c index 58ec78c4..226fd74d 100644 --- a/daemon/qrexec-daemon.c +++ b/daemon/qrexec-daemon.c @@ -36,6 +36,7 @@ #include "qrexec.h" #include "libqrexec-utils.h" #include "../libqrexec/ioall.h" +#include "qrexec-daemon-common.h" #define QREXEC_MIN_VERSION QREXEC_PROTOCOL_V2 #define QREXEC_SOCKET_PATH "/run/qubes/policy.sock" @@ -44,6 +45,12 @@ void __gcov_dump(void); void __gcov_reset(void); #endif +static _Noreturn void daemon__exit(int status) { +#ifdef COVERAGE + __gcov_dump(); +#endif + _exit(status); +} enum client_state { CLIENT_INVALID = 0, // table slot not used @@ -105,7 +112,6 @@ static const char default_user_keyword[] = "DEFAULT:"; static int opt_quiet = 0; static int opt_direct = 0; -static const char *socket_dir = QREXEC_DAEMON_SOCKET_DIR; static const char *policy_program = QREXEC_POLICY_PROGRAM; #ifdef __GNUC__ @@ -913,7 +919,7 @@ static void send_request_to_daemon( service_name); if (command_size < 0) { PERROR("failed to construct request"); - _exit(126); + daemon__exit(126); } for (int i = 0; i < command_size; i += bytes_sent) { @@ -923,12 +929,20 @@ static void send_request_to_daemon( if (bytes_sent < 0) { assert(bytes_sent == -1); PERROR("send to socket failed"); - _exit(126); + daemon__exit(126); } } free(command); } +static _Noreturn void null_exit(void) +{ +#ifdef COVERAGE + __gcov_dump(); +#endif + _exit(126); +} + /* * Called when agent sends a message asking to execute a predefined command. */ @@ -951,7 +965,7 @@ static enum policy_response connect_daemon_socket( int daemon_socket = socket(AF_UNIX, SOCK_STREAM, 0); if (daemon_socket < 0) { PERROR("socket creation failed"); - _exit(126); + daemon__exit(126); } int connect_result = connect(daemon_socket, @@ -982,7 +996,7 @@ static enum policy_response connect_daemon_socket( int fds[2]; if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, fds)) { PERROR("socketpair()"); - _exit(126); + daemon__exit(126); } daemon_socket = fds[0]; @@ -990,13 +1004,13 @@ static enum policy_response connect_daemon_socket( switch (pid) { case -1: LOG(ERROR, "Could not fork!"); - _exit(126); + daemon__exit(126); case 0: if (close(fds[0])) - abort(); + _exit(126); if (dup2(fds[1], 0) != 0 || dup2(fds[1], 1) != 1) { PERROR("dup2()"); - _exit(126); + daemon__exit(126); } if (close(fds[1])) abort(); @@ -1015,7 +1029,7 @@ static enum policy_response connect_daemon_socket( } else { PERROR("snprintf"); } - _exit(126); + daemon__exit(126); default: if (close(fds[1])) abort(); @@ -1026,12 +1040,12 @@ static enum policy_response connect_daemon_socket( do { if (waitpid(pid, &status, 0) != pid) { PERROR("waitpid"); - _exit(126); + daemon__exit(126); } } while (!WIFEXITED(status)); if (WEXITSTATUS(status) != 0) { LOG(ERROR, "qrexec-policy-exec failed"); - _exit(126); + daemon__exit(126); } // This leaks 'result', but as the code execs later anyway this isn't a problem. // 'result' cannot be freed as 'user', 'target', and 'requested_target' point into @@ -1040,36 +1054,23 @@ static enum policy_response connect_daemon_socket( } } -static void handle_execute_service( +static size_t compute_service_length(const char *const remote_cmdline) { + const size_t service_length = strlen(remote_cmdline) + 1; + if (service_length < 2 || service_length > MAX_QREXEC_CMD_LEN) { + /* This is arbitrary, but it helps reduce the risk of overflows in other code */ + errx(1, "Bad command: command line too long or empty: length %zu\n", service_length); + } + return service_length; +} + + +_Noreturn static void handle_execute_service_child( const int remote_domain_id, const char *remote_domain_name, const char *target_domain, const char *service_name, - const struct service_params *request_id) -{ + const struct service_params *request_id) { int i; - int policy_pending_slot; - pid_t pid; - - policy_pending_slot = find_policy_pending_slot(); - if (policy_pending_slot < 0) { - LOG(ERROR, "Service request denied, too many pending requests"); - send_service_refused(vchan, request_id); - return; - } - - switch (pid=fork()) { - case -1: - PERROR("fork"); - exit(1); - case 0: - break; - default: - policy_pending[policy_pending_slot].pid = pid; - policy_pending[policy_pending_slot].params = *request_id; - policy_pending[policy_pending_slot].response_sent = RESPONSE_PENDING; - return; - } for (i = 3; i < MAX_FDS; i++) close(i); @@ -1081,7 +1082,7 @@ static void handle_execute_service( &user, &target, &requested_target, &autostart); if (policy_response != RESPONSE_ALLOW) - _exit(126); + daemon__exit(126); /* Replace the target domain with the version normalized by the policy engine */ target_domain = requested_target; @@ -1113,14 +1114,31 @@ static void handle_execute_service( remote_domain_name, type, target_domain) <= 0) - _exit(126); + daemon__exit(126); + char *cid; + if (asprintf(&cid, "%s,%s,%d", request_id->ident, remote_domain_name, remote_domain_id) <= 0) + daemon__exit(126); + + const char *to_exec[] = { + "/usr/bin/qrexec-client", + "-Ed", + target, + "-c", + cid, + "--", + cmd, + NULL, + }; + execv(to_exec[0], (char **)to_exec); + LOG(ERROR, "execve() failed: %m"); + daemon__exit(126); } else { char *buf; if (strncmp("@dispvm:", target, sizeof("@dispvm:") - 1) == 0) { disposable = true; buf = qubesd_call(target + 8, "admin.vm.CreateDisposable", "", &resp_len); if (!buf) // error already printed by qubesd_call - _exit(126); + daemon__exit(126); if (memcmp(buf, "0", 2) == 0) { /* we exec later so memory leaks do not matter */ target = buf + 2; @@ -1130,7 +1148,7 @@ static void handle_execute_service( } else { LOG(ERROR, "invalid response to admin.vm.CreateDisposable"); } - _exit(126); + daemon__exit(126); } } if (asprintf(&cmd, "%s:QUBESRPC %s%s %s", @@ -1138,11 +1156,11 @@ static void handle_execute_service( service_name, trailer, remote_domain_name) <= 0) - _exit(126); + daemon__exit(126); if (autostart) { buf = qubesd_call(target, "admin.vm.Start", "", &resp_len); if (!buf) // error already printed by qubesd_call - _exit(126); + daemon__exit(126); if (!((memcmp(buf, "0", 2) == 0) || (resp_len >= 24 && memcmp(buf, "2\0QubesVMNotHaltedError", 24) == 0))) { if (memcmp(buf, "2", 2) == 0) { @@ -1150,28 +1168,79 @@ static void handle_execute_service( } else { LOG(ERROR, "invalid response to admin.vm.Start"); } - _exit(126); + daemon__exit(126); } free(buf); } + int s = connect_unix_socket(target); + int data_domain; + int data_port; + int rc = 126; + if (!negotiate_connection_params(s, + remote_domain_id, + MSG_EXEC_CMDLINE, + cmd, + compute_service_length(cmd), + &data_domain, + &data_port)) + daemon__exit(126); + int wait_connection_end = -1; + if (disposable) { + wait_connection_end = s; + } else { + close(s); + } + + s = connect_unix_socket_by_id((unsigned)remote_domain_id); + if (send_service_connect(s, request_id->ident, data_domain, data_port)) + rc = 0; + close(s); + if (wait_connection_end != -1) { + /* wait for EOF */ + struct pollfd fds[1] = { + { .fd = wait_connection_end, .events = POLLIN | POLLHUP, .revents = 0 }, + }; + poll(fds, 1, -1); + size_t l; + qubesd_call(target, "admin.vm.Kill", "", &l); + } + daemon__exit(rc); + } +} + +static void handle_execute_service( + const int remote_domain_id, + const char *remote_domain_name, + const char *target_domain, + const char *service_name, + const struct service_params *request_id) +{ + int policy_pending_slot; + pid_t pid; + + policy_pending_slot = find_policy_pending_slot(); + if (policy_pending_slot < 0) { + LOG(ERROR, "Service request denied, too many pending requests"); + send_service_refused(vchan, request_id); + return; + } + + switch (pid=fork()) { + case -1: + PERROR("fork"); + exit(1); + case 0: + if (atexit(null_exit)) + _exit(126); + handle_execute_service_child(remote_domain_id, remote_domain_name, + target_domain, service_name, request_id); + abort(); + default: + policy_pending[policy_pending_slot].pid = pid; + policy_pending[policy_pending_slot].params = *request_id; + policy_pending[policy_pending_slot].response_sent = RESPONSE_PENDING; + return; } - char *cid; - if (asprintf(&cid, "%s,%s,%d", request_id->ident, remote_domain_name, remote_domain_id) <= 0) - _exit(126); - - const char *to_exec[] = { - "/usr/bin/qrexec-client", - disposable ? "-EWkd" : "-Ed", - target, - "-c", - cid, - "--", - cmd, - NULL, - }; - execv(to_exec[0], (char **)to_exec); - LOG(ERROR, "execve() failed: %m"); - _exit(126); } diff --git a/fuzz/Makefile b/fuzz/Makefile index 01aa89de..9cfa3168 100644 --- a/fuzz/Makefile +++ b/fuzz/Makefile @@ -38,7 +38,7 @@ test-%: % %_seed_corpus.zip unzip $<_seed_corpus.zip ./$< $<_seed_corpus -runs=100000 -qrexec_daemon_fuzzer: qrexec_daemon_fuzzer.o fuzz.o $(LIBQREXEC_OBJS) daemon-qrexec-daemon.o +qrexec_daemon_fuzzer: qrexec_daemon_fuzzer.o fuzz.o $(LIBQREXEC_OBJS) daemon-qrexec-daemon.o daemon-qrexec-daemon-common.o %_fuzzer: %_fuzzer.o fuzz.o $(LIBQREXEC_OBJS) $(CXX) $(CXXFLAGS) -o $@ $^ $(LIB_FUZZING_ENGINE)