X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fcore%2Fexecute.c;h=bc876a32920270febcd25a4c66c0cef3e9f8d2ef;hb=8e70580bb07ae46dc0b0bf377de6333540668acc;hp=b878c331d58b6c642726b2e0effbc89098baefde;hpb=47c1d80d844689c81faf2eede95803c1ed6eb4af;p=elogind.git diff --git a/src/core/execute.c b/src/core/execute.c index b878c331d..bc876a329 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -40,6 +40,7 @@ #include #include #include +#include #ifdef HAVE_PAM #include @@ -165,6 +166,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; @@ -224,7 +245,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; @@ -320,7 +341,7 @@ 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; @@ -331,97 +352,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; + + /* Duplicate from stdout if possible */ + if (e == o || e == EXEC_OUTPUT_INHERIT) + return dup2(STDOUT_FILENO, fileno) < 0 ? -errno : fileno; - case EXEC_OUTPUT_INHERIT: + 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 */ - - 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; + return 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: - r = connect_logger_as(context, o, ident, unit_id, STDOUT_FILENO); - if (r < 0) { - log_error("Failed to connect stdout of %s to the journal socket: %s", unit_id, strerror(-r)); - r = open_null_as(O_WRONLY, STDOUT_FILENO); - } - return r; - - 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; - int r; - - 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: @@ -429,16 +408,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: - r = connect_logger_as(context, e, ident, unit_id, STDERR_FILENO); + r = connect_logger_as(context, o, ident, unit_id, fileno); if (r < 0) { - log_error("Failed to connect stderr of %s to the journal socket: %s", unit_id, strerror(-r)); - r = open_null_as(O_WRONLY, STDERR_FILENO); + 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"); @@ -997,7 +981,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, @@ -1065,6 +1049,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; @@ -1179,13 +1169,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; @@ -1331,6 +1321,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) { @@ -1559,7 +1551,26 @@ 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) { + char* dirs[] = {c->tmp_dir ? c->tmp_dir : c->var_tmp_dir, + c->tmp_dir ? c->var_tmp_dir : NULL, + NULL}; + char **dirp; + + for(dirp = dirs; *dirp; dirp++) { + char *dir; + rm_rf_dangerous(*dirp, false, true, false); + + dir = dirname(*dirp); + rmdir(dir); + + free(*dirp); + } + + c->tmp_dir = c->var_tmp_dir = NULL; +} + +void exec_context_done(ExecContext *c, bool reloading_or_reexecuting) { unsigned l; assert(c); @@ -1623,6 +1634,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) { @@ -1747,6 +1761,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;