]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/core/execute.c
Rename formats-util.h to format-util.h
[thirdparty/systemd.git] / src / core / execute.c
index 642add03609137b813c9e964b642fe65e4c8866f..c1cda6b5a14066140be7d220c37004695ae1990c 100644 (file)
 #include <sys/mman.h>
 #include <sys/personality.h>
 #include <sys/prctl.h>
+#include <sys/shm.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
+#include <sys/types.h>
 #include <sys/un.h>
 #include <unistd.h>
 #include <utmpx.h>
@@ -69,7 +71,7 @@
 #include "exit-status.h"
 #include "fd-util.h"
 #include "fileio.h"
-#include "formats-util.h"
+#include "format-util.h"
 #include "fs-util.h"
 #include "glob-util.h"
 #include "io-util.h"
@@ -771,11 +773,9 @@ static int get_fixed_group(const ExecContext *c, const char **group, gid_t *gid)
         return 0;
 }
 
-static int get_fixed_supplementary_groups(const ExecContext *c,
-                                          const char *user,
-                                          const char *group,
-                                          gid_t gid,
-                                          gid_t **supplementary_gids, int *ngids) {
+static int get_supplementary_groups(const ExecContext *c, const char *user,
+                                    const char *group, gid_t gid,
+                                    gid_t **supplementary_gids, int *ngids) {
         char **i;
         int r, k = 0;
         int ngroups_max;
@@ -785,6 +785,20 @@ static int get_fixed_supplementary_groups(const ExecContext *c,
 
         assert(c);
 
+        /*
+         * If user is given, then lookup GID and supplementary groups list.
+         * We avoid NSS lookups for gid=0. Also we have to initialize groups
+         * here and as early as possible so we keep the list of supplementary
+         * groups of the caller.
+         */
+        if (user && gid_is_valid(gid) && gid != 0) {
+                /* First step, initialize groups from /etc/groups */
+                if (initgroups(user, gid) < 0)
+                        return -errno;
+
+                keep_groups = true;
+        }
+
         if (!c->supplementary_groups)
                 return 0;
 
@@ -801,18 +815,6 @@ static int get_fixed_supplementary_groups(const ExecContext *c,
                         return -EOPNOTSUPP; /* For all other values */
         }
 
-        /*
-         * If user is given, then lookup GID and supplementary group list.
-         * We avoid NSS lookups for gid=0.
-         */
-        if (user && gid_is_valid(gid) && gid != 0) {
-                /* First step, initialize groups from /etc/groups */
-                if (initgroups(user, gid) < 0)
-                        return -errno;
-
-                keep_groups = true;
-        }
-
         l_gids = new(gid_t, ngroups_max);
         if (!l_gids)
                 return -ENOMEM;
@@ -1394,6 +1396,15 @@ static int apply_memory_deny_write_execute(const Unit* u, const ExecContext *c)
         if (r < 0)
                 goto finish;
 
+        r = seccomp_rule_add(
+                        seccomp,
+                        SCMP_ACT_ERRNO(EPERM),
+                        SCMP_SYS(shmat),
+                        1,
+                        SCMP_A2(SCMP_CMP_MASKED_EQ, SHM_EXEC, SHM_EXEC));
+        if (r < 0)
+                goto finish;
+
         r = seccomp_load(seccomp);
 
 finish:
@@ -1470,7 +1481,7 @@ finish:
         return r;
 }
 
-static int apply_protect_sysctl(Unit *u, const ExecContext *c) {
+static int apply_protect_sysctl(const Unit *u, const ExecContext *c) {
         scmp_filter_ctx seccomp;
         int r;
 
@@ -1501,7 +1512,7 @@ finish:
         return r;
 }
 
-static int apply_protect_kernel_modules(Unit *u, const ExecContext *c) {
+static int apply_protect_kernel_modules(const Unit *u, const ExecContext *c) {
         assert(c);
 
         /* Turn off module syscalls on ProtectKernelModules=yes */
@@ -1512,7 +1523,7 @@ static int apply_protect_kernel_modules(Unit *u, const ExecContext *c) {
         return seccomp_load_filter_set(SCMP_ACT_ALLOW, syscall_filter_sets + SYSCALL_FILTER_SET_MODULE, SCMP_ACT_ERRNO(EPERM));
 }
 
-static int apply_private_devices(Unit *u, const ExecContext *c) {
+static int apply_private_devices(const Unit *u, const ExecContext *c) {
         assert(c);
 
         /* If PrivateDevices= is set, also turn off iopl and all @raw-io syscalls. */
@@ -1592,7 +1603,7 @@ static int build_environment(
                 if (!joined)
                         return -ENOMEM;
 
-                x = strjoin("LISTEN_FDNAMES=", joined, NULL);
+                x = strjoin("LISTEN_FDNAMES=", joined);
                 if (!x)
                         return -ENOMEM;
                 our_env[n_env++] = x;
@@ -1699,7 +1710,7 @@ static int build_pass_environment(const ExecContext *c, char ***ret) {
                 v = getenv(*i);
                 if (!v)
                         continue;
-                x = strjoin(*i, "=", v, NULL);
+                x = strjoin(*i, "=", v);
                 if (!x)
                         return -ENOMEM;
                 if (!GREEDY_REALLOC(pass_env, n_bufsize, n_env + 2))
@@ -1913,7 +1924,7 @@ static int setup_runtime_directory(
         STRV_FOREACH(rt, context->runtime_directory) {
                 _cleanup_free_ char *p;
 
-                p = strjoin(params->runtime_prefix, "/", *rt, NULL);
+                p = strjoin(params->runtime_prefix, "/", *rt);
                 if (!p)
                         return -ENOMEM;
 
@@ -1989,7 +2000,7 @@ static int compile_read_write_paths(
         STRV_FOREACH(rt, context->runtime_directory) {
                 char *s;
 
-                s = strjoin(params->runtime_prefix, "/", *rt, NULL);
+                s = strjoin(params->runtime_prefix, "/", *rt);
                 if (!s)
                         return -ENOMEM;
 
@@ -2017,6 +2028,8 @@ static int apply_mount_namespace(Unit *u, const ExecContext *context,
                 .protect_kernel_modules = context->protect_kernel_modules,
         };
 
+        assert(context);
+
         /* The runtime struct only contains the parent of the private /tmp,
          * which is non-accessible to world users. Inside of it there's a /tmp
          * that is sticky, and that's the one we want to use here. */
@@ -2058,27 +2071,31 @@ static int apply_mount_namespace(Unit *u, const ExecContext *context,
 
 static int apply_working_directory(const ExecContext *context,
                                    const ExecParameters *params,
-                                   const char *working_directory,
+                                   const char *home,
                                    const bool needs_mount_ns) {
+        const char *d;
+        const char *wd;
+
+        assert(context);
+
+        if (context->working_directory_home)
+                wd = home;
+        else if (context->working_directory)
+                wd = context->working_directory;
+        else
+                wd = "/";
 
         if (params->flags & EXEC_APPLY_CHROOT) {
                 if (!needs_mount_ns && context->root_directory)
                         if (chroot(context->root_directory) < 0)
                                 return -errno;
 
-                if (chdir(working_directory) < 0 &&
-                    !context->working_directory_missing_ok)
-                        return -errno;
-
-        } else {
-                const char *d;
+                d = wd;
+        } else
+                d = strjoina(strempty(context->root_directory), "/", strempty(wd));
 
-                d = strjoina(strempty(context->root_directory), "/",
-                             strempty(working_directory));
-                if (chdir(d) < 0 &&
-                    !context->working_directory_missing_ok)
-                        return -errno;
-        }
+        if (chdir(d) < 0 && !context->working_directory_missing_ok)
+                return -errno;
 
         return 0;
 }
@@ -2219,7 +2236,7 @@ static int exec_child(
         _cleanup_free_ char *mac_selinux_context_net = NULL;
         _cleanup_free_ gid_t *supplementary_gids = NULL;
         const char *username = NULL, *groupname = NULL;
-        const char *home = NULL, *shell = NULL, *wd;
+        const char *home = NULL, *shell = NULL;
         dev_t journal_stream_dev = 0;
         ino_t journal_stream_ino = 0;
         bool needs_mount_namespace;
@@ -2328,13 +2345,14 @@ static int exec_child(
                         *exit_status = EXIT_GROUP;
                         return r;
                 }
+        }
 
-                r = get_fixed_supplementary_groups(context, username, groupname,
-                                                   gid, &supplementary_gids, &ngids);
-                if (r < 0) {
-                        *exit_status = EXIT_GROUP;
-                        return r;
-                }
+        /* Initialize user supplementary groups and get SupplementaryGroups= ones */
+        r = get_supplementary_groups(context, username, groupname, gid,
+                                     &supplementary_gids, &ngids);
+        if (r < 0) {
+                *exit_status = EXIT_GROUP;
+                return r;
         }
 
         r = send_user_lookup(unit, user_lookup_fd, uid, gid);
@@ -2521,12 +2539,6 @@ static int exec_child(
         (void) umask(context->umask);
 
         if ((params->flags & EXEC_APPLY_PERMISSIONS) && !command->privileged) {
-                r = setup_smack(context, command);
-                if (r < 0) {
-                        *exit_status = EXIT_SMACK_PROCESS_LABEL;
-                        return r;
-                }
-
                 if (context->pam_name && username) {
                         r = setup_pam(context->pam_name, username, uid, gid, context->tty_path, &accum_env, fds, n_fds);
                         if (r < 0) {
@@ -2553,14 +2565,14 @@ static int exec_child(
                 }
         }
 
-        if (context->working_directory_home)
-                wd = home;
-        else if (context->working_directory)
-                wd = context->working_directory;
-        else
-                wd = "/";
+        /* Apply just after mount namespace setup */
+        r = apply_working_directory(context, params, home, needs_mount_namespace);
+        if (r < 0) {
+                *exit_status = EXIT_CHROOT;
+                return r;
+        }
 
-        /* Drop group as early as possbile */
+        /* Drop groups as early as possbile */
         if ((params->flags & EXEC_APPLY_PERMISSIONS) && !command->privileged) {
                 r = enforce_groups(context, gid, supplementary_gids, ngids);
                 if (r < 0) {
@@ -2569,12 +2581,6 @@ static int exec_child(
                 }
         }
 
-        r = apply_working_directory(context, params, wd, needs_mount_namespace);
-        if (r < 0) {
-                *exit_status = EXIT_CHROOT;
-                return r;
-        }
-
 #ifdef HAVE_SELINUX
         if ((params->flags & EXEC_APPLY_PERMISSIONS) &&
             mac_selinux_use() &&
@@ -2682,6 +2688,41 @@ static int exec_child(
                         }
                 }
 
+                /* Apply the MAC contexts late, but before seccomp syscall filtering, as those should really be last to
+                 * influence our own codepaths as little as possible. Moreover, applying MAC contexts usually requires
+                 * syscalls that are subject to seccomp filtering, hence should probably be applied before the syscalls
+                 * are restricted. */
+
+#ifdef HAVE_SELINUX
+                if (mac_selinux_use()) {
+                        char *exec_context = mac_selinux_context_net ?: context->selinux_context;
+
+                        if (exec_context) {
+                                r = setexeccon(exec_context);
+                                if (r < 0) {
+                                        *exit_status = EXIT_SELINUX_CONTEXT;
+                                        return r;
+                                }
+                        }
+                }
+#endif
+
+                r = setup_smack(context, command);
+                if (r < 0) {
+                        *exit_status = EXIT_SMACK_PROCESS_LABEL;
+                        return r;
+                }
+
+#ifdef HAVE_APPARMOR
+                if (context->apparmor_profile && mac_apparmor_use()) {
+                        r = aa_change_onexec(context->apparmor_profile);
+                        if (r < 0 && !context->apparmor_profile_ignore) {
+                                *exit_status = EXIT_APPARMOR_PROFILE;
+                                return -errno;
+                        }
+                }
+#endif
+
                 /* PR_GET_SECUREBITS is not privileged, while
                  * PR_SET_SECUREBITS is. So to suppress
                  * potential EPERMs we'll try not to call
@@ -2747,6 +2788,8 @@ static int exec_child(
                         }
                 }
 
+                /* This really should remain the last step before the execve(), to make sure our own code is unaffected
+                 * by the filter as little as possible. */
                 if (context_has_syscall_filters(context)) {
                         r = apply_seccomp(unit, context);
                         if (r < 0) {
@@ -2755,30 +2798,6 @@ static int exec_child(
                         }
                 }
 #endif
-
-#ifdef HAVE_SELINUX
-                if (mac_selinux_use()) {
-                        char *exec_context = mac_selinux_context_net ?: context->selinux_context;
-
-                        if (exec_context) {
-                                r = setexeccon(exec_context);
-                                if (r < 0) {
-                                        *exit_status = EXIT_SELINUX_CONTEXT;
-                                        return r;
-                                }
-                        }
-                }
-#endif
-
-#ifdef HAVE_APPARMOR
-                if (context->apparmor_profile && mac_apparmor_use()) {
-                        r = aa_change_onexec(context->apparmor_profile);
-                        if (r < 0 && !context->apparmor_profile_ignore) {
-                                *exit_status = EXIT_APPARMOR_PROFILE;
-                                return -errno;
-                        }
-                }
-#endif
         }
 
         final_argv = replace_env_argv(argv, accum_env);
@@ -2985,7 +3004,7 @@ int exec_context_destroy_runtime_directory(ExecContext *c, const char *runtime_p
         STRV_FOREACH(i, c->runtime_directory) {
                 _cleanup_free_ char *p;
 
-                p = strjoin(runtime_prefix, "/", *i, NULL);
+                p = strjoin(runtime_prefix, "/", *i);
                 if (!p)
                         return -ENOMEM;
 
@@ -3600,7 +3619,8 @@ char *exec_command_line(char **argv) {
         STRV_FOREACH(a, argv)
                 k += strlen(*a)+3;
 
-        if (!(n = new(char, k)))
+        n = new(char, k);
+        if (!n)
                 return NULL;
 
         p = n;