execute.c revision 039f0e70a0fcd71dcf7cc2f3ba2cea2e3b186a60
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/>.
acf97e213e69a97e63ab8f7fad7ecd53608c757aLennart Poettering#define IDLE_TIMEOUT_USEC (5*USEC_PER_SEC)
acf97e213e69a97e63ab8f7fad7ecd53608c757aLennart Poettering#define IDLE_TIMEOUT2_USEC (1*USEC_PER_SEC)
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering/* This assumes there is a 'tty' group */
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poetteringstatic int shift_fds(int fds[], unsigned n_fds) {
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering /* Modifies the fds array! (sorts it) */
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering /* Already at right index? */
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering if ((nfd = fcntl(fds[i], F_DUPFD, i+3)) < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* Hmm, the fd we wanted isn't free? Then
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen * let's remember that and try again from here */
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poetteringstatic int flags_fds(const int fds[], unsigned n_fds, bool nonblock) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* Drops/Sets O_NONBLOCK and FD_CLOEXEC from the file flags */
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering for (i = 0; i < n_fds; i++) {
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering if ((r = fd_nonblock(fds[i], nonblock)) < 0)
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering /* We unconditionally drop FD_CLOEXEC from the fds,
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering * since after all we want to pass these fds to our
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering_pure_ static const char *tty_path(const ExecContext *context) {
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poetteringstatic void exec_context_tty_reset(const ExecContext *context) {
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering if (context->tty_vt_disallocate && context->tty_path)
e56056e93d33619a3acf13e483900b4f8938228fThomas Hindoe Paaboel Andersenstatic bool is_terminal_output(ExecOutput o) {
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poetteringstatic int open_null_as(int flags, int nfd) {
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poetteringstatic int connect_logger_as(const ExecContext *context, ExecOutput output, const char *ident, const char *unit_id, int nfd) {
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering .un.sun_path = "/run/systemd/journal/stdout",
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering r = connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path));
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering context->syslog_identifier ? context->syslog_identifier : ident,
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering output == EXEC_OUTPUT_SYSLOG || output == EXEC_OUTPUT_SYSLOG_AND_CONSOLE,
10f9c75519671e7c7ab8993b54fe22da7c2d0c38Lennart Poettering output == EXEC_OUTPUT_KMSG || output == EXEC_OUTPUT_KMSG_AND_CONSOLE,
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poetteringstatic int open_terminal_as(const char *path, mode_t mode, int nfd) {
10f9c75519671e7c7ab8993b54fe22da7c2d0c38Lennart Poettering if ((fd = open_terminal(path, mode | O_NOCTTY)) < 0)
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poetteringstatic bool is_terminal_input(ExecInput i) {
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poetteringstatic int fixup_input(ExecInput std_input, int socket_fd, bool apply_tty_stdin) {
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering if (is_terminal_input(std_input) && !apply_tty_stdin)
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering if (std_input == EXEC_INPUT_SOCKET && socket_fd < 0)
10f9c75519671e7c7ab8993b54fe22da7c2d0c38Lennart Poetteringstatic int fixup_output(ExecOutput std_output, int socket_fd) {
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering if (std_output == EXEC_OUTPUT_SOCKET && socket_fd < 0)
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poetteringstatic int setup_input(const ExecContext *context, int socket_fd, bool apply_tty_stdin) {
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering i = fixup_input(context->std_input, socket_fd, apply_tty_stdin);
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering return open_null_as(O_RDONLY, STDIN_FILENO);
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering r = dup2(fd, STDIN_FILENO) < 0 ? -errno : STDIN_FILENO;
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering return dup2(socket_fd, STDIN_FILENO) < 0 ? -errno : STDIN_FILENO;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poetteringstatic int setup_output(const ExecContext *context, int fileno, int socket_fd, const char *ident, const char *unit_id, bool apply_tty_stdin) {
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering i = fixup_input(context->std_input, socket_fd, apply_tty_stdin);
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering o = fixup_output(context->std_output, socket_fd);
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering e = fixup_output(context->std_error, socket_fd);
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering /* This expects the input and output are already set up */
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering /* Don't change the stderr file descriptor if we inherit all
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering * the way and are not on a tty */
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering !is_terminal_input(context->std_input) &&
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering /* Duplicate from stdout if possible */
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering if (e == o || e == EXEC_OUTPUT_INHERIT)
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering return dup2(STDOUT_FILENO, fileno) < 0 ? -errno : fileno;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering } else if (o == EXEC_OUTPUT_INHERIT) {
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering /* If input got downgraded, inherit the original value */
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering if (i == EXEC_INPUT_NULL && is_terminal_input(context->std_input))
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering return open_terminal_as(tty_path(context), O_WRONLY, fileno);
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering /* If the input is connected to anything that's not a /dev/null, inherit that... */
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering return dup2(STDIN_FILENO, fileno) < 0 ? -errno : fileno;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering /* If we are not started from PID 1 we just inherit STDOUT from our parent process. */
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering /* We need to open /dev/null here anew, to get the right access mode. */
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering return dup2(STDIN_FILENO, fileno) < 0 ? -errno : fileno;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering /* We don't reset the terminal if this is just about output */
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering return open_terminal_as(tty_path(context), O_WRONLY, fileno);
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering r = connect_logger_as(context, o, ident, unit_id, fileno);
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering LOG_MESSAGE("Failed to connect %s of %s to the journal socket: %s",
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering fileno == STDOUT_FILENO ? "stdout" : "stderr",
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering return dup2(socket_fd, fileno) < 0 ? -errno : fileno;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering assert_not_reached("Unknown error type");
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poetteringstatic int chown_terminal(int fd, uid_t uid) {
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering /* This might fail. What matters are the results. */
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering if (st.st_uid != uid || (st.st_mode & 0777) != TTY_MODE)
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poetteringstatic int setup_confirm_stdio(int *_saved_stdin,
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering int fd = -1, saved_stdin, saved_stdout = -1, r;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering saved_stdin = fcntl(STDIN_FILENO, F_DUPFD, 3);
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering saved_stdout = fcntl(STDOUT_FILENO, F_DUPFD, 3);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering_printf_(1, 2) static int write_confirm_message(const char *format, ...) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic int restore_confirm_stdio(int *saved_stdin,
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering if (dup2(*saved_stdin, STDIN_FILENO) < 0)
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering if (dup2(*saved_stdout, STDOUT_FILENO) < 0)
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poetteringstatic int ask_for_confirmation(char *response, char **argv) {
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering int saved_stdout = -1, saved_stdin = -1, r;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering r = setup_confirm_stdio(&saved_stdin, &saved_stdout);
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering r = ask_char(response, "yns", "Execute %s? [Yes, No, Skip] ", line);
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering restore_confirm_stdio(&saved_stdin, &saved_stdout);
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poetteringstatic int enforce_groups(const ExecContext *context, const char *username, gid_t gid) {
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering /* Lookup and set GID and supplementary group list. Here too
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering * we avoid NSS lookups for gid=0. */
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering /* First step, initialize groups from /etc/groups */
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering /* Second step, set our gids */
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers /* Final step, initialize any manually set supplementary groups */
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering assert_se((ngroups_max = (int) sysconf(_SC_NGROUPS_MAX)) > 0);
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering if ((k = getgroups(ngroups_max, gids)) < 0) {
a6c616024db23fef34152c1432892824a07799ccLennart Poettering STRV_FOREACH(i, context->supplementary_groups) {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen const char *g;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers if (r < 0) {
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sieversstatic int enforce_user(const ExecContext *context, uid_t uid) {
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering /* Sets (but doesn't lookup) the uid and make sure we keep the
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers * capabilities while doing so. */
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering CAP_SETUID, /* Necessary so that we can run setresuid() below */
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers CAP_SETPCAP /* Necessary so that we can set PR_SET_SECUREBITS later on */
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers /* First step: If we need to keep capabilities but
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen * drop privileges we need to make sure we keep our
27e72d6b22890ba4a8cbc05c49667cd1cccf1461Simon Peeters * caps, while we drop privileges. */
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt int sb = context->secure_bits | 1<<SECURE_KEEP_CAPS;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen /* Second step: set the capabilities. This will reduce
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering * the capabilities to the minimum we need. */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (cap_set_flag(d, CAP_EFFECTIVE, ELEMENTSOF(bits), bits, CAP_SET) < 0 ||
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering cap_set_flag(d, CAP_PERMITTED, ELEMENTSOF(bits), bits, CAP_SET) < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* Third step: actually set the uids */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* At this point we should have all necessary capabilities but
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering are otherwise a normal user. However, the caps might got
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering corrupted due to the setresuid() so we need clean them up
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering later. This is done outside of this call. */
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen /* We don't support conversations */
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers const char *user,
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers const char *tty,
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering /* We set up PAM in the parent process, then fork. The child
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering * will then stay around until killed via PR_GET_PDEATHSIG or
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering * systemd via the cgroup logic. It will then remove the PAM
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering * session again. The parent process will exec() the actual
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering * daemon. We do things this way to ensure that the main PID
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering * of the daemon is the one we initially fork()ed. */
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering if (log_get_max_level() < LOG_PRI(LOG_DEBUG))
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering pam_code = pam_start(name, user, &conv, &handle);
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering pam_code = pam_set_item(handle, PAM_TTY, tty);
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering pam_code = pam_open_session(handle, flags);
c19de71113f956809995fc68817e055e9f61f607Lennart Poettering /* Block SIGTERM, so that we know that it won't get lost in
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering * the child */
c19de71113f956809995fc68817e055e9f61f607Lennart Poettering sigprocmask(SIG_BLOCK, &ss, &old_ss) < 0)
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering /* The child's job is to reset the PAM session on
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering * termination */
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering /* This string must fit in 10 chars (i.e. the length
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering * of "/sbin/init"), to look pretty in /bin/ps */
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering /* Make sure we don't keep open the passed fds in this
c19de71113f956809995fc68817e055e9f61f607Lennart Poettering child. We assume that otherwise only those fds are
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering open here that have been opened by PAM. */
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering /* Drop privileges - we don't need any to pam_close_session
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering * and this will make PR_SET_PDEATHSIG work in most cases.
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering * If this fails, ignore the error - but expect sd-pam threads
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering * to fail to exit normally */
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering log_error_errno(r, "Error: Failed to setresuid() in sd-pam: %m");
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering /* Wait until our parent died. This will only work if
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering * the above setresuid() succeeds, otherwise the kernel
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering * will not allow unprivileged parents kill their privileged
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering * children this way. We rely on the control groups kill logic
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering * to do the rest for us. */
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering /* Check if our parent process might already have
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering /* If our parent died we'll end the session */
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering pam_code = pam_close_session(handle, flags);
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering /* If the child was forked off successfully it will do all the
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering * cleanups, so forget about the handle here. */
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering /* Unblock SIGTERM again in the parent */
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering if (sigprocmask(SIG_SETMASK, &old_ss, NULL) < 0)
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering /* We close the log explicitly here, since the PAM modules
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering * might have opened it, but we don't want this fd around. */
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering log_error("PAM failed: %s", pam_strerror(handle, pam_code));
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering err = -EPERM; /* PAM errors do not map to errno */
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering log_error_errno(errno, "PAM failed: %m");
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering pam_code = pam_close_session(handle, flags);
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poetteringstatic void rename_process_from_path(const char *path) {
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering const char *p;
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering /* This resulting string must fit in 10 chars (i.e. the length
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * of "/sbin/init") to look pretty in /bin/ps */
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering /* The end of the process name is usually more
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * interesting, since the first bit might just be
acf97e213e69a97e63ab8f7fad7ecd53608c757aLennart Poettering * "systemd-" */
acf97e213e69a97e63ab8f7fad7ecd53608c757aLennart Poettering p = p + l - 8;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersenstatic int apply_seccomp(const ExecContext *c) {
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering negative_action = c->syscall_errno == 0 ? SCMP_ACT_KILL : SCMP_ACT_ERRNO(c->syscall_errno);
1dba654b27918c22e413ac5b3c19301f1ff86ad2Lennart Poettering seccomp = seccomp_init(c->syscall_whitelist ? negative_action : SCMP_ACT_ALLOW);
1dba654b27918c22e413ac5b3c19301f1ff86ad2Lennart Poettering r = seccomp_arch_add(seccomp, PTR_TO_UINT32(id) - 1);
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering r = seccomp_add_secondary_archs(seccomp);
acf97e213e69a97e63ab8f7fad7ecd53608c757aLennart Poettering action = c->syscall_whitelist ? SCMP_ACT_ALLOW : negative_action;
1dba654b27918c22e413ac5b3c19301f1ff86ad2Lennart Poettering r = seccomp_rule_add(seccomp, action, PTR_TO_INT(id) - 1, 0);
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering r = seccomp_attr_set(seccomp, SCMP_FLTATR_CTL_NNP, 0);
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poetteringstatic int apply_address_families(const ExecContext *c) {
0370612e0522191f929e3feb7d4937fff3d421e2Lennart Poettering r = seccomp_add_secondary_archs(seccomp);
0370612e0522191f929e3feb7d4937fff3d421e2Lennart Poettering /* If this is a whitelist, we first block the address
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering * families that are out of range and then everything
0370612e0522191f929e3feb7d4937fff3d421e2Lennart Poettering * that is not in the set. First, we find the lowest
0370612e0522191f929e3feb7d4937fff3d421e2Lennart Poettering * and highest address family in the set. */
0370612e0522191f929e3feb7d4937fff3d421e2Lennart Poettering SET_FOREACH(afp, c->address_families, i) {
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering /* No entries in the valid range, block everything */
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering /* Block everything below the first entry */
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering /* Block everything above the last entry */
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering /* Block everything between the first and last
da054c3782f25b3b18243f6c76dcfcf90ba70274Lennart Poettering if (set_contains(c->address_families, INT_TO_PTR(af)))
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering /* If this is a blacklist, then generate one rule for
40205d706e1210763ff4c98a317556375bd04bcdLennart Poettering * each address family that are then combined in OR
c7b7d4493aa03e9ef5fb1e670b8969a48aa494ddLennart Poettering SET_FOREACH(af, c->address_families, i) {
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering r = seccomp_attr_set(seccomp, SCMP_FLTATR_CTL_NNP, 0);
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poetteringstatic void do_idle_pipe_dance(int idle_pipe[4]) {
d04c1fb8e215600b4950c6778c6c16ddafc14024Lennart Poettering r = fd_wait_for_event(idle_pipe[0], POLLHUP, IDLE_TIMEOUT_USEC);
d04c1fb8e215600b4950c6778c6c16ddafc14024Lennart Poettering if (idle_pipe[3] >= 0 && r == 0 /* timeout */) {
d04c1fb8e215600b4950c6778c6c16ddafc14024Lennart Poettering /* Signal systemd that we are bored and want to continue. */
d04c1fb8e215600b4950c6778c6c16ddafc14024Lennart Poettering /* Wait for systemd to react to the signal above. */
acf97e213e69a97e63ab8f7fad7ecd53608c757aLennart Poettering fd_wait_for_event(idle_pipe[0], POLLHUP, IDLE_TIMEOUT2_USEC);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering _cleanup_strv_free_ char **our_env = NULL;
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt if (asprintf(&x, "LISTEN_PID="PID_FMT, getpid()) < 0)
c7b7d4493aa03e9ef5fb1e670b8969a48aa494ddLennart Poettering if (asprintf(&x, "LISTEN_FDS=%u", n_fds) < 0)
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering if (asprintf(&x, "WATCHDOG_PID="PID_FMT, getpid()) < 0)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (asprintf(&x, "WATCHDOG_USEC="USEC_FMT, watchdog_usec) < 0)
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering x = strdup(default_term_for_tty(tty_path(c)));
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poetteringstatic int exec_child(ExecCommand *command,
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering _cleanup_strv_free_ char **our_env = NULL, **pam_env = NULL, **final_env = NULL, **final_argv = NULL;
acf97e213e69a97e63ab8f7fad7ecd53608c757aLennart Poettering _cleanup_free_ char *mac_selinux_context_net = NULL;
acf97e213e69a97e63ab8f7fad7ecd53608c757aLennart Poettering const char *username = NULL, *home = NULL, *shell = NULL;
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering /* We reset exactly these signals, since they are the
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering * only ones we set to SIG_IGN in the main daemon. All
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering * others we leave untouched because we set them to
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering * SIG_DFL or a valid handler initially, both of which
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering * will be demoted to SIG_DFL. */
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering /* Close sockets very early to make sure we don't
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering * block init reexecution because it cannot bind its
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering memcpy(dont_close + n_dont_close, fds, sizeof(int) * n_fds);
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering dont_close[n_dont_close++] = params->bus_endpoint_fd;
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering if (runtime->netns_storage_socket[0] >= 0)
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering dont_close[n_dont_close++] = runtime->netns_storage_socket[0];
ebd011d95b61a86258dece9864f65b7c4af721c0Lennart Poettering if (runtime->netns_storage_socket[1] >= 0)
ebd011d95b61a86258dece9864f65b7c4af721c0Lennart Poettering dont_close[n_dont_close++] = runtime->netns_storage_socket[1];
ebd011d95b61a86258dece9864f65b7c4af721c0Lennart Poettering err = close_all_fds(dont_close, n_dont_close);
ebd011d95b61a86258dece9864f65b7c4af721c0Lennart Poettering err = ask_for_confirmation(&response, argv);
ebd011d95b61a86258dece9864f65b7c4af721c0Lennart Poettering write_confirm_message("Confirmation question timed out, assuming positive response.\n");
ebd011d95b61a86258dece9864f65b7c4af721c0Lennart Poettering write_confirm_message("Couldn't ask confirmation question, assuming positive response: %s\n", strerror(-err));
ebd011d95b61a86258dece9864f65b7c4af721c0Lennart Poettering write_confirm_message("Skipping execution.\n");
ebd011d95b61a86258dece9864f65b7c4af721c0Lennart Poettering write_confirm_message("Failing execution.\n");
ebd011d95b61a86258dece9864f65b7c4af721c0Lennart Poettering /* If a socket is connected to STDIN/STDOUT/STDERR, we
ebd011d95b61a86258dece9864f65b7c4af721c0Lennart Poettering * must sure to drop O_NONBLOCK */
acf97e213e69a97e63ab8f7fad7ecd53608c757aLennart Poettering err = setup_input(context, socket_fd, params->apply_tty_stdin);
ebd011d95b61a86258dece9864f65b7c4af721c0Lennart Poettering err = setup_output(context, STDOUT_FILENO, socket_fd, basename(command->path), params->unit_id, params->apply_tty_stdin);
ebd011d95b61a86258dece9864f65b7c4af721c0Lennart Poettering err = setup_output(context, STDERR_FILENO, socket_fd, basename(command->path), params->unit_id, params->apply_tty_stdin);
ebd011d95b61a86258dece9864f65b7c4af721c0Lennart Poettering err = cg_attach_everywhere(params->cgroup_supported, params->cgroup_path, 0, NULL, NULL);
ebd011d95b61a86258dece9864f65b7c4af721c0Lennart Poettering snprintf(t, sizeof(t), "%i", context->oom_score_adjust);
d8f52ed25a9edce75fda5251c977b7898e33887eLennart Poettering if (write_string_file("/proc/self/oom_score_adj", t) < 0) {
d8f52ed25a9edce75fda5251c977b7898e33887eLennart Poettering if (setpriority(PRIO_PROCESS, 0, context->nice) < 0) {
d8f52ed25a9edce75fda5251c977b7898e33887eLennart Poettering .sched_priority = context->cpu_sched_priority,
d8f52ed25a9edce75fda5251c977b7898e33887eLennart Poettering if (sched_setaffinity(0, CPU_ALLOC_SIZE(context->cpuset_ncpus), context->cpuset) < 0) {
d8f52ed25a9edce75fda5251c977b7898e33887eLennart Poettering if (ioprio_set(IOPRIO_WHO_PROCESS, 0, context->ioprio) < 0) {
d8f52ed25a9edce75fda5251c977b7898e33887eLennart Poettering if (context->timer_slack_nsec != NSEC_INFINITY)
d8f52ed25a9edce75fda5251c977b7898e33887eLennart Poettering if (prctl(PR_SET_TIMERSLACK, context->timer_slack_nsec) < 0) {
d8f52ed25a9edce75fda5251c977b7898e33887eLennart Poettering if (context->personality != 0xffffffffUL)
d8f52ed25a9edce75fda5251c977b7898e33887eLennart Poettering if (personality(context->personality) < 0) {
d8f52ed25a9edce75fda5251c977b7898e33887eLennart Poettering utmp_put_init_process(context->utmp_id, getpid(), getsid(0), context->tty_path);
d8f52ed25a9edce75fda5251c977b7898e33887eLennart Poettering err = get_user_creds(&username, &uid, &gid, &home, &shell);
d8f52ed25a9edce75fda5251c977b7898e33887eLennart Poettering if (is_terminal_input(context->std_input)) {
d8f52ed25a9edce75fda5251c977b7898e33887eLennart Poettering if (params->bus_endpoint_fd >= 0 && context->bus_endpoint) {
d8f52ed25a9edce75fda5251c977b7898e33887eLennart Poettering uid_t ep_uid = (uid == UID_INVALID) ? 0 : uid;
d8f52ed25a9edce75fda5251c977b7898e33887eLennart Poettering err = bus_kernel_set_endpoint_policy(params->bus_endpoint_fd, ep_uid, context->bus_endpoint);
d8f52ed25a9edce75fda5251c977b7898e33887eLennart Poettering /* If delegation is enabled we'll pass ownership of the cgroup
d8f52ed25a9edce75fda5251c977b7898e33887eLennart Poettering * (but only in systemd's own controller hierarchy!) to the
d8f52ed25a9edce75fda5251c977b7898e33887eLennart Poettering * user of the new process. */
d8f52ed25a9edce75fda5251c977b7898e33887eLennart Poettering if (params->cgroup_path && context->user && params->cgroup_delegate) {
d8f52ed25a9edce75fda5251c977b7898e33887eLennart Poettering err = cg_set_task_access(SYSTEMD_CGROUP_CONTROLLER, params->cgroup_path, 0644, uid, gid);
d8f52ed25a9edce75fda5251c977b7898e33887eLennart Poettering err = cg_set_group_access(SYSTEMD_CGROUP_CONTROLLER, params->cgroup_path, 0755, uid, gid);
d8f52ed25a9edce75fda5251c977b7898e33887eLennart Poettering if (!strv_isempty(context->runtime_directory) && params->runtime_prefix) {
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering STRV_FOREACH(rt, context->runtime_directory) {
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering p = strjoin(params->runtime_prefix, "/", *rt, NULL);
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering err = mkdir_safe(p, context->runtime_directory_mode, uid, gid);
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering err = enforce_groups(context, username, gid);
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering if (params->apply_permissions && context->pam_name && username) {
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering err = setup_pam(context->pam_name, username, uid, context->tty_path, &pam_env, fds, n_fds);
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering if (context->private_network && runtime && runtime->netns_storage_socket[0] >= 0) {
6adf7b5e46d32376868feef0197e6ada352aa6f2Lennart Poettering err = setup_netns(runtime->netns_storage_socket);
6adf7b5e46d32376868feef0197e6ada352aa6f2Lennart Poettering if (!strv_isempty(context->read_write_dirs) ||
6adf7b5e46d32376868feef0197e6ada352aa6f2Lennart Poettering !strv_isempty(context->read_only_dirs) ||
6adf7b5e46d32376868feef0197e6ada352aa6f2Lennart Poettering !strv_isempty(context->inaccessible_dirs) ||
6adf7b5e46d32376868feef0197e6ada352aa6f2Lennart Poettering (context->private_tmp && runtime && (runtime->tmp_dir || runtime->var_tmp_dir)) ||
6adf7b5e46d32376868feef0197e6ada352aa6f2Lennart Poettering context->protect_system != PROTECT_SYSTEM_NO ||
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering context->protect_home != PROTECT_HOME_NO) {
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering /* The runtime struct only contains the parent
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering * of the private /tmp, which is
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering * non-accessible to world users. Inside of it
6adf7b5e46d32376868feef0197e6ada352aa6f2Lennart Poettering * there's a /tmp that is sticky, and that's
6adf7b5e46d32376868feef0197e6ada352aa6f2Lennart Poettering * the one we want to use here. */
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering tmp = strappenda(runtime->tmp_dir, "/tmp");
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering var = strappenda(runtime->var_tmp_dir, "/tmp");
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering 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");
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering else if (err < 0) {
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering if (chroot(context->root_directory) < 0) {
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering if (chdir(context->working_directory ? context->working_directory : "/") < 0) {
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering context->root_directory ? context->root_directory : "",
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering context->working_directory ? context->working_directory : "") < 0) {
6adf7b5e46d32376868feef0197e6ada352aa6f2Lennart Poettering if (params->apply_permissions && mac_selinux_use() && params->selinux_context_net && socket_fd >= 0) {
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering err = mac_selinux_get_child_mls_label(socket_fd, command->path, context->selinux_context, &mac_selinux_context_net);
6adf7b5e46d32376868feef0197e6ada352aa6f2Lennart Poettering /* We repeat the fd closing here, to make sure that
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering * nothing is leaked from the PAM modules. Note that
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering * we are more aggressive this time since socket_fd
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering * and the netns fds we don't need anymore. The custom
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering * endpoint fd was needed to upload the policy and can
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering * now be closed as well. */
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering err = flags_fds(fds, n_fds, context->non_blocking);
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering for (i = 0; i < _RLIMIT_MAX; i++) {
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering if (setrlimit_closest(i, context->rlimit[i]) < 0) {
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering if (context->capability_bounding_set_drop) {
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering err = capability_bounding_set_drop(context->capability_bounding_set_drop, false);
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering err = mac_smack_apply_pid(0, context->smack_process_label);
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering /* PR_GET_SECUREBITS is not privileged, while
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering * PR_SET_SECUREBITS is. So to suppress
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering * potential EPERMs we'll try not to call
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering * PR_SET_SECUREBITS unless necessary. */
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering if (prctl(PR_GET_SECUREBITS) != context->secure_bits)
6e18cc9fa078d2a967251017ddb5baefb104b720Lennart Poettering if (prctl(PR_SET_SECUREBITS, context->secure_bits) < 0) {
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering if (cap_set_proc(context->capabilities) < 0) {
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) {
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering if (context->address_families_whitelist ||
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering !set_isempty(context->address_families)) {
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering char *exec_context = mac_selinux_context_net ?: context->selinux_context;
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering if (context->apparmor_profile && mac_apparmor_use()) {
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering err = aa_change_onexec(context->apparmor_profile);
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering if (err < 0 && !context->apparmor_profile_ignore) {
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering err = build_environment(context, n_fds, params->watchdog_usec, home, username, shell, &our_env);
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering final_argv = replace_env_argv(argv, final_env);
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering if (_unlikely_(log_get_max_level() >= LOG_PRI(LOG_DEBUG))) {
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering execve(command->path, final_argv, final_env);
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering _cleanup_strv_free_ char **files_env = NULL;
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering assert(params->fds || params->n_fds <= 0);
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering if (context->std_input == EXEC_INPUT_SOCKET ||
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering context->std_output == EXEC_OUTPUT_SOCKET ||
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering context->std_error == EXEC_OUTPUT_SOCKET) {
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering err = exec_context_load_environment(context, params->unit_id, &files_env);
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering LOG_MESSAGE("Failed to load environment files: %s", strerror(-err)),
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering LOG_MESSAGE("About to execute: %s", line),
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering LOG_MESSAGE("Failed at step %s spawning %s: %s",
7079cfeffb6d520f20ddff53fd78467e72e6cc94Lennart Poettering exit_status_to_string(r, EXIT_STATUS_SYSTEMD),
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering /* We add the new process to the cgroup both in the child (so
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering * that we can be sure that no user code is ever executed
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering * outside of the cgroup) and in the parent (so that we can be
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering * sure that when we kill the cgroup the process will be
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering * killed too). */
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering cg_attach(SYSTEMD_CGROUP_CONTROLLER, params->cgroup_path, pid);
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering exec_status_start(&command->exec_status, pid);
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 0);
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering c->syslog_priority = LOG_DAEMON|LOG_INFO;
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering for (l = 0; l < ELEMENTSOF(c->rlimit); l++) {
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poetteringint exec_context_destroy_runtime_directory(ExecContext *c, const char *runtime_prefix) {
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering p = strjoin(runtime_prefix, "/", *i, NULL);
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering /* We execute this synchronously, since we need to be
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering * sure this is gone when we start the service
56b921c3d863f0e098f60f934e6c5880575c68abZbigniew Jędrzejewski-Szmek rm_rf(p, false, true, false);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringvoid exec_command_done_array(ExecCommand *c, unsigned n) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering for (i = 0; i < n; i++)
e56056e93d33619a3acf13e483900b4f8938228fThomas Hindoe Paaboel AndersenExecCommand* exec_command_free_list(ExecCommand *c) {
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering while ((i = c)) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringvoid exec_command_free_array(ExecCommand **c, unsigned n) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering for (i = 0; i < n; i++)
d8f52ed25a9edce75fda5251c977b7898e33887eLennart Poetteringstatic void invalid_env(const char *p, void *userdata) {
acf97e213e69a97e63ab8f7fad7ecd53608c757aLennart Poettering log_unit_error(info->unit_id, "Ignoring invalid environment assignment '%s': %s", p, info->path);
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poetteringint exec_context_load_environment(const ExecContext *c, const char *unit_id, char ***l) {
eb9da376d76b48585b3b63b4f91903b54f7abd36Lennart Poettering char **i, **r = NULL;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* Filename supports globbing, take all matching files */
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering for (n = 0; n < count; n++) {
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering k = load_env_file(NULL, pglob.gl_pathv[n], NULL, &p);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* Log invalid environment variables with filename */
e56056e93d33619a3acf13e483900b4f8938228fThomas Hindoe Paaboel Andersen p = strv_env_clean_with_callback(p, invalid_env, &info);
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poetteringstatic bool tty_may_match_dev_console(const char *tty) {
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering /* trivial identity? */
d8f52ed25a9edce75fda5251c977b7898e33887eLennart Poettering /* if we could not resolve, assume it may */
6e18cc9fa078d2a967251017ddb5baefb104b720Lennart Poettering /* "tty0" means the active VC, so it may be the same sometimes */
6e18cc9fa078d2a967251017ddb5baefb104b720Lennart Poettering return streq(console, tty) || (streq(console, "tty0") && tty_is_vc(tty));
6e18cc9fa078d2a967251017ddb5baefb104b720Lennart Poetteringbool exec_context_may_touch_console(ExecContext *ec) {
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering return (ec->tty_reset || ec->tty_vhangup || ec->tty_vt_disallocate ||
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poetteringstatic void strv_fprintf(FILE *f, char **l) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringvoid exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering "%sUMask: %04o\n"
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering "%sWorkingDirectory: %s\n"
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering "%sRootDirectory: %s\n"
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering "%sNonBlocking: %s\n"
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering "%sPrivateTmp: %s\n"
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering "%sPrivateNetwork: %s\n"
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering "%sPrivateDevices: %s\n"
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering "%sProtectHome: %s\n"
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering "%sProtectSystem: %s\n"
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering "%sIgnoreSIGPIPE: %s\n",
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering prefix, c->working_directory ? c->working_directory : "/",
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering prefix, c->root_directory ? c->root_directory : "/",
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering prefix, protect_home_to_string(c->protect_home),
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering prefix, protect_system_to_string(c->protect_system),
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering fprintf(f, "%sEnvironment: %s\n", prefix, *e);
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering fprintf(f, "%sEnvironmentFile: %s\n", prefix, *e);
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering "%sNice: %i\n",
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering "%sOOMScoreAdjust: %i\n",
84f6181c2ac99a0514ca5e0c8fc8c8e284caf789Lennart Poettering for (i = 0; i < RLIM_NLIMITS; i++)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering prefix, rlimit_to_string(i), c->rlimit[i]->rlim_max);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering ioprio_class_to_string_alloc(IOPRIO_PRIO_CLASS(c->ioprio), &class_str);
d21ed1ead18d16d35c30299a69d3366847f8a039Lennart Poettering "%sIOSchedulingClass: %s\n"
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen "%sIOPriority: %i\n",
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering sched_policy_to_string_alloc(c->cpu_sched_policy, &policy_str);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering "%sCPUSchedulingPolicy: %s\n"
84f6181c2ac99a0514ca5e0c8fc8c8e284caf789Lennart Poettering "%sCPUSchedulingPriority: %i\n"
84f6181c2ac99a0514ca5e0c8fc8c8e284caf789Lennart Poettering "%sCPUSchedulingResetOnFork: %s\n",
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)