Skip to content

Commit

Permalink
Rip out qubes-rpc-multiplexer
Browse files Browse the repository at this point in the history
Instead, directly execute the command from C.

All variables with names beginning with QREXEC are stripped from the
environment, except for QREXEC_SERVICE_PATH.  This is a change in
behavior compared to the current code.

This is a backwards-incompatible change to
exec_qubes_rpc_if_requested(), which now takes an extra argument.
Therefore, it cannot be backported to R4.2.  It also requires changing
the SELinux policy so that the labels on /etc/qubes-rpc/ and
/usr/local/etc/qubes-rpc/ (and their contents) are correct.

Fixes: QubesOS/qubes-issues#9062
  • Loading branch information
DemiMarie committed Jan 5, 2025
1 parent 1d42668 commit 25bdcd0
Show file tree
Hide file tree
Showing 20 changed files with 264 additions and 114 deletions.
33 changes: 27 additions & 6 deletions agent/qrexec-agent-data.c
Original file line number Diff line number Diff line change
Expand Up @@ -138,34 +138,52 @@ int handle_handshake(libvchan_t *ctrl)

static int handle_just_exec(struct qrexec_parsed_command *cmd)
{
int fdn, pid;
int fdn, pid, log_fd;

if (cmd == NULL)
return QREXEC_EXIT_PROBLEM;

char file_path[QUBES_SOCKADDR_UN_MAX_PATH_LEN];
struct buffer buf = { .data = file_path, .buflen = (int)sizeof(file_path) };
struct buffer stdin_buffer;
buffer_init(&stdin_buffer);
if (cmd->service_descriptor) {
int socket_fd;
struct buffer stdin_buffer;
buffer_init(&stdin_buffer);
int status = find_qrexec_service(cmd, &socket_fd, &stdin_buffer);
int status = find_qrexec_service(cmd, &socket_fd, &stdin_buffer, &buf);
if (status == -1)
return QREXEC_EXIT_SERVICE_NOT_FOUND;
if (status != 0)
return QREXEC_EXIT_PROBLEM;
if (socket_fd != -1)
return write_all(socket_fd, stdin_buffer.data, stdin_buffer.buflen) ? 0 : QREXEC_EXIT_PROBLEM;
return write_all(socket_fd, stdin_buffer.data, stdin_buffer.buflen) ?
0 : QREXEC_EXIT_PROBLEM;
} else {
buf.data = NULL;
}
switch (pid = fork()) {
case -1:
PERROR("fork");
return QREXEC_EXIT_PROBLEM;
case 0:
fdn = open("/dev/null", O_RDWR);
fix_fds(fdn, fdn, fdn);
do_exec(cmd->command, cmd->username);
if (fdn < 0) {
LOG(ERROR, "open /dev/null failed");
_exit(QREXEC_EXIT_PROBLEM);
}
int other_pid;
log_fd = cmd->service_descriptor ? open_logger(cmd, &other_pid) : fdn;
if (log_fd < 0)
_exit(QREXEC_EXIT_PROBLEM);
fix_fds(fdn, fdn, log_fd);
do_exec(buf.data, cmd->command, cmd->username);
default:;
}
LOG(INFO, "executed (nowait): %s (pid %d)", cmd->command, pid);
if (buf.data)
LOG(INFO, "executed (nowait): %s %s (pid %d)", buf.data, cmd->command, pid);
else
LOG(INFO, "executed (nowait): %s (pid %d)", cmd->command, pid);
return 0;
}

Expand Down Expand Up @@ -261,6 +279,7 @@ static int handle_new_process_common(
return 0;
}

int logger_pid = 0;
req.vchan = data_vchan;
req.stdin_buf = &stdin_buf;

Expand All @@ -280,6 +299,8 @@ static int handle_new_process_common(

req.prefix_data.data = NULL;
req.prefix_data.len = 0;
if (cmd->service_descriptor != NULL)
req.logger_fd = open_logger(cmd, &logger_pid);

exit_code = qrexec_process_io(&req, cmd);

Expand Down
8 changes: 4 additions & 4 deletions agent/qrexec-agent.c
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ static struct pam_conv conv = {
* If dom0 sends overly long cmd, it will probably crash qrexec-agent (unless
* process can allocate up to 4GB on both stack and heap), sorry.
*/
_Noreturn void do_exec(const char *cmd, const char *user)
_Noreturn void do_exec(const char *prog, const char *cmd, const char *user)
{
#ifdef HAVE_PAM
int retval, status;
Expand Down Expand Up @@ -172,7 +172,7 @@ _Noreturn void do_exec(const char *cmd, const char *user)
exit(1);
}
/* call QUBESRPC if requested */
exec_qubes_rpc_if_requested(cmd, environ);
exec_qubes_rpc_if_requested(prog, cmd, environ);

/* otherwise exec shell */
execl("/bin/sh", "sh", "-c", cmd, NULL);
Expand Down Expand Up @@ -279,7 +279,7 @@ _Noreturn void do_exec(const char *cmd, const char *user)
warn("chdir(%s)", pw->pw_dir);

/* call QUBESRPC if requested */
exec_qubes_rpc_if_requested(cmd, env);
exec_qubes_rpc_if_requested(prog, cmd, env);

/* otherwise exec shell */
execle(pw->pw_shell, arg0, "-c", cmd, (char*)NULL, env);
Expand Down Expand Up @@ -317,7 +317,7 @@ _Noreturn void do_exec(const char *cmd, const char *user)
exit(1);
#else
/* call QUBESRPC if requested */
exec_qubes_rpc_if_requested(cmd, environ);
exec_qubes_rpc_if_requested(prog, cmd, environ);

/* otherwise exec shell */
execl("/bin/su", "su", "-", user, "-c", cmd, NULL);
Expand Down
2 changes: 1 addition & 1 deletion agent/qrexec-agent.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@

int handle_handshake(libvchan_t *ctrl);
void handle_vchan_error(const char *op);
_Noreturn void do_exec(const char *cmd, const char *user);
_Noreturn void do_exec(const char *prog, const char *cmd, const char *user);
/* call before fork() for service handling process (either end) */
void prepare_child_env(void);

Expand Down
2 changes: 1 addition & 1 deletion agent/qrexec-client-vm.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ _Noreturn void handle_vchan_error(const char *op)
exit(1);
}

_Noreturn void do_exec(const char *cmd __attribute__((unused)), char const* user __attribute__((__unused__))) {
_Noreturn void do_exec(const char *prog __attribute__((unused)), const char *cmd __attribute__((unused)), char const* user __attribute__((__unused__))) {
LOG(ERROR, "BUG: do_exec function shouldn't be called!");
abort();
}
Expand Down
4 changes: 2 additions & 2 deletions agent/qrexec-fork-server.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,15 @@
extern char **environ;
const bool qrexec_is_fork_server = true;

void do_exec(const char *cmd, const char *user __attribute__((unused)))
void do_exec(const char *prog, const char *cmd, const char *user __attribute__((unused)))
{
char *shell;

signal(SIGCHLD, SIG_DFL);
signal(SIGPIPE, SIG_DFL);

/* call QUBESRPC if requested */
exec_qubes_rpc_if_requested(cmd, environ);
exec_qubes_rpc_if_requested(prog, cmd, environ);

/* otherwise, pass it to shell */
shell = getenv("SHELL");
Expand Down
12 changes: 7 additions & 5 deletions daemon/qrexec-client.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,15 @@ static void set_remote_domain(const char *src_domain_name) {
}

/* called from do_fork_exec */
static _Noreturn void do_exec(const char *prog, const char *username __attribute__((unused)))
static _Noreturn void do_exec(const char *prog,
const char *cmdline,
const char *username __attribute__((unused)))
{
/* avoid calling qubes-rpc-multiplexer through shell */
exec_qubes_rpc_if_requested(prog, environ);
/* avoid calling RPC command through shell */
exec_qubes_rpc_if_requested(prog, cmdline, environ);

/* if above haven't executed qubes-rpc-multiplexer, pass it to shell */
execl("/bin/bash", "bash", "-c", prog, NULL);
/* if above haven't executed RPC command, pass it to shell */
execl("/bin/bash", "bash", "-c", cmdline, NULL);
PERROR("exec bash");
exit(1);
}
Expand Down
11 changes: 6 additions & 5 deletions daemon/qrexec-daemon.c
Original file line number Diff line number Diff line change
Expand Up @@ -1131,14 +1131,15 @@ static enum policy_response connect_daemon_socket(
}

/* called from do_fork_exec */
static _Noreturn void do_exec(const char *prog, const char *username __attribute__((unused)))
static _Noreturn void do_exec(const char *prog, const char *cmd, const char *username __attribute__((unused)))
{
/* avoid calling qubes-rpc-multiplexer through shell */
exec_qubes_rpc_if_requested(prog, environ);
/* avoid calling RPC command through shell */
exec_qubes_rpc_if_requested(prog, cmd, environ);

/* if above haven't executed qubes-rpc-multiplexer, pass it to shell */
execl("/bin/bash", "bash", "-c", prog, NULL);
/* if above haven't executed RPC command, pass it to shell */
execl("/bin/bash", "bash", "-c", cmd, NULL);
PERROR("exec bash");
/* treat ENOENT as "problem" because bash should always exist */
_exit(QREXEC_EXIT_PROBLEM);
}

Expand Down
2 changes: 1 addition & 1 deletion libqrexec/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ endif


all: libqrexec-utils.so
libqrexec-utils.so.$(SO_VER): unix-server.o ioall.o buffer.o exec.o txrx-vchan.o write-stdin.o replace.o remote.o process_io.o log.o toml.o vchan_timeout.o
libqrexec-utils.so.$(SO_VER): unix-server.o ioall.o buffer.o exec.o txrx-vchan.o write-stdin.o replace.o remote.o process_io.o log.o toml.o open_logger.o vchan_timeout.o
$(CC) $(LDFLAGS) -Wl,-soname,$@ -o $@ $^ $(VCHANLIBS)

libqrexec-utils.so: libqrexec-utils.so.$(SO_VER)
Expand Down
10 changes: 5 additions & 5 deletions libqrexec/buffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,12 @@ static char *limited_malloc(int len)
(total_mem > BUFFER_LIMIT) || (len <= 0))
{
LOG(ERROR, "attempt to allocate >BUFFER_LIMIT");
exit(1);
abort();
}
ret = malloc((size_t)len);
if (!ret) {
PERROR("malloc");
exit(1);
abort();
}
return ret;
}
Expand Down Expand Up @@ -83,11 +83,11 @@ void buffer_append(struct buffer *b, const char *data, int len)
assert(data != NULL && "NULL data");
if (b->buflen < 0 || b->buflen > BUFFER_LIMIT) {
LOG(ERROR, "buffer_append buflen %d", len);
exit(1);
abort();
}
if (len < 0 || len > BUFFER_LIMIT) {
LOG(ERROR, "buffer_append %d", len);
exit(1);
abort();
}
if (len == 0)
return;
Expand All @@ -108,7 +108,7 @@ void buffer_remove(struct buffer *b, int len)
char *qdata = NULL;
if (len < 0 || len > b->buflen) {
LOG(ERROR, "buffer_remove %d/%d", len, b->buflen);
exit(1);
abort();
}
newsize = b->buflen - len;
if (newsize > 0) {
Expand Down
Loading

0 comments on commit 25bdcd0

Please sign in to comment.