]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/core/execute.c
service: add new RootImageOptions feature
[thirdparty/systemd.git] / src / core / execute.c
index e0835f9b92ca778ad1f86e4861bfac5ae645badb..39ffcba5802dff4b4e78c4b216fcef9239da1514 100644 (file)
@@ -1380,14 +1380,14 @@ static void rename_process_from_path(const char *path) {
 static bool context_has_address_families(const ExecContext *c) {
         assert(c);
 
-        return c->address_families_whitelist ||
+        return c->address_families_allow_list ||
                 !set_isempty(c->address_families);
 }
 
 static bool context_has_syscall_filters(const ExecContext *c) {
         assert(c);
 
-        return c->syscall_whitelist ||
+        return c->syscall_allow_list ||
                 !hashmap_isempty(c->syscall_filter);
 }
 
@@ -1443,7 +1443,7 @@ static int apply_syscall_filter(const Unit* u, const ExecContext *c, bool needs_
 
         negative_action = c->syscall_errno == 0 ? scmp_act_kill_process() : SCMP_ACT_ERRNO(c->syscall_errno);
 
-        if (c->syscall_whitelist) {
+        if (c->syscall_allow_list) {
                 default_action = negative_action;
                 action = SCMP_ACT_ALLOW;
         } else {
@@ -1452,7 +1452,7 @@ static int apply_syscall_filter(const Unit* u, const ExecContext *c, bool needs_
         }
 
         if (needs_ambient_hack) {
-                r = seccomp_filter_set_add(c->syscall_filter, c->syscall_whitelist, syscall_filter_sets + SYSCALL_FILTER_SET_SETUID);
+                r = seccomp_filter_set_add(c->syscall_filter, c->syscall_allow_list, syscall_filter_sets + SYSCALL_FILTER_SET_SETUID);
                 if (r < 0)
                         return r;
         }
@@ -1483,7 +1483,7 @@ static int apply_address_families(const Unit* u, const ExecContext *c) {
         if (skip_seccomp_unavailable(u, "RestrictAddressFamilies="))
                 return 0;
 
-        return seccomp_restrict_address_families(c->address_families, c->address_families_whitelist);
+        return seccomp_restrict_address_families(c->address_families, c->address_families_allow_list);
 }
 
 static int apply_memory_deny_write_execute(const Unit* u, const ExecContext *c) {
@@ -1725,7 +1725,8 @@ static int build_environment(
         assert(p);
         assert(ret);
 
-        our_env = new0(char*, 15 + _EXEC_DIRECTORY_TYPE_MAX);
+#define N_ENV_VARS 15
+        our_env = new0(char*, N_ENV_VARS + _EXEC_DIRECTORY_TYPE_MAX);
         if (!our_env)
                 return -ENOMEM;
 
@@ -1873,7 +1874,8 @@ static int build_environment(
         }
 
         our_env[n_env++] = NULL;
-        assert(n_env <= 14 + _EXEC_DIRECTORY_TYPE_MAX);
+        assert(n_env <= N_ENV_VARS + _EXEC_DIRECTORY_TYPE_MAX);
+#undef N_ENV_VARS
 
         *ret = TAKE_PTR(our_env);
 
@@ -2592,7 +2594,7 @@ static int apply_mount_namespace(
                 char **error_path) {
 
         _cleanup_strv_free_ char **empty_directories = NULL;
-        char *tmp = NULL, *var = NULL;
+        const char *tmp_dir = NULL, *var_tmp_dir = NULL;
         const char *root_dir = NULL, *root_image = NULL;
         NamespaceInfo ns_info;
         bool needs_sandboxing;
@@ -2617,13 +2619,19 @@ static int apply_mount_namespace(
         if (needs_sandboxing) {
                 /* 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. */
+                 * that is sticky, and that's the one we want to use here.
+                 * This does not apply when we are using /run/systemd/empty as fallback. */
 
                 if (context->private_tmp && runtime) {
-                        if (runtime->tmp_dir)
-                                tmp = strjoina(runtime->tmp_dir, "/tmp");
-                        if (runtime->var_tmp_dir)
-                                var = strjoina(runtime->var_tmp_dir, "/tmp");
+                        if (streq_ptr(runtime->tmp_dir, RUN_SYSTEMD_EMPTY))
+                                tmp_dir = runtime->tmp_dir;
+                        else if (runtime->tmp_dir)
+                                tmp_dir = strjoina(runtime->tmp_dir, "/tmp");
+
+                        if (streq_ptr(runtime->var_tmp_dir, RUN_SYSTEMD_EMPTY))
+                                var_tmp_dir = runtime->var_tmp_dir;
+                        else if (runtime->var_tmp_dir)
+                                var_tmp_dir = strjoina(runtime->var_tmp_dir, "/tmp");
                 }
 
                 ns_info = (NamespaceInfo) {
@@ -2652,7 +2660,7 @@ static int apply_mount_namespace(
         if (context->mount_flags == MS_SHARED)
                 log_unit_debug(u, "shared mount propagation hidden by other fs namespacing unit settings: ignoring");
 
-        r = setup_namespace(root_dir, root_image,
+        r = setup_namespace(root_dir, root_image, context->root_image_options,
                             &ns_info, context->read_write_paths,
                             needs_sandboxing ? context->read_only_paths : NULL,
                             needs_sandboxing ? context->inaccessible_paths : NULL,
@@ -2661,13 +2669,15 @@ static int apply_mount_namespace(
                             n_bind_mounts,
                             context->temporary_filesystems,
                             context->n_temporary_filesystems,
-                            tmp,
-                            var,
+                            tmp_dir,
+                            var_tmp_dir,
                             context->log_namespace,
                             needs_sandboxing ? context->protect_home : PROTECT_HOME_NO,
                             needs_sandboxing ? context->protect_system : PROTECT_SYSTEM_NO,
                             context->mount_flags,
-                            context->root_hash, context->root_hash_size, context->root_hash_path, context->root_verity,
+                            context->root_hash, context->root_hash_size, context->root_hash_path,
+                            context->root_hash_sig, context->root_hash_sig_size, context->root_hash_sig_path,
+                            context->root_verity,
                             DISSECT_IMAGE_DISCARD_ON_LOOP|DISSECT_IMAGE_RELAX_VAR_CHECK|DISSECT_IMAGE_FSCK,
                             error_path);
 
@@ -2853,7 +2863,7 @@ static int setup_keyring(
         }
 
 out:
-        /* Revert back uid & gid for the the last time, and exit */
+        /* Revert back uid & gid for the last time, and exit */
         /* no extra logging, as only the first already reported error matters */
         if (getuid() != saved_uid)
                 (void) setreuid(saved_uid, -1);
@@ -4197,9 +4207,13 @@ void exec_context_done(ExecContext *c) {
         c->working_directory = mfree(c->working_directory);
         c->root_directory = mfree(c->root_directory);
         c->root_image = mfree(c->root_image);
+        c->root_image_options = mount_options_free_all(c->root_image_options);
         c->root_hash = mfree(c->root_hash);
         c->root_hash_size = 0;
         c->root_hash_path = mfree(c->root_hash_path);
+        c->root_hash_sig = mfree(c->root_hash_sig);
+        c->root_hash_sig_size = 0;
+        c->root_hash_sig_path = mfree(c->root_hash_sig_path);
         c->root_verity = mfree(c->root_verity);
         c->tty_path = mfree(c->tty_path);
         c->syslog_identifier = mfree(c->syslog_identifier);
@@ -4605,6 +4619,16 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
         if (c->root_image)
                 fprintf(f, "%sRootImage: %s\n", prefix, c->root_image);
 
+        if (c->root_image_options) {
+                MountOptions *o;
+
+                fprintf(f, "%sRootImageOptions:", prefix);
+                LIST_FOREACH(mount_options, o, c->root_image_options)
+                        if (!isempty(o->options))
+                                fprintf(f, " %u:%s", o->partition_number, o->options);
+                fprintf(f, "\n");
+        }
+
         if (c->root_hash) {
                 _cleanup_free_ char *encoded = NULL;
                 encoded = hexmem(c->root_hash, c->root_hash_size);
@@ -4615,6 +4639,17 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
         if (c->root_hash_path)
                 fprintf(f, "%sRootHash: %s\n", prefix, c->root_hash_path);
 
+        if (c->root_hash_sig) {
+                _cleanup_free_ char *encoded = NULL;
+                ssize_t len;
+                len = base64mem(c->root_hash_sig, c->root_hash_sig_size, &encoded);
+                if (len)
+                        fprintf(f, "%sRootHashSignature: base64:%s\n", prefix, encoded);
+        }
+
+        if (c->root_hash_sig_path)
+                fprintf(f, "%sRootHashSignature: %s\n", prefix, c->root_hash_sig_path);
+
         if (c->root_verity)
                 fprintf(f, "%sRootVerity: %s\n", prefix, c->root_verity);
 
@@ -4918,7 +4953,7 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
                         "%sSystemCallFilter: ",
                         prefix);
 
-                if (!c->syscall_whitelist)
+                if (!c->syscall_allow_list)
                         fputc('~', f);
 
 #if HAVE_SECCOMP
@@ -5331,28 +5366,25 @@ static ExecRuntime* exec_runtime_free(ExecRuntime *rt, bool destroy) {
                 (void) hashmap_remove(rt->manager->exec_runtime_by_id, rt->id);
 
         /* When destroy is true, then rm_rf tmp_dir and var_tmp_dir. */
-        if (destroy && rt->tmp_dir) {
+
+        if (destroy && rt->tmp_dir && !streq(rt->tmp_dir, RUN_SYSTEMD_EMPTY)) {
                 log_debug("Spawning thread to nuke %s", rt->tmp_dir);
 
                 r = asynchronous_job(remove_tmpdir_thread, rt->tmp_dir);
-                if (r < 0) {
+                if (r < 0)
                         log_warning_errno(r, "Failed to nuke %s: %m", rt->tmp_dir);
-                        free(rt->tmp_dir);
-                }
-
-                rt->tmp_dir = NULL;
+                else
+                        rt->tmp_dir = NULL;
         }
 
-        if (destroy && rt->var_tmp_dir) {
+        if (destroy && rt->var_tmp_dir && !streq(rt->var_tmp_dir, RUN_SYSTEMD_EMPTY)) {
                 log_debug("Spawning thread to nuke %s", rt->var_tmp_dir);
 
                 r = asynchronous_job(remove_tmpdir_thread, rt->var_tmp_dir);
-                if (r < 0) {
+                if (r < 0)
                         log_warning_errno(r, "Failed to nuke %s: %m", rt->var_tmp_dir);
-                        free(rt->var_tmp_dir);
-                }
-
-                rt->var_tmp_dir = NULL;
+                else
+                        rt->var_tmp_dir = NULL;
         }
 
         rt->id = mfree(rt->id);
@@ -5366,16 +5398,22 @@ static void exec_runtime_freep(ExecRuntime **rt) {
         (void) exec_runtime_free(*rt, false);
 }
 
-static int exec_runtime_allocate(ExecRuntime **ret) {
+static int exec_runtime_allocate(ExecRuntime **ret, const char *id) {
+        _cleanup_free_ char *id_copy = NULL;
         ExecRuntime *n;
 
         assert(ret);
 
+        id_copy = strdup(id);
+        if (!id_copy)
+                return -ENOMEM;
+
         n = new(ExecRuntime, 1);
         if (!n)
                 return -ENOMEM;
 
         *n = (ExecRuntime) {
+                .id = TAKE_PTR(id_copy),
                 .netns_storage_socket = { -1, -1 },
         };
 
@@ -5386,9 +5424,9 @@ static int exec_runtime_allocate(ExecRuntime **ret) {
 static int exec_runtime_add(
                 Manager *m,
                 const char *id,
-                const char *tmp_dir,
-                const char *var_tmp_dir,
-                const int netns_storage_socket[2],
+                char **tmp_dir,
+                char **var_tmp_dir,
+                int netns_storage_socket[2],
                 ExecRuntime **ret) {
 
         _cleanup_(exec_runtime_freep) ExecRuntime *rt = NULL;
@@ -5397,51 +5435,40 @@ static int exec_runtime_add(
         assert(m);
         assert(id);
 
+        /* tmp_dir, var_tmp_dir, netns_storage_socket fds are donated on success */
+
         r = hashmap_ensure_allocated(&m->exec_runtime_by_id, &string_hash_ops);
         if (r < 0)
                 return r;
 
-        r = exec_runtime_allocate(&rt);
+        r = exec_runtime_allocate(&rt, id);
         if (r < 0)
                 return r;
 
-        rt->id = strdup(id);
-        if (!rt->id)
-                return -ENOMEM;
-
-        if (tmp_dir) {
-                rt->tmp_dir = strdup(tmp_dir);
-                if (!rt->tmp_dir)
-                        return -ENOMEM;
+        r = hashmap_put(m->exec_runtime_by_id, rt->id, rt);
+        if (r < 0)
+                return r;
 
-                /* When tmp_dir is set, then we require var_tmp_dir is also set. */
-                assert(var_tmp_dir);
-                rt->var_tmp_dir = strdup(var_tmp_dir);
-                if (!rt->var_tmp_dir)
-                        return -ENOMEM;
-        }
+        assert(!!rt->tmp_dir == !!rt->var_tmp_dir); /* We require both to be set together */
+        rt->tmp_dir = TAKE_PTR(*tmp_dir);
+        rt->var_tmp_dir = TAKE_PTR(*var_tmp_dir);
 
         if (netns_storage_socket) {
-                rt->netns_storage_socket[0] = netns_storage_socket[0];
-                rt->netns_storage_socket[1] = netns_storage_socket[1];
+                rt->netns_storage_socket[0] = TAKE_FD(netns_storage_socket[0]);
+                rt->netns_storage_socket[1] = TAKE_FD(netns_storage_socket[1]);
         }
 
-        r = hashmap_put(m->exec_runtime_by_id, rt->id, rt);
-        if (r < 0)
-                return r;
-
         rt->manager = m;
 
         if (ret)
                 *ret = rt;
-
         /* do not remove created ExecRuntime object when the operation succeeds. */
-        rt = NULL;
+        TAKE_PTR(rt);
         return 0;
 }
 
 static int exec_runtime_make(Manager *m, const ExecContext *c, const char *id, ExecRuntime **ret) {
-        _cleanup_free_ char *tmp_dir = NULL, *var_tmp_dir = NULL;
+        _cleanup_(namespace_cleanup_tmpdirp) char *tmp_dir = NULL, *var_tmp_dir = NULL;
         _cleanup_close_pair_ int netns_storage_socket[2] = { -1, -1 };
         int r;
 
@@ -5467,12 +5494,10 @@ static int exec_runtime_make(Manager *m, const ExecContext *c, const char *id, E
                         return -errno;
         }
 
-        r = exec_runtime_add(m, id, tmp_dir, var_tmp_dir, netns_storage_socket, ret);
+        r = exec_runtime_add(m, id, &tmp_dir, &var_tmp_dir, netns_storage_socket, ret);
         if (r < 0)
                 return r;
 
-        /* Avoid cleanup */
-        netns_storage_socket[0] = netns_storage_socket[1] = -1;
         return 1;
 }
 
@@ -5590,14 +5615,10 @@ int exec_runtime_deserialize_compat(Unit *u, const char *key, const char *value,
 
         rt = hashmap_get(u->manager->exec_runtime_by_id, u->id);
         if (!rt) {
-                r = exec_runtime_allocate(&rt_create);
+                r = exec_runtime_allocate(&rt_create, u->id);
                 if (r < 0)
                         return log_oom();
 
-                rt_create->id = strdup(u->id);
-                if (!rt_create->id)
-                        return log_oom();
-
                 rt = rt_create;
         }
 
@@ -5654,15 +5675,16 @@ int exec_runtime_deserialize_compat(Unit *u, const char *key, const char *value,
                 rt_create->manager = u->manager;
 
                 /* Avoid cleanup */
-                rt_create = NULL;
+                TAKE_PTR(rt_create);
         }
 
         return 1;
 }
 
-void exec_runtime_deserialize_one(Manager *m, const char *value, FDSet *fds) {
-        char *id = NULL, *tmp_dir = NULL, *var_tmp_dir = NULL;
-        int r, fd0 = -1, fd1 = -1;
+int exec_runtime_deserialize_one(Manager *m, const char *value, FDSet *fds) {
+        _cleanup_free_ char *tmp_dir = NULL, *var_tmp_dir = NULL;
+        char *id = NULL;
+        int r, fdpair[] = {-1, -1};
         const char *p, *v = value;
         size_t n;
 
@@ -5679,7 +5701,9 @@ void exec_runtime_deserialize_one(Manager *m, const char *value, FDSet *fds) {
         v = startswith(p, "tmp-dir=");
         if (v) {
                 n = strcspn(v, " ");
-                tmp_dir = strndupa(v, n);
+                tmp_dir = strndup(v, n);
+                if (!tmp_dir)
+                        return log_oom();
                 if (v[n] != ' ')
                         goto finalize;
                 p = v + n + 1;
@@ -5688,7 +5712,9 @@ void exec_runtime_deserialize_one(Manager *m, const char *value, FDSet *fds) {
         v = startswith(p, "var-tmp-dir=");
         if (v) {
                 n = strcspn(v, " ");
-                var_tmp_dir = strndupa(v, n);
+                var_tmp_dir = strndup(v, n);
+                if (!var_tmp_dir)
+                        return log_oom();
                 if (v[n] != ' ')
                         goto finalize;
                 p = v + n + 1;
@@ -5700,11 +5726,9 @@ void exec_runtime_deserialize_one(Manager *m, const char *value, FDSet *fds) {
 
                 n = strcspn(v, " ");
                 buf = strndupa(v, n);
-                if (safe_atoi(buf, &fd0) < 0 || !fdset_contains(fds, fd0)) {
-                        log_debug("Unable to process exec-runtime netns fd specification.");
-                        return;
-                }
-                fd0 = fdset_remove(fds, fd0);
+                if (safe_atoi(buf, &fdpair[0]) < 0 || !fdset_contains(fds, fdpair[0]))
+                        return log_debug("Unable to process exec-runtime netns fd specification.");
+                fdpair[0] = fdset_remove(fds, fdpair[0]);
                 if (v[n] != ' ')
                         goto finalize;
                 p = v + n + 1;
@@ -5716,18 +5740,16 @@ void exec_runtime_deserialize_one(Manager *m, const char *value, FDSet *fds) {
 
                 n = strcspn(v, " ");
                 buf = strndupa(v, n);
-                if (safe_atoi(buf, &fd1) < 0 || !fdset_contains(fds, fd1)) {
-                        log_debug("Unable to process exec-runtime netns fd specification.");
-                        return;
-                }
-                fd1 = fdset_remove(fds, fd1);
+                if (safe_atoi(buf, &fdpair[1]) < 0 || !fdset_contains(fds, fdpair[1]))
+                        return log_debug("Unable to process exec-runtime netns fd specification.");
+                fdpair[1] = fdset_remove(fds, fdpair[1]);
         }
 
 finalize:
-
-        r = exec_runtime_add(m, id, tmp_dir, var_tmp_dir, (int[]) { fd0, fd1 }, NULL);
+        r = exec_runtime_add(m, id, &tmp_dir, &var_tmp_dir, fdpair, NULL);
         if (r < 0)
-                log_debug_errno(r, "Failed to add exec-runtime: %m");
+                return log_debug_errno(r, "Failed to add exec-runtime: %m");
+        return 0;
 }
 
 void exec_runtime_vacuum(Manager *m) {
@@ -5750,7 +5772,10 @@ void exec_params_clear(ExecParameters *p) {
         if (!p)
                 return;
 
-        strv_free(p->environment);
+        p->environment = strv_free(p->environment);
+        p->fd_names = strv_free(p->fd_names);
+        p->fds = mfree(p->fds);
+        p->exec_fd = safe_close(p->exec_fd);
 }
 
 static const char* const exec_input_table[_EXEC_INPUT_MAX] = {