execute.c revision f1acf85a36f4c32d69511fe1bfa12f66e28fa80d
87d2c1ff6a7375f03476767e6f59454bcc5cd04bLennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
87d2c1ff6a7375f03476767e6f59454bcc5cd04bLennart Poettering This file is part of systemd.
87d2c1ff6a7375f03476767e6f59454bcc5cd04bLennart Poettering Copyright 2010 Lennart Poettering
87d2c1ff6a7375f03476767e6f59454bcc5cd04bLennart Poettering systemd is free software; you can redistribute it and/or modify it
87d2c1ff6a7375f03476767e6f59454bcc5cd04bLennart Poettering under the terms of the GNU Lesser General Public License as published by
87d2c1ff6a7375f03476767e6f59454bcc5cd04bLennart Poettering the Free Software Foundation; either version 2.1 of the License, or
87d2c1ff6a7375f03476767e6f59454bcc5cd04bLennart Poettering (at your option) any later version.
87d2c1ff6a7375f03476767e6f59454bcc5cd04bLennart Poettering systemd is distributed in the hope that it will be useful, but
87d2c1ff6a7375f03476767e6f59454bcc5cd04bLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
87d2c1ff6a7375f03476767e6f59454bcc5cd04bLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
87d2c1ff6a7375f03476767e6f59454bcc5cd04bLennart Poettering Lesser General Public License for more details.
87d2c1ff6a7375f03476767e6f59454bcc5cd04bLennart Poettering You should have received a copy of the GNU Lesser General Public License
87d2c1ff6a7375f03476767e6f59454bcc5cd04bLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
if (n_fds <= 0)
start = 0;
int nfd;
return -errno;
restart_from = i;
if (restart_from < 0)
if (n_fds <= 0)
for (i = 0; i < n_fds; i++) {
o == EXEC_OUTPUT_TTY ||
o == EXEC_OUTPUT_SYSLOG_AND_CONSOLE ||
o == EXEC_OUTPUT_KMSG_AND_CONSOLE ||
int fd, r;
if (fd < 0)
return -errno;
r = nfd;
static int connect_logger_as(const ExecContext *context, ExecOutput output, const char *ident, const char *unit_id, int nfd) {
int fd, r;
assert(ident);
if (fd < 0)
return -errno;
return -errno;
return -errno;
r = nfd;
int fd, r;
return fd;
r = nfd;
i == EXEC_INPUT_TTY ||
i == EXEC_INPUT_TTY_FORCE ||
i == EXEC_INPUT_TTY_FAIL;
return EXEC_INPUT_NULL;
return EXEC_INPUT_NULL;
return std_input;
return EXEC_OUTPUT_INHERIT;
return std_output;
ExecInput i;
case EXEC_INPUT_NULL:
case EXEC_INPUT_TTY:
case EXEC_INPUT_TTY_FORCE:
case EXEC_INPUT_TTY_FAIL: {
int fd, r;
i == EXEC_INPUT_TTY_FAIL,
i == EXEC_INPUT_TTY_FORCE,
if (fd < 0)
return fd;
r = STDIN_FILENO;
case EXEC_INPUT_SOCKET:
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;
assert(ident);
ExecOutput e;
if (e == EXEC_OUTPUT_INHERIT &&
o == EXEC_OUTPUT_INHERIT &&
i == EXEC_INPUT_NULL &&
return fileno;
if (e == o || e == EXEC_OUTPUT_INHERIT)
} else if (o == EXEC_OUTPUT_INHERIT) {
if (i != EXEC_INPUT_NULL)
return fileno;
case EXEC_OUTPUT_NULL:
case EXEC_OUTPUT_TTY:
if (is_terminal_input(i))
case EXEC_OUTPUT_SYSLOG:
case EXEC_OUTPUT_KMSG:
case EXEC_OUTPUT_JOURNAL:
LOG_ERRNO(-r),
NULL);
case EXEC_OUTPUT_SOCKET:
return -errno;
return -EPERM;
int *_saved_stdout) {
if (saved_stdin < 0)
return -errno;
if (saved_stdout < 0) {
r = errno;
goto fail;
if (fd < 0) {
r = fd;
goto fail;
goto fail;
r = -errno;
goto fail;
r = -errno;
goto fail;
fail:
if (fd < 0)
return fd;
int *saved_stdout) {
if (*saved_stdin >= 0)
r = -errno;
if (*saved_stdout >= 0)
r = -errno;
if (!line)
return -ENOMEM;
bool keep_groups = false;
return -errno;
keep_groups = true;
return -errno;
int ngroups_max, k;
return -ENOMEM;
if (keep_groups) {
return -errno;
if (k >= ngroups_max) {
return -E2BIG;
return -errno;
if (uid != 0) {
return -errno;
return -errno;
return -errno;
if (cap_set_proc(d) < 0)
return -errno;
return -errno;
#ifdef HAVE_PAM
static int null_conv(
int num_msg,
void *appdata_ptr) {
return PAM_CONV_ERR;
static int setup_pam(
const char *name,
const char *user,
const char *tty,
char ***pam_env,
int err;
char **e = NULL;
bool close_session = false;
int flags = 0;
goto fail;
if (tty) {
goto fail;
goto fail;
goto fail;
close_session = true;
goto fail;
goto fail;
if (pam_pid < 0)
goto fail;
if (pam_pid == 0) {
int sig;
int r = EXIT_PAM;
goto child_finish;
goto child_finish;
goto child_finish;
_exit(r);
goto fail;
closelog();
*pam_env = e;
e = NULL;
fail:
if (handle) {
if (close_session)
strv_free(e);
closelog();
return err;
size_t l;
if (isempty(p)) {
l = strlen(p);
#ifdef HAVE_SECCOMP
Iterator i;
void *id;
assert(c);
if (!seccomp)
return -ENOMEM;
if (c->syscall_archs) {
if (r == -EEXIST)
goto finish;
goto finish;
goto finish;
goto finish;
Iterator i;
assert(c);
if (!seccomp)
return -ENOMEM;
goto finish;
if (c->address_families_whitelist) {
void *afp;
if (first == 0) {
r = seccomp_rule_add(
goto finish;
r = seccomp_rule_add(
goto finish;
r = seccomp_rule_add(
goto finish;
r = seccomp_rule_add(
goto finish;
void *af;
r = seccomp_rule_add(
goto finish;
goto finish;
if (idle_pipe[0] >= 0) {
static int build_environment(
const ExecContext *c,
unsigned n_fds,
const char *home,
const char *username,
const char *shell,
char ***ret) {
unsigned n_env = 0;
assert(c);
if (!our_env)
return -ENOMEM;
if (n_fds > 0) {
return -ENOMEM;
return -ENOMEM;
if (watchdog_usec > 0) {
return -ENOMEM;
return -ENOMEM;
if (home) {
return -ENOMEM;
if (username) {
return -ENOMEM;
return -ENOMEM;
if (shell) {
return -ENOMEM;
c->tty_path) {
return -ENOMEM;
char **argv,
int socket_fd,
char **files_env,
int *error) {
_cleanup_strv_free_ char **our_env = NULL, **pam_env = NULL, **final_env = NULL, **final_argv = NULL;
unsigned n_dont_close = 0;
int i, err;
if (err < 0) {
return err;
if (socket_fd >= 0)
if (n_fds > 0) {
if (runtime) {
if (err < 0) {
return err;
if (setsid() < 0) {
return -errno;
char response;
else if (err < 0)
write_confirm_message("Couldn't ask confirmation question, assuming positive response: %s\n", strerror(-err));
return -ECANCELED;
*error = 0;
if (socket_fd >= 0)
if (err < 0) {
return err;
err = setup_output(context, STDOUT_FILENO, socket_fd, basename(command->path), params->unit_id, params->apply_tty_stdin);
if (err < 0) {
return err;
err = setup_output(context, STDERR_FILENO, socket_fd, basename(command->path), params->unit_id, params->apply_tty_stdin);
if (err < 0) {
return err;
if (err < 0) {
return err;
char_array_0(t);
return -errno;
return -errno;
SCHED_RESET_ON_FORK : 0),
¶m);
if (err < 0) {
return -errno;
return -errno;
return -errno;
return -errno;
return -errno;
if (err < 0) {
return err;
if (err < 0) {
return err;
#ifdef ENABLE_KDBUS
if (err < 0) {
return err;
if (err < 0) {
return err;
if (err < 0) {
return err;
char **rt;
_cleanup_free_ char *p;
return -ENOMEM;
if (err < 0) {
return err;
if (err < 0) {
return err;
#ifdef HAVE_PAM
if (err < 0) {
return err;
if (err < 0) {
return err;
tmp,
var,
log_unit_warning_errno(params->unit_id, err, "Failed to set up file system namespace due to lack of privileges. Execution sandbox will not be in effect: %m");
else if (err < 0) {
return err;
return -errno;
return -errno;
return -ENOMEM;
if (chdir(d) < 0) {
return -errno;
#ifdef HAVE_SELINUX
if (params->apply_permissions && mac_selinux_use() && params->selinux_context_net && socket_fd >= 0) {
err = mac_selinux_get_child_mls_label(socket_fd, command->path, context->selinux_context, &mac_selinux_context_net);
if (err < 0) {
return err;
if (err >= 0)
if (err >= 0)
if (err < 0) {
return err;
for (i = 0; i < _RLIMIT_MAX; i++) {
return -errno;
if (err < 0) {
return err;
#ifdef HAVE_SMACK
if (err < 0) {
return err;
if (err < 0) {
return err;
return -errno;
return -errno;
return -errno;
#ifdef HAVE_SECCOMP
if (err < 0) {
return err;
if (err < 0) {
return err;
#ifdef HAVE_SELINUX
if (mac_selinux_use()) {
if (exec_context) {
if (err < 0) {
return err;
#ifdef HAVE_APPARMOR
return -errno;
if (err < 0) {
return err;
NULL);
if (!final_env) {
return -ENOMEM;
if (!final_argv) {
return -ENOMEM;
if (line) {
log_open();
NULL);
log_close();
return -errno;
int socket_fd;
int err;
return -EINVAL;
if (err < 0) {
NULL);
return err;
if (!line)
return log_oom();
NULL);
if (pid < 0)
return -errno;
if (pid == 0) {
argv,
log_open();
NULL);
log_close();
_exit(r);
NULL);
assert(c);
c->syslog_level_prefix = true;
c->ignore_sigpipe = true;
assert(c);
if (c->capabilities) {
if (c->cpuset)
assert(c);
if (!runtime_prefix)
_cleanup_free_ char *p;
return -ENOMEM;
rm_rf_dangerous(p, false, true, false);
assert(c);
exec_command_done(c+i);
ExecCommand *i;
free(i);
return NULL;
c[i] = exec_command_free_list(c[i]);
char **i, **r = NULL;
assert(c);
assert(l);
char *fn;
bool ignore = false;
int count, n;
fn = *i;
ignore = true;
fn ++;
if (ignore)
strv_free(r);
return -EINVAL;
errno = 0;
if (ignore)
strv_free(r);
if (count == 0) {
if (ignore)
strv_free(r);
return -EINVAL;
for (n = 0; n < count; n++) {
if (ignore)
strv_free(r);
if (r == NULL)
strv_free(r);
strv_free(p);
return -ENOMEM;
char *console;
if (!console)
assert(f);
STRV_FOREACH(g, l)
assert(c);
assert(f);
fprintf(f,
if (c->nice_set)
fprintf(f,
if (c->oom_score_adjust_set)
fprintf(f,
for (i = 0; i < RLIM_NLIMITS; i++)
if (c->rlimit[i])
if (c->ioprio_set) {
fprintf(f,
if (c->cpu_sched_set) {
fprintf(f,
if (c->cpuset) {
for (i = 0; i < c->cpuset_ncpus; i++)
fprintf(f,
if (c->tty_path)
fprintf(f,
fprintf(f,
if (c->capabilities) {
_cleanup_cap_free_charp_ char *t;
if (c->secure_bits)
if (c->capability_bounding_set_drop) {
for (l = 0; l <= cap_last_cap(); l++)
if (c->user)
if (c->group)
if (c->pam_name)
if (c->utmp_id)
fprintf(f,
if (c->selinux_context)
fprintf(f,
fprintf(f,
if (c->syscall_filter) {
#ifdef HAVE_SECCOMP
Iterator j;
void *id;
bool first = true;
fprintf(f,
prefix);
if (!c->syscall_whitelist)
#ifdef HAVE_SECCOMP
if (first)
first = false;
if (c->syscall_archs) {
#ifdef HAVE_SECCOMP
Iterator j;
void *id;
fprintf(f,
prefix);
#ifdef HAVE_SECCOMP
if (c->syscall_errno != 0)
fprintf(f,
if (c->apparmor_profile)
fprintf(f,
assert(c);
if (!c->user)
assert(s);
zero(*s);
assert(s);
zero(*s);
if (context) {
assert(s);
assert(f);
if (s->pid <= 0)
fprintf(f,
fprintf(f,
fprintf(f,
size_t k;
bool first = true;
if (!(n = new(char, k)))
return NULL;
if (!first)
first = false;
p = stpcpy(p, *a);
p = stpcpy(p, *a);
const char *prefix2;
assert(c);
assert(f);
fprintf(f,
assert(f);
assert(l);
assert(e);
assert(c);
return -ENOMEM;
strv_free(l);
return -ENOMEM;
c->path = p;
c->argv = l;
assert(c);
return -ENOMEM;
if (*rt)
if (!*rt)
return -ENOMEM;
assert(c);
if (*rt)
return -errno;
assert(r);
r->n_ref++;
return NULL;
r->n_ref--;
if (r->n_ref <= 0) {
free(r);
return NULL;
assert(u);
assert(f);
if (!rt)
int copy;
if (copy < 0)
return copy;
int copy;
if (copy < 0)
return copy;
int exec_runtime_deserialize_item(ExecRuntime **rt, Unit *u, const char *key, const char *value, FDSet *fds) {
char *copy;
if (!copy)
return log_oom();
char *copy;
if (!copy)
return log_oom();
int fd;
int fd;
static void *remove_tmpdir_thread(void *p) {
return NULL;
if (!rt)