execute.c revision 3cc2aff1abff9e34f9fec282d970204dc1eab6f1
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/>.
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen/* This assumes there is a 'tty' group */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic int shift_fds(int fds[], unsigned n_fds) {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen /* Modifies the fds array! (sorts it) */
5b30bef856e89a571df57b7b953e9a1409d9acedLennart Poettering /* Already at right index? */
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering /* Hmm, the fd we wanted isn't free? Then
10f9c75519671e7c7ab8993b54fe22da7c2d0c38Lennart Poettering * let's remember that and try again from here */
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poetteringstatic int flags_fds(const int fds[], unsigned n_fds, bool nonblock) {
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering /* Drops/Sets O_NONBLOCK and FD_CLOEXEC from the file flags */
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering for (i = 0; i < n_fds; i++) {
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering /* We unconditionally drop FD_CLOEXEC from the fds,
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering * since after all we want to pass these fds to our
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering_pure_ static const char *tty_path(const ExecContext *context) {
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poetteringstatic void exec_context_tty_reset(const ExecContext *context) {
10f9c75519671e7c7ab8993b54fe22da7c2d0c38Lennart Poettering if (context->tty_vt_disallocate && context->tty_path)
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poetteringstatic bool is_terminal_output(ExecOutput o) {
10f9c75519671e7c7ab8993b54fe22da7c2d0c38Lennart Poetteringstatic int open_null_as(int flags, int nfd) {
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poetteringstatic int connect_journal_socket(int fd, uid_t uid, gid_t gid) {
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart 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 /* If we fail to restore the uid or gid, things will likely
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering fail later on. This should only happen if an LSM interferes. */
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poetteringstatic int connect_logger_as(const ExecContext *context, ExecOutput output, const char *ident, const char *unit_id, int nfd, uid_t uid, gid_t gid) {
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering r = connect_journal_socket(fd, uid, gid);
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering context->syslog_identifier ? context->syslog_identifier : ident,
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering output == EXEC_OUTPUT_SYSLOG || output == EXEC_OUTPUT_SYSLOG_AND_CONSOLE,
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering output == EXEC_OUTPUT_KMSG || output == EXEC_OUTPUT_KMSG_AND_CONSOLE,
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poetteringstatic int open_terminal_as(const char *path, mode_t mode, int nfd) {
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering fd = open_terminal(path, mode | O_NOCTTY);
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poetteringstatic bool is_terminal_input(ExecInput i) {
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poetteringstatic int fixup_input(ExecInput std_input, int socket_fd, bool apply_tty_stdin) {
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering if (is_terminal_input(std_input) && !apply_tty_stdin)
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering if (std_input == EXEC_INPUT_SOCKET && socket_fd < 0)
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poetteringstatic int fixup_output(ExecOutput std_output, int socket_fd) {
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering if (std_output == EXEC_OUTPUT_SOCKET && socket_fd < 0)
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poetteringstatic int setup_input(const ExecContext *context, int socket_fd, bool apply_tty_stdin) {
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering i = fixup_input(context->std_input, socket_fd, apply_tty_stdin);
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering return open_null_as(O_RDONLY, STDIN_FILENO);
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering r = dup2(fd, STDIN_FILENO) < 0 ? -errno : STDIN_FILENO;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering return dup2(socket_fd, STDIN_FILENO) < 0 ? -errno : STDIN_FILENO;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering assert_not_reached("Unknown input type");
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poetteringstatic int setup_output(Unit *unit, const ExecContext *context, int fileno, int socket_fd, const char *ident, bool apply_tty_stdin, uid_t uid, gid_t gid) {
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering i = fixup_input(context->std_input, socket_fd, apply_tty_stdin);
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering o = fixup_output(context->std_output, socket_fd);
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart 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
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers * 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)
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen return dup2(STDOUT_FILENO, fileno) < 0 ? -errno : fileno;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering } else if (o == EXEC_OUTPUT_INHERIT) {
56159e0d918e9a9be07988133bb2847779325de0Lennart 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... */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return dup2(STDIN_FILENO, fileno) < 0 ? -errno : fileno;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* If we are not started from PID 1 we just inherit STDOUT from our parent process. */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* We need to open /dev/null here anew, to get the right access mode. */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return dup2(STDIN_FILENO, fileno) < 0 ? -errno : fileno;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* We don't reset the terminal if this is just about output */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return open_terminal_as(tty_path(context), O_WRONLY, fileno);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = connect_logger_as(context, o, ident, unit->id, fileno, uid, gid);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_unit_error_errno(unit, r, "Failed to connect %s to the journal socket, ignoring: %m", fileno == STDOUT_FILENO ? "stdout" : "stderr");
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering return dup2(socket_fd, fileno) < 0 ? -errno : fileno;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering assert_not_reached("Unknown error type");
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poetteringstatic int chown_terminal(int fd, uid_t uid) {
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering /* This might fail. What matters are the results. */
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering if (st.st_uid != uid || (st.st_mode & 0777) != TTY_MODE)
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poetteringstatic int setup_confirm_stdio(int *_saved_stdin,
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering int fd = -1, saved_stdin, saved_stdout = -1, r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering saved_stdin = fcntl(STDIN_FILENO, F_DUPFD, 3);
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering saved_stdout = fcntl(STDOUT_FILENO, F_DUPFD, 3);
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers_printf_(1, 2) static int write_confirm_message(const char *format, ...) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sieversstatic int restore_confirm_stdio(int *saved_stdin,
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersenstatic int ask_for_confirmation(char *response, char **argv) {
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering int saved_stdout = -1, saved_stdin = -1, r;
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering r = setup_confirm_stdio(&saved_stdin, &saved_stdout);
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering r = ask_char(response, "yns", "Execute %s? [Yes, No, Skip] ", line);
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers restore_confirm_stdio(&saved_stdin, &saved_stdout);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic int enforce_groups(const ExecContext *context, const char *username, gid_t gid) {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen /* Lookup and set GID and supplementary group list. Here too
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen * we avoid NSS lookups for gid=0. */
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen /* First step, initialize groups from /etc/groups */
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering /* Second step, set our gids */
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering /* Final step, initialize any manually set supplementary groups */
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering assert_se((ngroups_max = (int) sysconf(_SC_NGROUPS_MAX)) > 0);
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering STRV_FOREACH(i, context->supplementary_groups) {
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering const char *g;
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poetteringstatic int enforce_user(const ExecContext *context, uid_t uid) {
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering /* Sets (but doesn't lookup) the uid and make sure we keep the
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering * capabilities while doing so. */
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering CAP_SETUID, /* Necessary so that we can run setresuid() below */
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering CAP_SETPCAP /* Necessary so that we can set PR_SET_SECUREBITS later on */
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering /* First step: If we need to keep capabilities but
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering * drop privileges we need to make sure we keep our
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering * caps, while we drop privileges. */
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering int sb = context->secure_bits | 1<<SECURE_KEEP_CAPS;
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering /* Second step: set the capabilities. This will reduce
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering * the capabilities to the minimum we need. */
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering if (cap_set_flag(d, CAP_EFFECTIVE, ELEMENTSOF(bits), bits, CAP_SET) < 0 ||
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering cap_set_flag(d, CAP_PERMITTED, ELEMENTSOF(bits), bits, CAP_SET) < 0)
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering /* Third step: actually set the uids */
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering /* At this point we should have all necessary capabilities but
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering are otherwise a normal user. However, the caps might got
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering corrupted due to the setresuid() so we need clean them up
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering later. This is done outside of this call. */
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering /* We don't support conversations */
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering /* We set up PAM in the parent process, then fork. The child
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering * will then stay around until killed via PR_GET_PDEATHSIG or
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart 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 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);
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering /* Block SIGTERM, so that we know that it won't get lost in
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering * the child */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert_se(sigprocmask_many(SIG_BLOCK, &old_ss, SIGTERM, -1) >= 0);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* The child's job is to reset the PAM session on
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * termination */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* This string must fit in 10 chars (i.e. the length
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * of "/sbin/init"), to look pretty in /bin/ps */
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering /* Make sure we don't keep open the passed fds in this
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering child. We assume that otherwise only those fds are
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering open here that have been opened by PAM. */
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering /* Drop privileges - we don't need any to pam_close_session
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering * and this will make PR_SET_PDEATHSIG work in most cases.
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen * If this fails, ignore the error - but expect sd-pam threads
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen * to fail to exit normally */
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen log_error_errno(r, "Error: Failed to setresuid() in sd-pam: %m");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* Wait until our parent died. This will only work if
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * the above setresuid() succeeds, otherwise the kernel
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering * will not allow unprivileged parents kill their privileged
1dba654b27918c22e413ac5b3c19301f1ff86ad2Lennart Poettering * children this way. We rely on the control groups kill logic
1dba654b27918c22e413ac5b3c19301f1ff86ad2Lennart Poettering * to do the rest for us. */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* Check if our parent process might already have
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering /* If our parent died we'll end the session */
1dba654b27918c22e413ac5b3c19301f1ff86ad2Lennart Poettering pam_code = pam_close_session(handle, flags);
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering /* If the child was forked off successfully it will do all the
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering * cleanups, so forget about the handle here. */
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering /* Unblock SIGTERM again in the parent */
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering assert_se(sigprocmask(SIG_SETMASK, &old_ss, NULL) >= 0);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering /* We close the log explicitly here, since the PAM modules
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering * might have opened it, but we don't want this fd around. */
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering log_error("PAM failed: %s", pam_strerror(handle, pam_code));
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering err = -EPERM; /* PAM errors do not map to errno */
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering log_error_errno(errno, "PAM failed: %m");
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering pam_code = pam_close_session(handle, flags);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poetteringstatic void rename_process_from_path(const char *path) {
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering const char *p;
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering /* This resulting string must fit in 10 chars (i.e. the length
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering * of "/sbin/init") to look pretty in /bin/ps */
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering /* The end of the process name is usually more
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering * interesting, since the first bit might just be
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering * "systemd-" */
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering p = p + l - 8;
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poetteringstatic int apply_seccomp(const ExecContext *c) {
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering negative_action = c->syscall_errno == 0 ? SCMP_ACT_KILL : SCMP_ACT_ERRNO(c->syscall_errno);
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering seccomp = seccomp_init(c->syscall_whitelist ? negative_action : SCMP_ACT_ALLOW);
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering r = seccomp_arch_add(seccomp, PTR_TO_UINT32(id) - 1);
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering r = seccomp_add_secondary_archs(seccomp);
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering action = c->syscall_whitelist ? SCMP_ACT_ALLOW : negative_action;
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering r = seccomp_rule_add(seccomp, action, PTR_TO_INT(id) - 1, 0);
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering r = seccomp_attr_set(seccomp, SCMP_FLTATR_CTL_NNP, 0);
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poetteringstatic int apply_address_families(const ExecContext *c) {
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering r = seccomp_add_secondary_archs(seccomp);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering /* If this is a whitelist, we first block the address
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering * families that are out of range and then everything
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering * that is not in the set. First, we find the lowest
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering * and highest address family in the set. */
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering SET_FOREACH(afp, c->address_families, i) {
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering /* No entries in the valid range, block everything */
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering /* Block everything below the first entry */
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering /* Block everything above the last entry */
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering /* Block everything between the first and last
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering if (set_contains(c->address_families, INT_TO_PTR(af)))
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering /* If this is a blacklist, then generate one rule for
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering * each address family that are then combined in OR
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering SET_FOREACH(af, c->address_families, i) {
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering r = seccomp_attr_set(seccomp, SCMP_FLTATR_CTL_NNP, 0);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poetteringstatic void do_idle_pipe_dance(int idle_pipe[4]) {
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering r = fd_wait_for_event(idle_pipe[0], POLLHUP, IDLE_TIMEOUT_USEC);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering if (idle_pipe[3] >= 0 && r == 0 /* timeout */) {
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering /* Signal systemd that we are bored and want to continue. */
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering /* Wait for systemd to react to the signal above. */
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering fd_wait_for_event(idle_pipe[0], POLLHUP, IDLE_TIMEOUT2_USEC);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering _cleanup_strv_free_ char **our_env = NULL;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering if (asprintf(&x, "LISTEN_PID="PID_FMT, getpid()) < 0)
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering if (asprintf(&x, "LISTEN_FDS=%u", n_fds) < 0)
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering if (asprintf(&x, "WATCHDOG_PID="PID_FMT, getpid()) < 0)
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering if (asprintf(&x, "WATCHDOG_USEC="USEC_FMT, watchdog_usec) < 0)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering x = strdup(default_term_for_tty(tty_path(c)));
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering if (!strv_isempty(context->read_write_dirs) ||
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering !strv_isempty(context->read_only_dirs) ||
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering if (context->private_tmp && runtime && (runtime->tmp_dir || runtime->var_tmp_dir))
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering context->protect_system != PROTECT_SYSTEM_NO ||
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering context->protect_home != PROTECT_HOME_NO)
d04c1fb8e215600b4950c6778c6c16ddafc14024Lennart Poettering _cleanup_strv_free_ char **our_env = NULL, **pam_env = NULL, **final_env = NULL, **final_argv = NULL;
d04c1fb8e215600b4950c6778c6c16ddafc14024Lennart Poettering _cleanup_free_ char *mac_selinux_context_net = NULL;
40205d706e1210763ff4c98a317556375bd04bcdLennart Poettering const char *username = NULL, *home = NULL, *shell = NULL;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering /* We reset exactly these signals, since they are the
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering * only ones we set to SIG_IGN in the main daemon. All
9b15b7846d4de01bb5d9700a24077787e984e8abLennart Poettering * others we leave untouched because we set them to
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt * SIG_DFL or a valid handler initially, both of which
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt * will be demoted to SIG_DFL. */
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering (void) default_signals(SIGNALS_CRASH_HANDLER,
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering /* Close sockets very early to make sure we don't
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering * block init reexecution because it cannot bind its
086821244b5113f00a0ef993b78dc56aae2a8f6cLennart Poettering memcpy(dont_close + n_dont_close, fds, sizeof(int) * n_fds);
086821244b5113f00a0ef993b78dc56aae2a8f6cLennart Poettering dont_close[n_dont_close++] = params->bus_endpoint_fd;
086821244b5113f00a0ef993b78dc56aae2a8f6cLennart Poettering if (runtime->netns_storage_socket[0] >= 0)
086821244b5113f00a0ef993b78dc56aae2a8f6cLennart Poettering dont_close[n_dont_close++] = runtime->netns_storage_socket[0];
086821244b5113f00a0ef993b78dc56aae2a8f6cLennart Poettering if (runtime->netns_storage_socket[1] >= 0)
086821244b5113f00a0ef993b78dc56aae2a8f6cLennart Poettering dont_close[n_dont_close++] = runtime->netns_storage_socket[1];
086821244b5113f00a0ef993b78dc56aae2a8f6cLennart Poettering r = close_all_fds(dont_close, n_dont_close);
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering r = ask_for_confirmation(&response, argv);
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering write_confirm_message("Confirmation question timed out, assuming positive response.\n");
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering else if (r < 0)
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering write_confirm_message("Couldn't ask confirmation question, assuming positive response: %s\n", strerror(-r));
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering write_confirm_message("Skipping execution.\n");
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering write_confirm_message("Failing execution.\n");
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering r = get_user_creds(&username, &uid, &gid, &home, &shell);
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering /* If a socket is connected to STDIN/STDOUT/STDERR, we
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering * must sure to drop O_NONBLOCK */
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering r = setup_input(context, socket_fd, params->apply_tty_stdin);
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering r = setup_output(unit, context, STDOUT_FILENO, socket_fd, basename(command->path), params->apply_tty_stdin, uid, gid);
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering r = setup_output(unit, context, STDERR_FILENO, socket_fd, basename(command->path), params->apply_tty_stdin, uid, gid);
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering r = cg_attach_everywhere(params->cgroup_supported, params->cgroup_path, 0, NULL, NULL);
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering char t[DECIMAL_STR_MAX(context->oom_score_adjust)];
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering /* When we can't make this change due to EPERM, then
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering * let's silently skip over it. User namespaces
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering * prohibit write access to this file, and we
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering * shouldn't trip up over that. */
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering sprintf(t, "%i", context->oom_score_adjust);
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering r = write_string_file("/proc/self/oom_score_adj", t, 0);
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering log_unit_debug_errno(unit, r, "Failed to adjust OOM setting, assuming containerized execution, ignoring: %m");
ebd011d95b61a86258dece9864f65b7c4af721c0Lennart Poettering } else if (r < 0) {
ebd011d95b61a86258dece9864f65b7c4af721c0Lennart Poettering if (setpriority(PRIO_PROCESS, 0, context->nice) < 0) {
ebd011d95b61a86258dece9864f65b7c4af721c0Lennart Poettering .sched_priority = context->cpu_sched_priority,
ebd011d95b61a86258dece9864f65b7c4af721c0Lennart Poettering if (sched_setaffinity(0, CPU_ALLOC_SIZE(context->cpuset_ncpus), context->cpuset) < 0) {
ebd011d95b61a86258dece9864f65b7c4af721c0Lennart Poettering if (ioprio_set(IOPRIO_WHO_PROCESS, 0, context->ioprio) < 0) {
ebd011d95b61a86258dece9864f65b7c4af721c0Lennart Poettering if (context->timer_slack_nsec != NSEC_INFINITY)
ebd011d95b61a86258dece9864f65b7c4af721c0Lennart Poettering if (prctl(PR_SET_TIMERSLACK, context->timer_slack_nsec) < 0) {
ebd011d95b61a86258dece9864f65b7c4af721c0Lennart Poettering if (context->personality != PERSONALITY_INVALID)
ebd011d95b61a86258dece9864f65b7c4af721c0Lennart Poettering if (personality(context->personality) < 0) {
ebd011d95b61a86258dece9864f65b7c4af721c0Lennart Poettering utmp_put_init_process(context->utmp_id, getpid(), getsid(0), context->tty_path,
ebd011d95b61a86258dece9864f65b7c4af721c0Lennart Poettering context->utmp_mode == EXEC_UTMP_INIT ? INIT_PROCESS :
ebd011d95b61a86258dece9864f65b7c4af721c0Lennart Poettering context->utmp_mode == EXEC_UTMP_LOGIN ? LOGIN_PROCESS :
ebd011d95b61a86258dece9864f65b7c4af721c0Lennart Poettering if (context->user && is_terminal_input(context->std_input)) {
ebd011d95b61a86258dece9864f65b7c4af721c0Lennart Poettering if (params->bus_endpoint_fd >= 0 && context->bus_endpoint) {
ebd011d95b61a86258dece9864f65b7c4af721c0Lennart Poettering uid_t ep_uid = (uid == UID_INVALID) ? 0 : uid;
d8f52ed25a9edce75fda5251c977b7898e33887eLennart Poettering r = 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 r = cg_set_task_access(SYSTEMD_CGROUP_CONTROLLER, params->cgroup_path, 0644, uid, gid);
d8f52ed25a9edce75fda5251c977b7898e33887eLennart Poettering r = cg_set_group_access(SYSTEMD_CGROUP_CONTROLLER, params->cgroup_path, 0755, uid, gid);
d8f52ed25a9edce75fda5251c977b7898e33887eLennart Poettering if (!strv_isempty(context->runtime_directory) && params->runtime_prefix) {
d8f52ed25a9edce75fda5251c977b7898e33887eLennart Poettering STRV_FOREACH(rt, context->runtime_directory) {
d8f52ed25a9edce75fda5251c977b7898e33887eLennart Poettering p = strjoin(params->runtime_prefix, "/", *rt, NULL);
d8f52ed25a9edce75fda5251c977b7898e33887eLennart Poettering r = mkdir_p_label(p, context->runtime_directory_mode);
d8f52ed25a9edce75fda5251c977b7898e33887eLennart Poettering r = chmod_and_chown(p, context->runtime_directory_mode, uid, gid);
d8f52ed25a9edce75fda5251c977b7898e33887eLennart Poettering r = enforce_groups(context, username, gid);
d8f52ed25a9edce75fda5251c977b7898e33887eLennart Poettering if (params->apply_permissions && context->pam_name && username) {
d8f52ed25a9edce75fda5251c977b7898e33887eLennart Poettering r = setup_pam(context->pam_name, username, uid, context->tty_path, &pam_env, fds, n_fds);
d8f52ed25a9edce75fda5251c977b7898e33887eLennart Poettering if (context->private_network && runtime && runtime->netns_storage_socket[0] >= 0) {
d8f52ed25a9edce75fda5251c977b7898e33887eLennart Poettering r = setup_netns(runtime->netns_storage_socket);
d8f52ed25a9edce75fda5251c977b7898e33887eLennart Poettering needs_mount_namespace = exec_needs_mount_namespace(context, params, runtime);
d8f52ed25a9edce75fda5251c977b7898e33887eLennart Poettering /* The runtime struct only contains the parent
d8f52ed25a9edce75fda5251c977b7898e33887eLennart Poettering * of the private /tmp, which is
d8f52ed25a9edce75fda5251c977b7898e33887eLennart Poettering * non-accessible to world users. Inside of it
d8f52ed25a9edce75fda5251c977b7898e33887eLennart Poettering * there's a /tmp that is sticky, and that's
d8f52ed25a9edce75fda5251c977b7898e33887eLennart Poettering * the one we want to use here. */
d8f52ed25a9edce75fda5251c977b7898e33887eLennart Poettering tmp = strjoina(runtime->tmp_dir, "/tmp");
d8f52ed25a9edce75fda5251c977b7898e33887eLennart Poettering var = strjoina(runtime->var_tmp_dir, "/tmp");
d8f52ed25a9edce75fda5251c977b7898e33887eLennart Poettering params->apply_chroot ? context->root_directory : NULL,
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering /* If we couldn't set up the namespace this is
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering * probably due to a missing capability. In this case,
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering * silently proceeed. */
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering log_unit_debug_errno(unit, r, "Failed to set up namespace, assuming containerized execution, ignoring: %m");
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering } else if (r < 0) {
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering if (!needs_mount_namespace && context->root_directory)
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering if (chroot(context->root_directory) < 0) {
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering if (chdir(context->working_directory ?: "/") < 0 &&
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering !context->working_directory_missing_ok) {
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering !context->working_directory_missing_ok) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (params->apply_permissions && mac_selinux_use() && params->selinux_context_net && socket_fd >= 0) {
e56056e93d33619a3acf13e483900b4f8938228fThomas Hindoe Paaboel Andersen r = mac_selinux_get_child_mls_label(socket_fd, command->path, context->selinux_context, &mac_selinux_context_net);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* We repeat the fd closing here, to make sure that
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * nothing is leaked from the PAM modules. Note that
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * we are more aggressive this time since socket_fd
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * and the netns fds we don't need anymore. The custom
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * endpoint fd was needed to upload the policy and can
e56056e93d33619a3acf13e483900b4f8938228fThomas Hindoe Paaboel Andersen * now be closed as well. */
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering r = flags_fds(fds, n_fds, context->non_blocking);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering for (i = 0; i < _RLIMIT_MAX; i++) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (setrlimit_closest(i, context->rlimit[i]) < 0) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (context->capability_bounding_set_drop) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = capability_bounding_set_drop(context->capability_bounding_set_drop, false);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = mac_smack_apply_pid(0, context->smack_process_label);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = mac_smack_read(command->path, SMACK_ATTR_EXEC, &exec_label);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (r < 0 && r != -ENODATA && r != -EOPNOTSUPP) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = mac_smack_apply_pid(0, exec_label ? : SMACK_DEFAULT_PROCESS_LABEL);
e56056e93d33619a3acf13e483900b4f8938228fThomas Hindoe Paaboel Andersen *exit_status = EXIT_SMACK_PROCESS_LABEL;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* PR_GET_SECUREBITS is not privileged, while
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * PR_SET_SECUREBITS is. So to suppress
d21ed1ead18d16d35c30299a69d3366847f8a039Lennart Poettering * potential EPERMs we'll try not to call
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering * PR_SET_SECUREBITS unless necessary. */
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering if (prctl(PR_GET_SECUREBITS) != context->secure_bits)
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering if (prctl(PR_SET_SECUREBITS, context->secure_bits) < 0) {
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering if (cap_set_proc(context->capabilities) < 0) {
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (context->address_families_whitelist ||
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering !set_isempty(context->address_families)) {
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering char *exec_context = mac_selinux_context_net ?: context->selinux_context;
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering if (context->apparmor_profile && mac_apparmor_use()) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = aa_change_onexec(context->apparmor_profile);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (r < 0 && !context->apparmor_profile_ignore) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = build_environment(context, n_fds, params->watchdog_usec, home, username, shell, &our_env);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering final_argv = replace_env_argv(argv, final_env);
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();
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;
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 *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)
return NULL;
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(Unit *u, ExecRuntime **rt, const char *key, const char *value, FDSet *fds) {
char *copy;
return log_oom();
if (!copy)
return log_oom();
char *copy;
return log_oom();
if (!copy)
return log_oom();
int fd;
return log_oom();
int fd;
return log_oom();
static void *remove_tmpdir_thread(void *p) {
return NULL;
if (!rt)