execute.c revision f146f5e159445c4fc7e89fe19ee2b8d72fc19ed7
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering This file is part of systemd.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Copyright 2010 Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering systemd is free software; you can redistribute it and/or modify it
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering under the terms of the GNU Lesser General Public License as published by
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering (at your option) any later version.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering systemd is distributed in the hope that it will be useful, but
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Lesser General Public License for more details.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering You should have received a copy of the GNU Lesser General Public License
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering#define IDLE_TIMEOUT_USEC (5*USEC_PER_SEC)
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering#define IDLE_TIMEOUT2_USEC (1*USEC_PER_SEC)
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering/* This assumes there is a 'tty' group */
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poetteringstatic int shift_fds(int fds[], unsigned n_fds) {
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering /* Modifies the fds array! (sorts it) */
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering /* Already at right index? */
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering if ((nfd = fcntl(fds[i], F_DUPFD, i+3)) < 0)
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering /* Hmm, the fd we wanted isn't free? Then
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering * let's remember that and try again from here*/
cb81cd8073392936882643af0129934bf67e96c4Lennart Poetteringstatic int flags_fds(const int fds[], unsigned n_fds, bool nonblock) {
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering /* Drops/Sets O_NONBLOCK and FD_CLOEXEC from the file flags */
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering for (i = 0; i < n_fds; i++) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if ((r = fd_nonblock(fds[i], nonblock)) < 0)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering /* We unconditionally drop FD_CLOEXEC from the fds,
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering * since after all we want to pass these fds to our
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering_pure_ static const char *tty_path(const ExecContext *context) {
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poetteringstatic void exec_context_tty_reset(const ExecContext *context) {
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering if (context->tty_vt_disallocate && context->tty_path)
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poetteringstatic bool is_terminal_output(ExecOutput o) {
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poetteringstatic int open_null_as(int flags, int nfd) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poetteringstatic int connect_logger_as(const ExecContext *context, ExecOutput output, const char *ident, const char *unit_id, int nfd) {
06820eafdbc3dd89cb1f7563564c7d91426709caLennart Poettering .un.sun_path = "/run/systemd/journal/stdout",
4e724d9c5ab76c3f8327945317463ef706011082Lennart Poettering r = connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path));
de0671ee7fe465e108f62dcbbbe9366f81dd9e9aZbigniew Jędrzejewski-Szmek if (shutdown(fd, SHUT_RD) < 0) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering context->syslog_identifier ? context->syslog_identifier : ident,
df2d202e6ed4001a21c6512c244acad5d4706c87Lennart Poettering output == EXEC_OUTPUT_SYSLOG || output == EXEC_OUTPUT_SYSLOG_AND_CONSOLE,
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering output == EXEC_OUTPUT_KMSG || output == EXEC_OUTPUT_KMSG_AND_CONSOLE,
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poetteringstatic int open_terminal_as(const char *path, mode_t mode, int nfd) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if ((fd = open_terminal(path, mode | O_NOCTTY)) < 0)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poetteringstatic bool is_terminal_input(ExecInput i) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poetteringstatic int fixup_input(ExecInput std_input, int socket_fd, bool apply_tty_stdin) {
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering if (is_terminal_input(std_input) && !apply_tty_stdin)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (std_input == EXEC_INPUT_SOCKET && socket_fd < 0)
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poetteringstatic int fixup_output(ExecOutput std_output, int socket_fd) {
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering if (std_output == EXEC_OUTPUT_SOCKET && socket_fd < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic int setup_input(const ExecContext *context, int socket_fd, bool apply_tty_stdin) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering i = fixup_input(context->std_input, socket_fd, apply_tty_stdin);
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering return open_null_as(O_RDONLY, STDIN_FILENO);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = dup2(fd, STDIN_FILENO) < 0 ? -errno : STDIN_FILENO;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return dup2(socket_fd, STDIN_FILENO) < 0 ? -errno : STDIN_FILENO;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert_not_reached("Unknown input type");
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poetteringstatic int setup_output(const ExecContext *context, int fileno, int socket_fd, const char *ident, const char *unit_id, bool apply_tty_stdin) {
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering i = fixup_input(context->std_input, socket_fd, apply_tty_stdin);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering o = fixup_output(context->std_output, socket_fd);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering e = fixup_output(context->std_error, socket_fd);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* This expects the input and output are already set up */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* Don't change the stderr file descriptor if we inherit all
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * the way and are not on a tty */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering !is_terminal_input(context->std_input) &&
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* Duplicate from stdout if possible */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (e == o || e == EXEC_OUTPUT_INHERIT)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return dup2(STDOUT_FILENO, fileno) < 0 ? -errno : fileno;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering } else if (o == EXEC_OUTPUT_INHERIT) {
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering /* If input got downgraded, inherit the original value */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (i == EXEC_INPUT_NULL && is_terminal_input(context->std_input))
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return open_terminal_as(tty_path(context), O_WRONLY, fileno);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* If the input is connected to anything that's not a /dev/null, inherit that... */
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering return dup2(STDIN_FILENO, fileno) < 0 ? -errno : fileno;
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering /* If we are not started from PID 1 we just inherit STDOUT from our parent process. */
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering /* We need to open /dev/null here anew, to get the right access mode. */
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering return dup2(STDIN_FILENO, fileno) < 0 ? -errno : fileno;
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering /* We don't reset the terminal if this is just about output */
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering return open_terminal_as(tty_path(context), O_WRONLY, fileno);
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering r = connect_logger_as(context, o, ident, unit_id, fileno);
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering "MESSAGE=Failed to connect std%s of %s to the journal socket: %s",
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering "ERRNO=%d", -r,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return dup2(socket_fd, fileno) < 0 ? -errno : fileno;
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering assert_not_reached("Unknown error type");
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poetteringstatic int chown_terminal(int fd, uid_t uid) {
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering /* This might fail. What matters are the results. */
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering if (st.st_uid != uid || (st.st_mode & 0777) != TTY_MODE)
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poetteringstatic int setup_confirm_stdio(int *_saved_stdin,
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering int fd = -1, saved_stdin, saved_stdout = -1, r;
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering saved_stdin = fcntl(STDIN_FILENO, F_DUPFD, 3);
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering saved_stdout = fcntl(STDOUT_FILENO, F_DUPFD, 3);
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering_printf_(1, 2) static int write_confirm_message(const char *format, ...) {
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poetteringstatic int restore_confirm_stdio(int *saved_stdin,
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering if (dup2(*saved_stdin, STDIN_FILENO) < 0)
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering if (dup2(*saved_stdout, STDOUT_FILENO) < 0)
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poetteringstatic int ask_for_confirmation(char *response, char **argv) {
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering int saved_stdout = -1, saved_stdin = -1, r;
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering r = setup_confirm_stdio(&saved_stdin, &saved_stdout);
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering r = ask(response, "yns", "Execute %s? [Yes, No, Skip] ", line);
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering restore_confirm_stdio(&saved_stdin, &saved_stdout);
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poetteringstatic int enforce_groups(const ExecContext *context, const char *username, gid_t gid) {
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering /* Lookup and set GID and supplementary group list. Here too
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering * we avoid NSS lookups for gid=0. */
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering /* First step, initialize groups from /etc/groups */
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering /* Second step, set our gids */
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering /* Final step, initialize any manually set supplementary groups */
40205d706e1210763ff4c98a317556375bd04bcdLennart Poettering assert_se((ngroups_max = (int) sysconf(_SC_NGROUPS_MAX)) > 0);
40205d706e1210763ff4c98a317556375bd04bcdLennart Poettering if ((k = getgroups(ngroups_max, gids)) < 0) {
40205d706e1210763ff4c98a317556375bd04bcdLennart Poettering STRV_FOREACH(i, context->supplementary_groups) {
40205d706e1210763ff4c98a317556375bd04bcdLennart Poettering const char *g;
49af9e1368571f4e423cde0fd45ee284451434d1Lennart Poetteringstatic int enforce_user(const ExecContext *context, uid_t uid) {
49af9e1368571f4e423cde0fd45ee284451434d1Lennart Poettering /* Sets (but doesn't lookup) the uid and make sure we keep the
49af9e1368571f4e423cde0fd45ee284451434d1Lennart Poettering * capabilities while doing so. */
49af9e1368571f4e423cde0fd45ee284451434d1Lennart Poettering CAP_SETUID, /* Necessary so that we can run setresuid() below */
49af9e1368571f4e423cde0fd45ee284451434d1Lennart Poettering CAP_SETPCAP /* Necessary so that we can set PR_SET_SECUREBITS later on */
49af9e1368571f4e423cde0fd45ee284451434d1Lennart Poettering /* First step: If we need to keep capabilities but
49af9e1368571f4e423cde0fd45ee284451434d1Lennart Poettering * drop privileges we need to make sure we keep our
49af9e1368571f4e423cde0fd45ee284451434d1Lennart Poettering * caps, while we drop privileges. */
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering int sb = context->secure_bits | 1<<SECURE_KEEP_CAPS;
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering /* Second step: set the capabilities. This will reduce
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering * the capabilities to the minimum we need. */
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering if (!(d = cap_dup(context->capabilities)))
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering if (cap_set_flag(d, CAP_EFFECTIVE, ELEMENTSOF(bits), bits, CAP_SET) < 0 ||
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering cap_set_flag(d, CAP_PERMITTED, ELEMENTSOF(bits), bits, CAP_SET) < 0) {
0370612e0522191f929e3feb7d4937fff3d421e2Lennart Poettering /* Third step: actually set the uids */
0370612e0522191f929e3feb7d4937fff3d421e2Lennart Poettering /* At this point we should have all necessary capabilities but
0370612e0522191f929e3feb7d4937fff3d421e2Lennart Poettering are otherwise a normal user. However, the caps might got
0370612e0522191f929e3feb7d4937fff3d421e2Lennart Poettering corrupted due to the setresuid() so we need clean them up
0370612e0522191f929e3feb7d4937fff3d421e2Lennart Poettering later. This is done outside of this call. */
086821244b5113f00a0ef993b78dc56aae2a8f6cLennart Poettering /* We don't support conversations */
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering /* We set up PAM in the parent process, then fork. The child
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering * will then stay around until killed via PR_GET_PDEATHSIG or
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering * systemd via the cgroup logic. It will then remove the PAM
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering * session again. The parent process will exec() the actual
70244d1d25eb80b57e160ea004d0e6bf793d4cafLennart Poettering * daemon. We do things this way to ensure that the main PID
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering * of the daemon is the one we initially fork()ed. */
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering if (log_get_max_level() < LOG_PRI(LOG_DEBUG))
1ddb263d21099ae42195c2bc382bdf72a7f24f82Lennart Poettering pam_code = pam_start(name, user, &conv, &handle);
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering pam_code = pam_set_item(handle, PAM_TTY, tty);
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering pam_code = pam_open_session(handle, flags);
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering /* Block SIGTERM, so that we know that it won't get lost in
1ddb263d21099ae42195c2bc382bdf72a7f24f82Lennart Poettering * the child */
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering sigprocmask(SIG_BLOCK, &ss, &old_ss) < 0)
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering /* The child's job is to reset the PAM session on
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering * termination */
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering /* This string must fit in 10 chars (i.e. the length
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering * of "/sbin/init"), to look pretty in /bin/ps */
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering /* Make sure we don't keep open the passed fds in this
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering child. We assume that otherwise only those fds are
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering open here that have been opened by PAM. */
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering /* Drop privileges - we don't need any to pam_close_session
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering * and this will make PR_SET_PDEATHSIG work in most cases.
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering * If this fails, ignore the error - but expect sd-pam threads
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering * to fail to exit normally */
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering log_error("Error: Failed to setresuid() in sd-pam: %s", strerror(-r));
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering /* Wait until our parent died. This will only work if
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering * the above setresuid() succeeds, otherwise the kernel
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering * will not allow unprivileged parents kill their privileged
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering * children this way. We rely on the control groups kill logic
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering * to do the rest for us. */
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
4cee5eede280b7fd48c18a1942616c4ac896a554Lennart Poettering /* Check if our parent process might already have
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering /* If our parent died we'll end the session */
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering pam_code = pam_close_session(handle, flags);
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering /* If the child was forked off successfully it will do all the
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering * cleanups, so forget about the handle here. */
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering /* Unblock SIGTERM again in the parent */
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering if (sigprocmask(SIG_SETMASK, &old_ss, NULL) < 0)
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering /* We close the log explicitly here, since the PAM modules
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering * might have opened it, but we don't want this fd around. */
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering log_error("PAM failed: %s", pam_strerror(handle, pam_code));
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering err = -EPERM; /* PAM errors do not map to errno */
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering pam_code = pam_close_session(handle, flags);
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poetteringstatic void rename_process_from_path(const char *path) {
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering const char *p;
b3267152783d5784c45010615045d4e8ee459da2Zbigniew Jędrzejewski-Szmek /* This resulting string must fit in 10 chars (i.e. the length
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering * of "/sbin/init") to look pretty in /bin/ps */
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering /* The end of the process name is usually more
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering * interesting, since the first bit might just be
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering * "systemd-" */
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering p = p + l - 8;
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poetteringstatic int apply_seccomp(uint32_t *syscall_filter) {
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering static const struct sock_filter header[] = {
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering static const struct sock_filter footer[] = {
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering /* First: count the syscalls to check for */
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering for (i = 0, n = 0; i < syscall_max(); i++)
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering if (syscall_filter[i >> 4] & (1 << (i & 31)))
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering /* Second: build the filter program from a header the syscall
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering * matches and the footer */
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering f = alloca(sizeof(struct sock_filter) * (ELEMENTSOF(header) + 2*n + ELEMENTSOF(footer)));
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering for (i = 0, n = 0; i < syscall_max(); i++)
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering if (syscall_filter[i >> 4] & (1 << (i & 31))) {
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, INDEX_TO_SYSCALL(i), 0, 1),
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW)
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering memcpy(f + (ELEMENTSOF(header) + 2*n), footer, sizeof(footer));
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering /* Third: install the filter */
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering prog.len = ELEMENTSOF(header) + ELEMENTSOF(footer) + 2*n;
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) < 0)
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poetteringstatic void do_idle_pipe_dance(int idle_pipe[4]) {
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering r = fd_wait_for_event(idle_pipe[0], POLLHUP, IDLE_TIMEOUT_USEC);
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering if (idle_pipe[3] >= 0 && r == 0 /* timeout */) {
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering /* Signal systemd that we are bored and want to continue. */
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering /* Wait for systemd to react to the signal above. */
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering fd_wait_for_event(idle_pipe[0], POLLHUP, IDLE_TIMEOUT2_USEC);
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering _cleanup_strv_free_ char **our_env = NULL;
c077529ba6852192c464772ce907670850210dfeLennart Poettering if (asprintf(&x, "LISTEN_PID=%lu", (unsigned long) getpid()) < 0)
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering if (asprintf(&x, "LISTEN_FDS=%u", n_fds) < 0)
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering if (asprintf(&x, "WATCHDOG_PID=%lu", (unsigned long) getpid()) < 0)
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering if (asprintf(&x, "WATCHDOG_USEC=%llu", (unsigned long long) watchdog_usec) < 0)
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering x = strdup(default_term_for_tty(tty_path(c)));
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering _cleanup_strv_free_ char **files_env = NULL;
70244d1d25eb80b57e160ea004d0e6bf793d4cafLennart Poettering if (context->std_input == EXEC_INPUT_SOCKET ||
70244d1d25eb80b57e160ea004d0e6bf793d4cafLennart Poettering context->std_output == EXEC_OUTPUT_SOCKET ||
70244d1d25eb80b57e160ea004d0e6bf793d4cafLennart Poettering context->std_error == EXEC_OUTPUT_SOCKET) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering r = exec_context_load_environment(context, &files_env);
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering "MESSAGE=Failed to load environment files: %s", strerror(-r),
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering "ERRNO=%d", -r,
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering _cleanup_strv_free_ char **our_env = NULL, **pam_env = NULL, **final_env = NULL, **final_argv = NULL;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering const char *username = NULL, *home = NULL, *shell = NULL;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering /* We reset exactly these signals, since they are the
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering * only ones we set to SIG_IGN in the main daemon. All
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * others we leave untouched because we set them to
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * SIG_DFL or a valid handler initially, both of which
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering * will be demoted to SIG_DFL. */
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (sigprocmask(SIG_SETMASK, &ss, NULL) < 0) {
9b420b3cfb8b93daf50e4cdbc92b05f2209ef893Lennart Poettering /* Close sockets very early to make sure we don't
9b420b3cfb8b93daf50e4cdbc92b05f2209ef893Lennart Poettering * block init reexecution because it cannot bind its
9b420b3cfb8b93daf50e4cdbc92b05f2209ef893Lennart Poettering memcpy(dont_close + n_dont_close, fds, sizeof(int) * n_fds);
554604b3073467af75dc94fac9e2343148603289Lennart Poettering if (runtime->netns_storage_socket[0] >= 0)
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering dont_close[n_dont_close++] = runtime->netns_storage_socket[0];
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (runtime->netns_storage_socket[1] >= 0)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering dont_close[n_dont_close++] = runtime->netns_storage_socket[1];
554604b3073467af75dc94fac9e2343148603289Lennart Poettering err = close_all_fds(dont_close, n_dont_close);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (!socket_tcpwrap(socket_fd, context->tcpwrap_name)) {
a658cafa98ab55ea948c29bc87eb3945d515fb41Lennart Poettering for (i = 0; i < (int) n_fds; i++) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (!socket_tcpwrap(fds[i], context->tcpwrap_name)) {
a658cafa98ab55ea948c29bc87eb3945d515fb41Lennart Poettering err = ask_for_confirmation(&response, argv);
554604b3073467af75dc94fac9e2343148603289Lennart Poettering write_confirm_message("Confirmation question timed out, assuming positive response.\n");
a658cafa98ab55ea948c29bc87eb3945d515fb41Lennart Poettering write_confirm_message("Couldn't ask confirmation question, assuming positive response: %s\n", strerror(-err));
554604b3073467af75dc94fac9e2343148603289Lennart Poettering write_confirm_message("Skipping execution.\n");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering write_confirm_message("Failing execution.\n");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* If a socket is connected to STDIN/STDOUT/STDERR, we
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * must sure to drop O_NONBLOCK */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering err = setup_input(context, socket_fd, apply_tty_stdin);
151b9b9662a90455262ce575a8a8ae74bf4ff336Lennart Poettering err = setup_output(context, STDOUT_FILENO, socket_fd, basename(command->path), unit_id, apply_tty_stdin);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering err = setup_output(context, STDERR_FILENO, socket_fd, basename(command->path), unit_id, apply_tty_stdin);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering err = cg_attach_everywhere(cgroup_supported, cgroup_path, 0);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering snprintf(t, sizeof(t), "%i", context->oom_score_adjust);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (write_string_file("/proc/self/oom_score_adj", t) < 0) {
a931ad47a8623163a29d898224d8a8c1177ffdafLennart Poettering if (setpriority(PRIO_PROCESS, 0, context->nice) < 0) {
554604b3073467af75dc94fac9e2343148603289Lennart Poettering .sched_priority = context->cpu_sched_priority,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (sched_setaffinity(0, CPU_ALLOC_SIZE(context->cpuset_ncpus), context->cpuset) < 0) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (ioprio_set(IOPRIO_WHO_PROCESS, 0, context->ioprio) < 0) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (context->timer_slack_nsec != (nsec_t) -1)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (prctl(PR_SET_TIMERSLACK, context->timer_slack_nsec) < 0) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering utmp_put_init_process(context->utmp_id, getpid(), getsid(0), context->tty_path);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering err = get_user_creds(&username, &uid, &gid, &home, &shell);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (is_terminal_input(context->std_input)) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (cgroup_path && context->user && context->pam_name) {
6797c324a653f119a3d7133122648aaa4878ddd6Lennart Poettering err = cg_set_task_access(SYSTEMD_CGROUP_CONTROLLER, cgroup_path, 0644, uid, gid);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering err = cg_set_group_access(SYSTEMD_CGROUP_CONTROLLER, cgroup_path, 0755, uid, gid);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering err = enforce_groups(context, username, gid);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (apply_permissions && context->pam_name && username) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering err = setup_pam(context->pam_name, username, uid, context->tty_path, &pam_env, fds, n_fds);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (context->private_network && runtime && runtime->netns_storage_socket[0] >= 0) {
a658cafa98ab55ea948c29bc87eb3945d515fb41Lennart Poettering err = setup_netns(runtime->netns_storage_socket);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (!strv_isempty(context->read_write_dirs) ||
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering !strv_isempty(context->read_only_dirs) ||
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering !strv_isempty(context->inaccessible_dirs) ||
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering (context->private_tmp && runtime && (runtime->tmp_dir || runtime->var_tmp_dir))) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* The runtime struct only contains the parent
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * of the private /tmp, which is
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * non-accessible to world users. Inside of it
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering * there's a /tmp that is sticky, and that's
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * the one we want to use here. */
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering tmp = strappenda(runtime->tmp_dir, "/tmp");
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering var = strappenda(runtime->var_tmp_dir, "/tmp");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (chroot(context->root_directory) < 0) {
bd16acf35e13a19cd2ded0a0c2ef774a98f73808Zbigniew Jędrzejewski-Szmek if (chdir(context->working_directory ? context->working_directory : "/") < 0) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering context->root_directory ? context->root_directory : "",
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering context->working_directory ? context->working_directory : "") < 0) {
bd16acf35e13a19cd2ded0a0c2ef774a98f73808Zbigniew Jędrzejewski-Szmek /* We repeat the fd closing here, to make sure that
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering * nothing is leaked from the PAM modules */
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers err = flags_fds(fds, n_fds, context->non_blocking);
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers for (i = 0; i < RLIMIT_NLIMITS; i++) {
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers if (setrlimit_closest(i, context->rlimit[i]) < 0) {
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers err = capability_bounding_set_drop(context->capability_bounding_set_drop, false);
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers /* PR_GET_SECUREBITS is not privileged, while
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers * PR_SET_SECUREBITS is. So to suppress
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers * potential EPERMs we'll try not to call
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers * PR_SET_SECUREBITS unless necessary. */
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers if (prctl(PR_GET_SECUREBITS) != context->secure_bits)
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers if (prctl(PR_SET_SECUREBITS, context->secure_bits) < 0) {
r = EXIT_SECUREBITS;
goto fail_child;
r = EXIT_CAPABILITIES;
goto fail_child;
goto fail_child;
if (err < 0) {
r = EXIT_SECCOMP;
goto fail_child;
r = EXIT_MEMORY;
goto fail_child;
NULL);
if (!final_env) {
r = EXIT_MEMORY;
goto fail_child;
if (!final_argv) {
r = EXIT_MEMORY;
goto fail_child;
if (line) {
log_open();
NULL);
log_close();
r = EXIT_EXEC;
log_open();
NULL);
log_close();
_exit(r);
NULL);
if (cgroup_path)
assert(c);
c->syslog_level_prefix = true;
c->ignore_sigpipe = true;
assert(c);
if (c->capabilities) {
if (c->cpuset)
assert(c);
exec_command_done(c+i);
ExecCommand *i;
free(i);
exec_command_free_list(c[i]);
c[i] = NULL;
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;
if (!console)
assert(f);
STRV_FOREACH(g, l)
assert(c);
assert(f);
fprintf(f,
if (c->tcpwrap_name)
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])
fprintf(f, "%s%s: %llu\n", prefix, rlimit_to_string(i), (unsigned long long) c->rlimit[i]->rlim_max);
if (c->ioprio_set) {
char *class_str;
fprintf(f,
if (c->cpu_sched_set) {
char *policy_str;
fprintf(f,
if (c->cpuset) {
for (i = 0; i < c->cpuset_ncpus; i++)
fprintf(f,
if (c->tty_path)
fprintf(f,
if (c->std_output == EXEC_OUTPUT_SYSLOG || c->std_output == EXEC_OUTPUT_KMSG || c->std_output == EXEC_OUTPUT_JOURNAL ||
c->std_output == EXEC_OUTPUT_SYSLOG_AND_CONSOLE || c->std_output == EXEC_OUTPUT_KMSG_AND_CONSOLE || c->std_output == EXEC_OUTPUT_JOURNAL_AND_CONSOLE ||
c->std_error == EXEC_OUTPUT_SYSLOG || c->std_error == EXEC_OUTPUT_KMSG || c->std_error == EXEC_OUTPUT_JOURNAL ||
c->std_error == EXEC_OUTPUT_SYSLOG_AND_CONSOLE || c->std_error == EXEC_OUTPUT_KMSG_AND_CONSOLE || c->std_error == EXEC_OUTPUT_JOURNAL_AND_CONSOLE) {
fprintf(f,
if (c->capabilities) {
prefix, t);
cap_free(t);
if (c->secure_bits)
if (c->capability_bounding_set_drop) {
for (l = 0; l <= cap_last_cap(); l++)
if ((t = cap_to_name(l))) {
cap_free(t);
if (c->user)
if (c->group)
if (c->pam_name)
if (c->utmp_id)
fprintf(f,
assert(s);
zero(*s);
assert(s);
zero(*s);
if (context) {
assert(s);
assert(f);
if (!prefix)
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);
char *p2;
const char *prefix2;
char *cmd;
assert(c);
assert(f);
if (!prefix)
fprintf(f,
assert(f);
if (!prefix)
assert(l);
assert(e);
assert(c);
return -ENOMEM;
strv_free(l);
return -ENOMEM;
c->path = p;
c->argv = l;
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)