X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fcore%2Fexecute.c;h=18e25fa6e69dd14ad7cf3dae0dde69b53da3195c;hp=7dc15044b4982866719a40801f0cee18378b903e;hb=c17ec25e4d9bd6c8e8617416f813e25b2ebbafc5;hpb=2bef10ab3648db144c421f7765d20dbdf1afe074;ds=sidebyside diff --git a/src/core/execute.c b/src/core/execute.c index 7dc15044b..18e25fa6e 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -64,6 +64,8 @@ #include "loopback-setup.h" #include "path-util.h" #include "syscall-list.h" +#include "env-util.h" +#include "fileio.h" #define IDLE_TIMEOUT_USEC (5*USEC_PER_SEC) @@ -163,6 +165,26 @@ void exec_context_tty_reset(const ExecContext *context) { vt_disallocate(context->tty_path); } +static bool is_terminal_output(ExecOutput o) { + return + o == EXEC_OUTPUT_TTY || + o == EXEC_OUTPUT_SYSLOG_AND_CONSOLE || + o == EXEC_OUTPUT_KMSG_AND_CONSOLE || + o == EXEC_OUTPUT_JOURNAL_AND_CONSOLE; +} + +void exec_context_serialize(const ExecContext *context, Unit *u, FILE *f) { + assert(context); + assert(u); + assert(f); + + if (context->tmp_dir) + unit_serialize_item(u, f, "tmp-dir", context->tmp_dir); + + if (context->var_tmp_dir) + unit_serialize_item(u, f, "var-tmp-dir", context->var_tmp_dir); +} + static int open_null_as(int flags, int nfd) { int fd, r; @@ -222,7 +244,7 @@ static int connect_logger_as(const ExecContext *context, ExecOutput output, cons !!context->syslog_level_prefix, output == EXEC_OUTPUT_SYSLOG || output == EXEC_OUTPUT_SYSLOG_AND_CONSOLE, output == EXEC_OUTPUT_KMSG || output == EXEC_OUTPUT_KMSG_AND_CONSOLE, - output == EXEC_OUTPUT_SYSLOG_AND_CONSOLE || output == EXEC_OUTPUT_KMSG_AND_CONSOLE || output == EXEC_OUTPUT_JOURNAL_AND_CONSOLE); + is_terminal_output(output)); if (fd != nfd) { r = dup2(fd, nfd) < 0 ? -errno : nfd; @@ -318,9 +340,10 @@ static int setup_input(const ExecContext *context, int socket_fd, bool apply_tty } } -static int setup_output(const ExecContext *context, int socket_fd, const char *ident, const char *unit_id, bool apply_tty_stdin) { +static int setup_output(const ExecContext *context, int fileno, int socket_fd, const char *ident, const char *unit_id, bool apply_tty_stdin) { ExecOutput o; ExecInput i; + int r; assert(context); assert(ident); @@ -328,91 +351,55 @@ static int setup_output(const ExecContext *context, int socket_fd, const char *i i = fixup_input(context->std_input, socket_fd, apply_tty_stdin); o = fixup_output(context->std_output, socket_fd); - /* This expects the input is already set up */ + if (fileno == STDERR_FILENO) { + ExecOutput e; + e = fixup_output(context->std_error, socket_fd); - switch (o) { + /* This expects the input and output are already set up */ + + /* Don't change the stderr file descriptor if we inherit all + * the way and are not on a tty */ + if (e == EXEC_OUTPUT_INHERIT && + o == EXEC_OUTPUT_INHERIT && + i == EXEC_INPUT_NULL && + !is_terminal_input(context->std_input) && + getppid () != 1) + return fileno; - case EXEC_OUTPUT_INHERIT: + /* Duplicate from stdout if possible */ + if (e == o || e == EXEC_OUTPUT_INHERIT) + return dup2(STDOUT_FILENO, fileno) < 0 ? -errno : fileno; + o = e; + + } else if (o == EXEC_OUTPUT_INHERIT) { /* If input got downgraded, inherit the original value */ if (i == EXEC_INPUT_NULL && is_terminal_input(context->std_input)) - return open_terminal_as(tty_path(context), O_WRONLY, STDOUT_FILENO); + return open_terminal_as(tty_path(context), O_WRONLY, fileno); /* If the input is connected to anything that's not a /dev/null, inherit that... */ if (i != EXEC_INPUT_NULL) - return dup2(STDIN_FILENO, STDOUT_FILENO) < 0 ? -errno : STDOUT_FILENO; + return dup2(STDIN_FILENO, fileno) < 0 ? -errno : fileno; /* If we are not started from PID 1 we just inherit STDOUT from our parent process. */ if (getppid() != 1) - return STDOUT_FILENO; - - /* We need to open /dev/null here anew, to get the - * right access mode. So we fall through */ + return fileno; - case EXEC_OUTPUT_NULL: - return open_null_as(O_WRONLY, STDOUT_FILENO); - - case EXEC_OUTPUT_TTY: - if (is_terminal_input(i)) - return dup2(STDIN_FILENO, STDOUT_FILENO) < 0 ? -errno : STDOUT_FILENO; - - /* We don't reset the terminal if this is just about output */ - return open_terminal_as(tty_path(context), O_WRONLY, STDOUT_FILENO); - - case EXEC_OUTPUT_SYSLOG: - case EXEC_OUTPUT_SYSLOG_AND_CONSOLE: - case EXEC_OUTPUT_KMSG: - case EXEC_OUTPUT_KMSG_AND_CONSOLE: - case EXEC_OUTPUT_JOURNAL: - case EXEC_OUTPUT_JOURNAL_AND_CONSOLE: - return connect_logger_as(context, o, ident, unit_id, STDOUT_FILENO); - - case EXEC_OUTPUT_SOCKET: - assert(socket_fd >= 0); - return dup2(socket_fd, STDOUT_FILENO) < 0 ? -errno : STDOUT_FILENO; - - default: - assert_not_reached("Unknown output type"); + /* We need to open /dev/null here anew, to get the right access mode. */ + return open_null_as(O_WRONLY, fileno); } -} - -static int setup_error(const ExecContext *context, int socket_fd, const char *ident, const char *unit_id, bool apply_tty_stdin) { - ExecOutput o, e; - ExecInput i; - assert(context); - assert(ident); - - i = fixup_input(context->std_input, socket_fd, apply_tty_stdin); - o = fixup_output(context->std_output, socket_fd); - e = fixup_output(context->std_error, socket_fd); - - /* This expects the input and output are already set up */ - - /* Don't change the stderr file descriptor if we inherit all - * the way and are not on a tty */ - if (e == EXEC_OUTPUT_INHERIT && - o == EXEC_OUTPUT_INHERIT && - i == EXEC_INPUT_NULL && - !is_terminal_input(context->std_input) && - getppid () != 1) - return STDERR_FILENO; - - /* Duplicate from stdout if possible */ - if (e == o || e == EXEC_OUTPUT_INHERIT) - return dup2(STDOUT_FILENO, STDERR_FILENO) < 0 ? -errno : STDERR_FILENO; - - switch (e) { + switch (o) { case EXEC_OUTPUT_NULL: - return open_null_as(O_WRONLY, STDERR_FILENO); + return open_null_as(O_WRONLY, fileno); case EXEC_OUTPUT_TTY: if (is_terminal_input(i)) - return dup2(STDIN_FILENO, STDERR_FILENO) < 0 ? -errno : STDERR_FILENO; + return dup2(STDIN_FILENO, fileno) < 0 ? -errno : fileno; /* We don't reset the terminal if this is just about output */ - return open_terminal_as(tty_path(context), O_WRONLY, STDERR_FILENO); + return open_terminal_as(tty_path(context), O_WRONLY, fileno); case EXEC_OUTPUT_SYSLOG: case EXEC_OUTPUT_SYSLOG_AND_CONSOLE: @@ -420,11 +407,21 @@ static int setup_error(const ExecContext *context, int socket_fd, const char *id case EXEC_OUTPUT_KMSG_AND_CONSOLE: case EXEC_OUTPUT_JOURNAL: case EXEC_OUTPUT_JOURNAL_AND_CONSOLE: - return connect_logger_as(context, e, ident, unit_id, STDERR_FILENO); + r = connect_logger_as(context, o, ident, unit_id, fileno); + if (r < 0) { + log_struct_unit(LOG_CRIT, unit_id, + "MESSAGE=Failed to connect std%s of %s to the journal socket: %s", + fileno == STDOUT_FILENO ? "out" : "err", + unit_id, strerror(-r), + "ERRNO=%d", -r, + NULL); + r = open_null_as(O_WRONLY, fileno); + } + return r; case EXEC_OUTPUT_SOCKET: assert(socket_fd >= 0); - return dup2(socket_fd, STDERR_FILENO) < 0 ? -errno : STDERR_FILENO; + return dup2(socket_fd, fileno) < 0 ? -errno : fileno; default: assert_not_reached("Unknown error type"); @@ -957,7 +954,7 @@ static int apply_seccomp(uint32_t *syscall_filter) { for (i = 0, n = 0; i < syscall_max(); i++) if (syscall_filter[i >> 4] & (1 << (i & 31))) { struct sock_filter item[] = { - BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, i, 0, 1), + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, INDEX_TO_SYSCALL(i), 0, 1), BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW) }; @@ -983,7 +980,7 @@ static int apply_seccomp(uint32_t *syscall_filter) { int exec_spawn(ExecCommand *command, char **argv, - const ExecContext *context, + ExecContext *context, int fds[], unsigned n_fds, char **environment, bool apply_permissions, @@ -1024,8 +1021,8 @@ int exec_spawn(ExecCommand *command, r = exec_context_load_environment(context, &files_env); if (r < 0) { - log_struct(LOG_ERR, - "UNIT=%s", unit_id, + log_struct_unit(LOG_ERR, + unit_id, "MESSAGE=Failed to load environment files: %s", strerror(-r), "ERRNO=%d", -r, NULL); @@ -1039,8 +1036,8 @@ int exec_spawn(ExecCommand *command, if (!line) return log_oom(); - log_struct(LOG_DEBUG, - "UNIT=%s", unit_id, + log_struct_unit(LOG_DEBUG, + unit_id, "MESSAGE=About to execute %s", line, NULL); free(line); @@ -1051,6 +1048,12 @@ int exec_spawn(ExecCommand *command, cgroup_attribute_apply_list(cgroup_attributes, cgroup_bondings); + if (context->private_tmp && !context->tmp_dir && !context->var_tmp_dir) { + r = setup_tmpdirs(&context->tmp_dir, &context->var_tmp_dir); + if (r < 0) + return r; + } + pid = fork(); if (pid < 0) return -errno; @@ -1165,13 +1168,13 @@ int exec_spawn(ExecCommand *command, goto fail_child; } - err = setup_output(context, socket_fd, path_get_file_name(command->path), unit_id, apply_tty_stdin); + err = setup_output(context, STDOUT_FILENO, socket_fd, path_get_file_name(command->path), unit_id, apply_tty_stdin); if (err < 0) { r = EXIT_STDOUT; goto fail_child; } - err = setup_error(context, socket_fd, path_get_file_name(command->path), unit_id, apply_tty_stdin); + err = setup_output(context, STDERR_FILENO, socket_fd, path_get_file_name(command->path), unit_id, apply_tty_stdin); if (err < 0) { r = EXIT_STDERR; goto fail_child; @@ -1317,6 +1320,8 @@ int exec_spawn(ExecCommand *command, err = setup_namespace(context->read_write_dirs, context->read_only_dirs, context->inaccessible_dirs, + context->tmp_dir, + context->var_tmp_dir, context->private_tmp, context->mount_flags); if (err < 0) { @@ -1512,8 +1517,8 @@ int exec_spawn(ExecCommand *command, _exit(r); } - log_struct(LOG_DEBUG, - "UNIT=%s", unit_id, + log_struct_unit(LOG_DEBUG, + unit_id, "MESSAGE=Forked %s as %lu", command->path, (unsigned long) pid, NULL); @@ -1545,7 +1550,23 @@ void exec_context_init(ExecContext *c) { c->timer_slack_nsec = (nsec_t) -1; } -void exec_context_done(ExecContext *c) { +void exec_context_tmp_dirs_done(ExecContext *c) { + assert(c); + + if (c->tmp_dir) { + rm_rf_dangerous(c->tmp_dir, false, true, false); + free(c->tmp_dir); + c->tmp_dir = NULL; + } + + if (c->var_tmp_dir) { + rm_rf_dangerous(c->var_tmp_dir, false, true, false); + free(c->var_tmp_dir); + c->var_tmp_dir = NULL; + } +} + +void exec_context_done(ExecContext *c, bool reloading_or_reexecuting) { unsigned l; assert(c); @@ -1609,6 +1630,9 @@ void exec_context_done(ExecContext *c) { free(c->syscall_filter); c->syscall_filter = NULL; + + if (!reloading_or_reexecuting) + exec_context_tmp_dirs_done(c); } void exec_command_done(ExecCommand *c) { @@ -1733,6 +1757,37 @@ int exec_context_load_environment(const ExecContext *c, char ***l) { return 0; } +static bool tty_may_match_dev_console(const char *tty) { + char *active = NULL, *console; + bool b; + + if (startswith(tty, "/dev/")) + tty += 5; + + /* trivial identity? */ + if (streq(tty, "console")) + return true; + + console = resolve_dev_console(&active); + /* if we could not resolve, assume it may */ + if (!console) + return true; + + /* "tty0" means the active VC, so it may be the same sometimes */ + b = streq(console, tty) || (streq(console, "tty0") && tty_is_vc(tty)); + free(active); + + return b; +} + +bool exec_context_may_touch_console(ExecContext *ec) { + return (ec->tty_reset || ec->tty_vhangup || ec->tty_vt_disallocate || + is_terminal_input(ec->std_input) || + is_terminal_output(ec->std_output) || + is_terminal_output(ec->std_error)) && + tty_may_match_dev_console(tty_path(ec)); +} + static void strv_fprintf(FILE *f, char **l) { char **g; @@ -1827,7 +1882,7 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { prefix, c->cpu_sched_priority, prefix, yes_no(c->cpu_sched_reset_on_fork)); free(policy_str); - } + } if (c->cpuset) { fprintf(f, "%sCPUAffinity:", prefix);