execute.c revision cd972d6911b0e1403e0a11408be732fc3a513f2b
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen This file is part of systemd.
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen Copyright 2010 Lennart Poettering
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen systemd is free software; you can redistribute it and/or modify it
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen under the terms of the GNU Lesser General Public License as published by
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen the Free Software Foundation; either version 2.1 of the License, or
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen (at your option) any later version.
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen systemd is distributed in the hope that it will be useful, but
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen WITHOUT ANY WARRANTY; without even the implied warranty of
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen Lesser General Public License for more details.
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen You should have received a copy of the GNU Lesser General Public License
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen along with systemd; If not, see <http://www.gnu.org/licenses/>.
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen/* This assumes there is a 'tty' group */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic int shift_fds(int fds[], unsigned n_fds) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* Modifies the fds array! (sorts it) */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* Already at right index? */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* Hmm, the fd we wanted isn't free? Then
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen * let's remember that and try again from here */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic int flags_fds(const int fds[], unsigned n_fds, bool nonblock) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* Drops/Sets O_NONBLOCK and FD_CLOEXEC from the file flags */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen for (i = 0; i < n_fds; i++) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* We unconditionally drop FD_CLOEXEC from the fds,
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen * since after all we want to pass these fds to our
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen * children */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_pure_ static const char *tty_path(const ExecContext *context) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic void exec_context_tty_reset(const ExecContext *context) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (context->tty_vt_disallocate && context->tty_path)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic int connect_journal_socket(int fd, uid_t uid, gid_t gid) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path));
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* If we fail to restore the uid or gid, things will likely
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen fail later on. This should only happen if an LSM interferes. */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic int connect_logger_as(const ExecContext *context, ExecOutput output, const char *ident, const char *unit_id, int nfd, uid_t uid, gid_t gid) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen context->syslog_identifier ? context->syslog_identifier : ident,
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen output == EXEC_OUTPUT_SYSLOG || output == EXEC_OUTPUT_SYSLOG_AND_CONSOLE,
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen output == EXEC_OUTPUT_KMSG || output == EXEC_OUTPUT_KMSG_AND_CONSOLE,
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic int open_terminal_as(const char *path, mode_t mode, int nfd) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if ((fd = open_terminal(path, mode | O_NOCTTY)) < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic int fixup_input(ExecInput std_input, int socket_fd, bool apply_tty_stdin) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (is_terminal_input(std_input) && !apply_tty_stdin)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (std_input == EXEC_INPUT_SOCKET && socket_fd < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic int fixup_output(ExecOutput std_output, int socket_fd) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (std_output == EXEC_OUTPUT_SOCKET && socket_fd < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic int setup_input(const ExecContext *context, int socket_fd, bool apply_tty_stdin) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen i = fixup_input(context->std_input, socket_fd, apply_tty_stdin);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = dup2(fd, STDIN_FILENO) < 0 ? -errno : STDIN_FILENO;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return dup2(socket_fd, STDIN_FILENO) < 0 ? -errno : STDIN_FILENO;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic int setup_output(const ExecContext *context, int fileno, int socket_fd, const char *ident, const char *unit_id, bool apply_tty_stdin, uid_t uid, gid_t gid) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen i = fixup_input(context->std_input, socket_fd, apply_tty_stdin);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen o = fixup_output(context->std_output, socket_fd);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen e = fixup_output(context->std_error, socket_fd);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* This expects the input and output are already set up */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* Don't change the stderr file descriptor if we inherit all
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen * the way and are not on a tty */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* Duplicate from stdout if possible */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (e == o || e == EXEC_OUTPUT_INHERIT)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return dup2(STDOUT_FILENO, fileno) < 0 ? -errno : fileno;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else if (o == EXEC_OUTPUT_INHERIT) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* If input got downgraded, inherit the original value */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (i == EXEC_INPUT_NULL && is_terminal_input(context->std_input))
4df4fd1127df4b70f78d952a37a51a8c69e3243fTom Gundersen return open_terminal_as(tty_path(context), O_WRONLY, fileno);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* If the input is connected to anything that's not a /dev/null, inherit that... */
de9b34b6d4250056ae2c483cf22844880504bcccTom Gundersen return dup2(STDIN_FILENO, fileno) < 0 ? -errno : fileno;
de9b34b6d4250056ae2c483cf22844880504bcccTom Gundersen /* If we are not started from PID 1 we just inherit STDOUT from our parent process. */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* We need to open /dev/null here anew, to get the right access mode. */
de9b34b6d4250056ae2c483cf22844880504bcccTom Gundersen return dup2(STDIN_FILENO, fileno) < 0 ? -errno : fileno;
4df4fd1127df4b70f78d952a37a51a8c69e3243fTom Gundersen /* We don't reset the terminal if this is just about output */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return open_terminal_as(tty_path(context), O_WRONLY, fileno);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = connect_logger_as(context, o, ident, unit_id, fileno, uid, gid);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen LOG_MESSAGE("Failed to connect %s of %s to the journal socket: %s",
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen fileno == STDOUT_FILENO ? "stdout" : "stderr",
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return dup2(socket_fd, fileno) < 0 ? -errno : fileno;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* This might fail. What matters are the results. */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (st.st_uid != uid || (st.st_mode & 0777) != TTY_MODE)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic int setup_confirm_stdio(int *_saved_stdin,
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int fd = -1, saved_stdin, saved_stdout = -1, r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen saved_stdin = fcntl(STDIN_FILENO, F_DUPFD, 3);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen saved_stdout = fcntl(STDOUT_FILENO, F_DUPFD, 3);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_printf_(1, 2) static int write_confirm_message(const char *format, ...) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic int restore_confirm_stdio(int *saved_stdin,
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic int ask_for_confirmation(char *response, char **argv) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = setup_confirm_stdio(&saved_stdin, &saved_stdout);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = ask_char(response, "yns", "Execute %s? [Yes, No, Skip] ", line);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen restore_confirm_stdio(&saved_stdin, &saved_stdout);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic int enforce_groups(const ExecContext *context, const char *username, gid_t gid) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* Lookup and set GID and supplementary group list. Here too
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen * we avoid NSS lookups for gid=0. */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* First step, initialize groups from /etc/groups */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* Second step, set our gids */
aa20f49a1c5816e6e7e97f2e2ba209be47f3c0a3Tom Gundersen /* Final step, initialize any manually set supplementary groups */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_se((ngroups_max = (int) sysconf(_SC_NGROUPS_MAX)) > 0);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen STRV_FOREACH(i, context->supplementary_groups) {
ccc1002a1c510b7d4631833eaf60225f028f2280Tom Gundersen const char *g;
d854ba50a82f28b776c670d27156f0e9881fde8aMartin Pitt if (r < 0) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic int enforce_user(const ExecContext *context, uid_t uid) {
aa20f49a1c5816e6e7e97f2e2ba209be47f3c0a3Tom Gundersen /* Sets (but doesn't lookup) the uid and make sure we keep the
aa20f49a1c5816e6e7e97f2e2ba209be47f3c0a3Tom Gundersen * capabilities while doing so. */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen CAP_SETUID, /* Necessary so that we can run setresuid() below */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen CAP_SETPCAP /* Necessary so that we can set PR_SET_SECUREBITS later on */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* First step: If we need to keep capabilities but
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen * drop privileges we need to make sure we keep our
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen * caps, while we drop privileges. */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int sb = context->secure_bits | 1<<SECURE_KEEP_CAPS;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* Second step: set the capabilities. This will reduce
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen * the capabilities to the minimum we need. */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (cap_set_flag(d, CAP_EFFECTIVE, ELEMENTSOF(bits), bits, CAP_SET) < 0 ||
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen cap_set_flag(d, CAP_PERMITTED, ELEMENTSOF(bits), bits, CAP_SET) < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* Third step: actually set the uids */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* At this point we should have all necessary capabilities but
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen are otherwise a normal user. However, the caps might got
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen corrupted due to the setresuid() so we need clean them up
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen later. This is done outside of this call. */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* We don't support conversations */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen const char *tty,
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* We set up PAM in the parent process, then fork. The child
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen * will then stay around until killed via PR_GET_PDEATHSIG or
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen * systemd via the cgroup logic. It will then remove the PAM
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen * session again. The parent process will exec() the actual
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen * daemon. We do things this way to ensure that the main PID
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen * of the daemon is the one we initially fork()ed. */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen pam_code = pam_start(name, user, &conv, &handle);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen pam_code = pam_set_item(handle, PAM_TTY, tty);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* Block SIGTERM, so that we know that it won't get lost in
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen * the child */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* The child's job is to reset the PAM session on
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen * termination */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* This string must fit in 10 chars (i.e. the length
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen * of "/sbin/init"), to look pretty in /bin/ps */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* Make sure we don't keep open the passed fds in this
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen child. We assume that otherwise only those fds are
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen open here that have been opened by PAM. */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* Drop privileges - we don't need any to pam_close_session
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen * and this will make PR_SET_PDEATHSIG work in most cases.
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen * If this fails, ignore the error - but expect sd-pam threads
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen * to fail to exit normally */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen log_error_errno(r, "Error: Failed to setresuid() in sd-pam: %m");
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* Wait until our parent died. This will only work if
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen * the above setresuid() succeeds, otherwise the kernel
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen * will not allow unprivileged parents kill their privileged
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen * children this way. We rely on the control groups kill logic
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen * to do the rest for us. */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* Check if our parent process might already have
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* If our parent died we'll end the session */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* If the child was forked off successfully it will do all the
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen * cleanups, so forget about the handle here. */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* Unblock SIGTERM again in the parent */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (sigprocmask(SIG_SETMASK, &old_ss, NULL) < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* We close the log explicitly here, since the PAM modules
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen * might have opened it, but we don't want this fd around. */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen log_error("PAM failed: %s", pam_strerror(handle, pam_code));
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen err = -EPERM; /* PAM errors do not map to errno */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic void rename_process_from_path(const char *path) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen const char *p;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* This resulting string must fit in 10 chars (i.e. the length
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen * of "/sbin/init") to look pretty in /bin/ps */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* The end of the process name is usually more
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen * interesting, since the first bit might just be
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen * "systemd-" */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen p = p + l - 8;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic int apply_seccomp(const ExecContext *c) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen negative_action = c->syscall_errno == 0 ? SCMP_ACT_KILL : SCMP_ACT_ERRNO(c->syscall_errno);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen seccomp = seccomp_init(c->syscall_whitelist ? negative_action : SCMP_ACT_ALLOW);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = seccomp_arch_add(seccomp, PTR_TO_UINT32(id) - 1);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen action = c->syscall_whitelist ? SCMP_ACT_ALLOW : negative_action;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = seccomp_rule_add(seccomp, action, PTR_TO_INT(id) - 1, 0);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = seccomp_attr_set(seccomp, SCMP_FLTATR_CTL_NNP, 0);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic int apply_address_families(const ExecContext *c) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* If this is a whitelist, we first block the address
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen * families that are out of range and then everything
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen * that is not in the set. First, we find the lowest
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen * and highest address family in the set. */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* No entries in the valid range, block everything */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* Block everything below the first entry */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* Block everything above the last entry */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* Block everything between the first and last
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (set_contains(c->address_families, INT_TO_PTR(af)))
107f2e2526d476c6cc9b81a690391c111027d641Tom Gundersen /* If this is a blacklist, then generate one rule for
107f2e2526d476c6cc9b81a690391c111027d641Tom Gundersen * each address family that are then combined in OR
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;
static int exec_child(
char **argv,
int socket_fd,
char **files_env,
int *exit_status) {
_cleanup_strv_free_ char **our_env = NULL, **pam_env = NULL, **final_env = NULL, **final_argv = NULL;
unsigned n_dont_close = 0;
r = reset_signal_mask();
if (socket_fd >= 0)
if (n_fds > 0) {
if (runtime) {
if (setsid() < 0) {
return -errno;
char response;
if (r == -ETIMEDOUT)
write_confirm_message("Couldn't ask confirmation question, assuming positive response: %s\n", strerror(-r));
return -ECANCELED;
*exit_status = 0;
if (socket_fd >= 0)
r = setup_output(context, STDOUT_FILENO, socket_fd, basename(command->path), params->unit_id, params->apply_tty_stdin, uid, gid);
r = setup_output(context, STDERR_FILENO, socket_fd, basename(command->path), params->unit_id, params->apply_tty_stdin, uid, gid);
log_open();
log_unit_debug_errno(params->unit_id, r, "Failed to adjust OOM setting, assuming containerized execution, ignoring: %m");
log_close();
return -errno;
return -errno;
r = sched_setscheduler(0,
SCHED_RESET_ON_FORK : 0),
¶m);
return -errno;
return -errno;
return -errno;
return -errno;
return -errno;
#ifdef ENABLE_KDBUS
char **rt;
_cleanup_free_ char *p;
return -ENOMEM;
#ifdef HAVE_PAM
r = setup_namespace(
tmp,
var,
log_open();
log_unit_debug_errno(params->unit_id, r, "Failed to set up namespace, assuming containerized execution, ignoring: %m");
log_close();
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) {
r = mac_selinux_get_child_mls_label(socket_fd, command->path, context->selinux_context, &mac_selinux_context_net);
for (i = 0; i < _RLIMIT_MAX; i++) {
return -errno;
#ifdef HAVE_SMACK
return -errno;
return -errno;
return -errno;
#ifdef HAVE_SECCOMP
#ifdef HAVE_SELINUX
if (mac_selinux_use()) {
if (exec_context) {
#ifdef HAVE_APPARMOR
return -errno;
NULL);
if (!final_env) {
return -ENOMEM;
if (!final_argv) {
return -ENOMEM;
if (line) {
log_open();
NULL);
log_close();
return -errno;
int socket_fd, r;
char **argv;
return -EINVAL;
if (!line)
return log_oom();
NULL);
if (pid < 0)
if (pid == 0) {
int exit_status;
argv,
&exit_status);
log_open();
LOG_ERRNO(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(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]);
typedef struct InvalidEnvInfo {
const char *unit_id;
const char *path;
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)