chiark / gitweb /
core: general cgroup rework
[elogind.git] / src / core / execute.c
index 18e25fa6e69dd14ad7cf3dae0dde69b53da3195c..5e342f8d47af71fdf1afb3faeb7a38eb9c5d69b5 100644 (file)
@@ -40,6 +40,7 @@
 #include <sys/poll.h>
 #include <linux/seccomp-bpf.h>
 #include <glob.h>
+#include <libgen.h>
 
 #ifdef HAVE_PAM
 #include <security/pam_appl.h>
@@ -54,7 +55,6 @@
 #include "sd-messages.h"
 #include "ioprio.h"
 #include "securebits.h"
-#include "cgroup.h"
 #include "namespace.h"
 #include "tcpwrap.h"
 #include "exit-status.h"
@@ -66,6 +66,7 @@
 #include "syscall-list.h"
 #include "env-util.h"
 #include "fileio.h"
+#include "unit.h"
 
 #define IDLE_TIMEOUT_USEC (5*USEC_PER_SEC)
 
@@ -143,7 +144,7 @@ static int flags_fds(const int fds[], unsigned n_fds, bool nonblock) {
         return 0;
 }
 
-static const char *tty_path(const ExecContext *context) {
+_pure_ static const char *tty_path(const ExecContext *context) {
         assert(context);
 
         if (context->tty_path)
@@ -204,7 +205,10 @@ static int open_null_as(int flags, int nfd) {
 
 static int connect_logger_as(const ExecContext *context, ExecOutput output, const char *ident, const char *unit_id, int nfd) {
         int fd, r;
-        union sockaddr_union sa;
+        union sockaddr_union sa = {
+                .un.sun_family = AF_UNIX,
+                .un.sun_path = "/run/systemd/journal/stdout",
+        };
 
         assert(context);
         assert(output < _EXEC_OUTPUT_MAX);
@@ -215,10 +219,6 @@ static int connect_logger_as(const ExecContext *context, ExecOutput output, cons
         if (fd < 0)
                 return -errno;
 
-        zero(sa);
-        sa.un.sun_family = AF_UNIX;
-        strncpy(sa.un.sun_path, "/run/systemd/journal/stdout", sizeof(sa.un.sun_path));
-
         r = connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path));
         if (r < 0) {
                 close_nointr_nofail(fd);
@@ -509,7 +509,7 @@ fail:
         return r;
 }
 
-static int write_confirm_message(const char *format, ...) {
+_printf_attr_(1, 2) static int write_confirm_message(const char *format, ...) {
         int fd;
         va_list ap;
 
@@ -670,9 +670,9 @@ static int enforce_user(const ExecContext *context, uid_t uid) {
 
                 /* First step: If we need to keep capabilities but
                  * drop privileges we need to make sure we keep our
-                 * caps, whiel we drop privileges. */
+                 * caps, while we drop privileges. */
                 if (uid != 0) {
-                        int sb = context->secure_bits|SECURE_KEEP_CAPS;
+                        int sb = context->secure_bits | 1<<SECURE_KEEP_CAPS;
 
                         if (prctl(PR_GET_SECUREBITS) != sb)
                                 if (prctl(PR_SET_SECUREBITS, sb) < 0)
@@ -937,7 +937,7 @@ static int apply_seccomp(uint32_t *syscall_filter) {
         int i;
         unsigned n;
         struct sock_filter *f;
-        struct sock_fprog prog;
+        struct sock_fprog prog = {};
 
         assert(syscall_filter);
 
@@ -969,7 +969,6 @@ static int apply_seccomp(uint32_t *syscall_filter) {
         memcpy(f + (ELEMENTSOF(header) + 2*n), footer, sizeof(footer));
 
         /* Third: install the filter */
-        zero(prog);
         prog.len = ELEMENTSOF(header) + ELEMENTSOF(footer) + 2*n;
         prog.filter = f;
         if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) < 0)
@@ -987,18 +986,17 @@ int exec_spawn(ExecCommand *command,
                bool apply_chroot,
                bool apply_tty_stdin,
                bool confirm_spawn,
-               CGroupBonding *cgroup_bondings,
-               CGroupAttribute *cgroup_attributes,
-               const char *cgroup_suffix,
+               CGroupControllerMask cgroup_mask,
+               const char *cgroup_path,
                const char *unit_id,
                int idle_pipe[2],
                pid_t *ret) {
 
+        _cleanup_strv_free_ char **files_env = NULL;
+        int socket_fd;
+        char *line;
         pid_t pid;
         int r;
-        char *line;
-        int socket_fd;
-        char _cleanup_strv_free_ **files_env = NULL;
 
         assert(command);
         assert(context);
@@ -1037,17 +1035,12 @@ int exec_spawn(ExecCommand *command,
                 return log_oom();
 
         log_struct_unit(LOG_DEBUG,
-                   unit_id,
-                   "MESSAGE=About to execute %s", line,
-                   NULL);
+                        unit_id,
+                        "EXECUTABLE=%s", command->path,
+                        "MESSAGE=About to execute: %s", line,
+                        NULL);
         free(line);
 
-        r = cgroup_bonding_realize_list(cgroup_bondings);
-        if (r < 0)
-                return r;
-
-        cgroup_attribute_apply_list(cgroup_attributes, cgroup_bondings);
-
         if (context->private_tmp && !context->tmp_dir && !context->var_tmp_dir) {
                 r = setup_tmpdirs(&context->tmp_dir, &context->var_tmp_dir);
                 if (r < 0)
@@ -1064,10 +1057,9 @@ int exec_spawn(ExecCommand *command,
                 const char *username = NULL, *home = NULL;
                 uid_t uid = (uid_t) -1;
                 gid_t gid = (gid_t) -1;
-                char _cleanup_strv_free_ **our_env = NULL, **pam_env = NULL,
+                _cleanup_strv_free_ char **our_env = NULL, **pam_env = NULL,
                         **final_env = NULL, **final_argv = NULL;
                 unsigned n_env = 0;
-                bool set_access = false;
 
                 /* child */
 
@@ -1180,8 +1172,8 @@ int exec_spawn(ExecCommand *command,
                         goto fail_child;
                 }
 
-                if (cgroup_bondings) {
-                        err = cgroup_bonding_install_list(cgroup_bondings, 0, cgroup_suffix);
+                if (cgroup_path) {
+                        err = cg_attach_with_mask(cgroup_mask, cgroup_path, 0);
                         if (err < 0) {
                                 r = EXIT_CGROUP;
                                 goto fail_child;
@@ -1194,7 +1186,7 @@ int exec_spawn(ExecCommand *command,
                         snprintf(t, sizeof(t), "%i", context->oom_score_adjust);
                         char_array_0(t);
 
-                        if (write_one_line_file("/proc/self/oom_score_adj", t) < 0) {
+                        if (write_string_file("/proc/self/oom_score_adj", t) < 0) {
                                 err = -errno;
                                 r = EXIT_OOM_ADJUST;
                                 goto fail_child;
@@ -1209,13 +1201,16 @@ int exec_spawn(ExecCommand *command,
                         }
 
                 if (context->cpu_sched_set) {
-                        struct sched_param param;
-
-                        zero(param);
-                        param.sched_priority = context->cpu_sched_priority;
+                        struct sched_param param = {
+                                .sched_priority = context->cpu_sched_priority,
+                        };
 
-                        if (sched_setscheduler(0, context->cpu_sched_policy |
-                                               (context->cpu_sched_reset_on_fork ? SCHED_RESET_ON_FORK : 0), &param) < 0) {
+                        r = sched_setscheduler(0,
+                                               context->cpu_sched_policy |
+                                               (context->cpu_sched_reset_on_fork ?
+                                                SCHED_RESET_ON_FORK : 0),
+                                               &param);
+                        if (r < 0) {
                                 err = -errno;
                                 r = EXIT_SETSCHEDULER;
                                 goto fail_child;
@@ -1261,26 +1256,6 @@ int exec_spawn(ExecCommand *command,
                                         goto fail_child;
                                 }
                         }
-
-                        if (cgroup_bondings && context->control_group_modify) {
-                                err = cgroup_bonding_set_group_access_list(cgroup_bondings, 0755, uid, gid);
-                                if (err >= 0)
-                                        err = cgroup_bonding_set_task_access_list(cgroup_bondings, 0644, uid, gid, context->control_group_persistent);
-                                if (err < 0) {
-                                        r = EXIT_CGROUP;
-                                        goto fail_child;
-                                }
-
-                                set_access = true;
-                        }
-                }
-
-                if (cgroup_bondings && !set_access && context->control_group_persistent >= 0)  {
-                        err = cgroup_bonding_set_task_access_list(cgroup_bondings, (mode_t) -1, (uid_t) -1, (uid_t) -1, context->control_group_persistent);
-                        if (err < 0) {
-                                r = EXIT_CGROUP;
-                                goto fail_child;
-                        }
                 }
 
                 if (apply_permissions) {
@@ -1344,7 +1319,7 @@ int exec_spawn(ExecCommand *command,
                                 goto fail_child;
                         }
                 } else {
-                        char _cleanup_free_ *d = NULL;
+                        _cleanup_free_ char *d = NULL;
 
                         if (asprintf(&d, "%s/%s",
                                      context->root_directory ? context->root_directory : "",
@@ -1436,7 +1411,8 @@ int exec_spawn(ExecCommand *command,
                         }
                 }
 
-                if (!(our_env = new0(char*, 7))) {
+                our_env = new0(char*, 7);
+                if (!our_env) {
                         err = -ENOMEM;
                         r = EXIT_MEMORY;
                         goto fail_child;
@@ -1476,20 +1452,21 @@ int exec_spawn(ExecCommand *command,
 
                 assert(n_env <= 7);
 
-                if (!(final_env = strv_env_merge(
-                                      5,
-                                      environment,
-                                      our_env,
-                                      context->environment,
-                                      files_env,
-                                      pam_env,
-                                      NULL))) {
+                final_env = strv_env_merge(5,
+                                           environment,
+                                           our_env,
+                                           context->environment,
+                                           files_env,
+                                           pam_env,
+                                           NULL);
+                if (!final_env) {
                         err = -ENOMEM;
                         r = EXIT_MEMORY;
                         goto fail_child;
                 }
 
-                if (!(final_argv = replace_env_argv(argv, final_env))) {
+                final_argv = replace_env_argv(argv, final_env);
+                if (!final_argv) {
                         err = -ENOMEM;
                         r = EXIT_MEMORY;
                         goto fail_child;
@@ -1497,6 +1474,20 @@ int exec_spawn(ExecCommand *command,
 
                 final_env = strv_env_clean(final_env);
 
+                if (_unlikely_(log_get_max_level() >= LOG_PRI(LOG_DEBUG))) {
+                        line = exec_command_line(final_argv);
+                        if (line) {
+                                log_open();
+                                log_struct_unit(LOG_DEBUG,
+                                                unit_id,
+                                                "EXECUTABLE=%s", command->path,
+                                                "MESSAGE=Executing: %s", line,
+                                                NULL);
+                                log_close();
+                                free(line);
+                                line = NULL;
+                        }
+                }
                 execve(command->path, final_argv, final_env);
                 err = -errno;
                 r = EXIT_EXEC;
@@ -1518,18 +1509,18 @@ int exec_spawn(ExecCommand *command,
         }
 
         log_struct_unit(LOG_DEBUG,
-                   unit_id,
-                   "MESSAGE=Forked %s as %lu",
-                          command->path, (unsigned long) pid,
-                   NULL);
+                        unit_id,
+                        "MESSAGE=Forked %s as %lu",
+                        command->path, (unsigned long) pid,
+                        NULL);
 
         /* We add the new process to the cgroup both in the child (so
          * that we can be sure that no user code is ever executed
          * outside of the cgroup) and in the parent (so that we can be
          * sure that when we kill the cgroup the process will be
          * killed too). */
-        if (cgroup_bondings)
-                cgroup_bonding_install_list(cgroup_bondings, pid, cgroup_suffix);
+        if (cgroup_path)
+                cg_attach(SYSTEMD_CGROUP_CONTROLLER, cgroup_path, pid);
 
         exec_status_start(&command->exec_status, pid);
 
@@ -1545,25 +1536,36 @@ void exec_context_init(ExecContext *c) {
         c->cpu_sched_policy = SCHED_OTHER;
         c->syslog_priority = LOG_DAEMON|LOG_INFO;
         c->syslog_level_prefix = true;
-        c->control_group_persistent = -1;
         c->ignore_sigpipe = true;
         c->timer_slack_nsec = (nsec_t) -1;
 }
 
 void exec_context_tmp_dirs_done(ExecContext *c) {
-        assert(c);
+        char* dirs[] = {c->tmp_dir ? c->tmp_dir : c->var_tmp_dir,
+                        c->tmp_dir ? c->var_tmp_dir : NULL,
+                        NULL};
+        char **dirp;
 
-        if (c->tmp_dir) {
-                rm_rf_dangerous(c->tmp_dir, false, true, false);
-                free(c->tmp_dir);
-                c->tmp_dir = NULL;
-        }
+        for(dirp = dirs; *dirp; dirp++) {
+                char *dir;
+                int r;
 
-        if (c->var_tmp_dir) {
-                rm_rf_dangerous(c->var_tmp_dir, false, true, false);
-                free(c->var_tmp_dir);
-                c->var_tmp_dir = NULL;
+                r = rm_rf_dangerous(*dirp, false, true, false);
+                dir = dirname(*dirp);
+                if (r < 0)
+                        log_warning("Failed to remove content of temporary directory %s: %s",
+                                    dir, strerror(-r));
+                else {
+                        r = rmdir(dir);
+                        if (r < 0)
+                                log_warning("Failed to remove  temporary directory %s: %s",
+                                            dir, strerror(-r));
+                }
+
+                free(*dirp);
         }
+
+        c->tmp_dir = c->var_tmp_dir = NULL;
 }
 
 void exec_context_done(ExecContext *c, bool reloading_or_reexecuting) {
@@ -1682,7 +1684,7 @@ int exec_context_load_environment(const ExecContext *c, char ***l) {
                 int k;
                 bool ignore = false;
                 char **p;
-                glob_t pglob;
+                _cleanup_globfree_ glob_t pglob = {};
                 int count, n;
 
                 fn = *i;
@@ -1693,7 +1695,6 @@ int exec_context_load_environment(const ExecContext *c, char ***l) {
                 }
 
                 if (!path_is_absolute(fn)) {
-
                         if (ignore)
                                 continue;
 
@@ -1702,10 +1703,8 @@ int exec_context_load_environment(const ExecContext *c, char ***l) {
                 }
 
                 /* Filename supports globbing, take all matching files */
-                zero(pglob);
                 errno = 0;
                 if (glob(fn, 0, NULL, &pglob) != 0) {
-                        globfree(&pglob);
                         if (ignore)
                                 continue;
 
@@ -1714,7 +1713,6 @@ int exec_context_load_environment(const ExecContext *c, char ***l) {
                 }
                 count = pglob.gl_pathc;
                 if (count == 0) {
-                        globfree(&pglob);
                         if (ignore)
                                 continue;
 
@@ -1722,15 +1720,17 @@ int exec_context_load_environment(const ExecContext *c, char ***l) {
                         return -EINVAL;
                 }
                 for (n = 0; n < count; n++) {
-                        k = load_env_file(pglob.gl_pathv[n], &p);
+                        k = load_env_file(pglob.gl_pathv[n], NULL, &p);
                         if (k < 0) {
                                 if (ignore)
                                         continue;
 
                                 strv_free(r);
-                                globfree(&pglob);
                                 return k;
                          }
+                        /* Log invalid environment variables with filename */
+                       if (p)
+                               p = strv_env_clean_log(p, pglob.gl_pathv[n]);
 
                         if (r == NULL)
                                 r = p;
@@ -1740,16 +1740,12 @@ int exec_context_load_environment(const ExecContext *c, char ***l) {
                                 m = strv_env_merge(2, r, p);
                                 strv_free(r);
                                 strv_free(p);
-
-                                if (!m) {
-                                        globfree(&pglob);
+                                if (!m)
                                         return -ENOMEM;
-                                }
 
                                 r = m;
                         }
                 }
-                globfree(&pglob);
         }
 
         *l = r;
@@ -1798,14 +1794,13 @@ static void strv_fprintf(FILE *f, char **l) {
 }
 
 void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
-        char ** e;
+        char **e;
         unsigned i;
 
         assert(c);
         assert(f);
 
-        if (!prefix)
-                prefix = "";
+        prefix = strempty(prefix);
 
         fprintf(f,
                 "%sUMask: %04o\n"
@@ -1813,8 +1808,6 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
                 "%sRootDirectory: %s\n"
                 "%sNonBlocking: %s\n"
                 "%sPrivateTmp: %s\n"
-                "%sControlGroupModify: %s\n"
-                "%sControlGroupPersistent: %s\n"
                 "%sPrivateNetwork: %s\n"
                 "%sIgnoreSIGPIPE: %s\n",
                 prefix, c->umask,
@@ -1822,8 +1815,6 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
                 prefix, c->root_directory ? c->root_directory : "/",
                 prefix, yes_no(c->non_blocking),
                 prefix, yes_no(c->private_tmp),
-                prefix, yes_no(c->control_group_modify),
-                prefix, yes_no(c->control_group_persistent),
                 prefix, yes_no(c->private_network),
                 prefix, yes_no(c->ignore_sigpipe));
 
@@ -1950,12 +1941,12 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
         if (c->secure_bits)
                 fprintf(f, "%sSecure Bits:%s%s%s%s%s%s\n",
                         prefix,
-                        (c->secure_bits & SECURE_KEEP_CAPS) ? " keep-caps" : "",
-                        (c->secure_bits & SECURE_KEEP_CAPS_LOCKED) ? " keep-caps-locked" : "",
-                        (c->secure_bits & SECURE_NO_SETUID_FIXUP) ? " no-setuid-fixup" : "",
-                        (c->secure_bits & SECURE_NO_SETUID_FIXUP_LOCKED) ? " no-setuid-fixup-locked" : "",
-                        (c->secure_bits & SECURE_NOROOT) ? " noroot" : "",
-                        (c->secure_bits & SECURE_NOROOT_LOCKED) ? "noroot-locked" : "");
+                        (c->secure_bits & 1<<SECURE_KEEP_CAPS) ? " keep-caps" : "",
+                        (c->secure_bits & 1<<SECURE_KEEP_CAPS_LOCKED) ? " keep-caps-locked" : "",
+                        (c->secure_bits & 1<<SECURE_NO_SETUID_FIXUP) ? " no-setuid-fixup" : "",
+                        (c->secure_bits & 1<<SECURE_NO_SETUID_FIXUP_LOCKED) ? " no-setuid-fixup-locked" : "",
+                        (c->secure_bits & 1<<SECURE_NOROOT) ? " noroot" : "",
+                        (c->secure_bits & 1<<SECURE_NOROOT_LOCKED) ? "noroot-locked" : "");
 
         if (c->capability_bounding_set_drop) {
                 unsigned long l;