]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/core/execute.c
tree-wide: use UINT64_MAX or friends
[thirdparty/systemd.git] / src / core / execute.c
index 4b4880218345baba89fbdc5d237776358bb46716..158172bd263e916efa2dbf1d95adf72c47e007eb 100644 (file)
@@ -446,12 +446,12 @@ static int fixup_input(
         return std_input;
 }
 
-static int fixup_output(ExecOutput std_output, int socket_fd) {
+static int fixup_output(ExecOutput output, int socket_fd) {
 
-        if (std_output == EXEC_OUTPUT_SOCKET && socket_fd < 0)
+        if (output == EXEC_OUTPUT_SOCKET && socket_fd < 0)
                 return EXEC_OUTPUT_INHERIT;
 
-        return std_output;
+        return output;
 }
 
 static int setup_input(
@@ -622,7 +622,7 @@ static int setup_output(
                     o == EXEC_OUTPUT_INHERIT &&
                     i == EXEC_INPUT_NULL &&
                     !is_terminal_input(context->std_input) &&
-                    getppid () != 1)
+                    getppid() != 1)
                         return fileno;
 
                 /* Duplicate from stdout if possible */
@@ -666,7 +666,8 @@ static int setup_output(
         case EXEC_OUTPUT_JOURNAL_AND_CONSOLE:
                 r = connect_logger_as(unit, context, params, o, ident, fileno, uid, gid);
                 if (r < 0) {
-                        log_unit_warning_errno(unit, r, "Failed to connect %s to the journal socket, ignoring: %m", fileno == STDOUT_FILENO ? "stdout" : "stderr");
+                        log_unit_warning_errno(unit, r, "Failed to connect %s to the journal socket, ignoring: %m",
+                                               fileno == STDOUT_FILENO ? "stdout" : "stderr");
                         r = open_null_as(O_WRONLY, fileno);
                 } else {
                         struct stat st;
@@ -1268,7 +1269,7 @@ static int setup_pam(
                 if (setresuid(uid, uid, uid) < 0)
                         log_warning_errno(errno, "Failed to setresuid() in sd-pam: %m");
 
-                (void) ignore_signals(SIGPIPE, -1);
+                (void) ignore_signals(SIGPIPE);
 
                 /* Wait until our parent died. This will only work if
                  * the above setresuid() succeeds, otherwise the kernel
@@ -2018,6 +2019,9 @@ bool exec_needs_mount_namespace(
         if (context->n_mount_images > 0)
                 return true;
 
+        if (context->n_extension_images > 0)
+                return true;
+
         if (!IN_SET(context->mount_flags, 0, MS_SHARED))
                 return true;
 
@@ -2033,7 +2037,9 @@ bool exec_needs_mount_namespace(
             context->protect_kernel_logs ||
             context->protect_control_groups ||
             context->protect_proc != PROTECT_PROC_DEFAULT ||
-            context->proc_subset != PROC_SUBSET_ALL)
+            context->proc_subset != PROC_SUBSET_ALL ||
+            context->private_ipc ||
+            context->ipc_namespace_path)
                 return true;
 
         if (context->root_directory) {
@@ -2502,7 +2508,7 @@ static int write_credential(
                                             * user can no longer chmod() the file to gain write access. */
                                 return r;
 
-                        if (fchown(fd, uid, (gid_t) -1) < 0)
+                        if (fchown(fd, uid, GID_INVALID) < 0)
                                 return -errno;
                 }
         }
@@ -2620,7 +2626,7 @@ static int acquire_credentials(
                         if (!ownership_ok)
                                 return r;
 
-                        if (fchown(dfd, uid, (gid_t) -1) < 0)
+                        if (fchown(dfd, uid, GID_INVALID) < 0)
                                 return -errno;
                 }
         }
@@ -3174,6 +3180,7 @@ static int apply_mount_namespace(
                         .protect_system = context->protect_system,
                         .protect_proc = context->protect_proc,
                         .proc_subset = context->proc_subset,
+                        .private_ipc = context->private_ipc || context->ipc_namespace_path,
                 };
         } else if (!context->dynamic_user && root_dir)
                 /*
@@ -3202,11 +3209,16 @@ static int apply_mount_namespace(
 
         if (MANAGER_IS_SYSTEM(u->manager)) {
                 propagate_dir = path_join("/run/systemd/propagate/", u->id);
-                if (!propagate_dir)
-                        return -ENOMEM;
+                if (!propagate_dir) {
+                        r = -ENOMEM;
+                        goto finalize;
+                }
+
                 incoming_dir = strdup("/run/systemd/incoming");
-                if (!incoming_dir)
-                        return -ENOMEM;
+                if (!incoming_dir) {
+                        r = -ENOMEM;
+                        goto finalize;
+                }
         }
 
         r = setup_namespace(root_dir, root_image, context->root_image_options,
@@ -3230,6 +3242,8 @@ static int apply_mount_namespace(
                             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,
+                            context->extension_images,
+                            context->n_extension_images,
                             propagate_dir,
                             incoming_dir,
                             root_dir || root_image ? params->notify_socket : NULL,
@@ -3465,8 +3479,10 @@ static int close_remaining_fds(
                 n_dont_close += n_fds;
         }
 
-        if (runtime)
+        if (runtime) {
                 append_socket_pair(dont_close, &n_dont_close, runtime->netns_storage_socket);
+                append_socket_pair(dont_close, &n_dont_close, runtime->ipcns_storage_socket);
+        }
 
         if (dcreds) {
                 if (dcreds->user)
@@ -3723,16 +3739,14 @@ static int exec_child(
 
         rename_process_from_path(command->path);
 
-        /* We reset exactly these signals, since they are the
-         * only ones we set to SIG_IGN in the main daemon. All
-         * others we leave untouched because we set them to
-         * SIG_DFL or a valid handler initially, both of which
-         * will be demoted to SIG_DFL. */
+        /* We reset exactly these signals, since they are the only ones we set to SIG_IGN in the main
+         * daemon. All others we leave untouched because we set them to SIG_DFL or a valid handler initially,
+         * both of which will be demoted to SIG_DFL. */
         (void) default_signals(SIGNALS_CRASH_HANDLER,
-                               SIGNALS_IGNORE, -1);
+                               SIGNALS_IGNORE);
 
         if (context->ignore_sigpipe)
-                (void) ignore_signals(SIGPIPE, -1);
+                (void) ignore_signals(SIGPIPE);
 
         r = reset_signal_mask();
         if (r < 0) {
@@ -3909,13 +3923,21 @@ static int exec_child(
         }
 
         if (context->network_namespace_path && runtime && runtime->netns_storage_socket[0] >= 0) {
-                r = open_netns_path(runtime->netns_storage_socket, context->network_namespace_path);
+                r = open_shareable_ns_path(runtime->netns_storage_socket, context->network_namespace_path, CLONE_NEWNET);
                 if (r < 0) {
                         *exit_status = EXIT_NETWORK;
                         return log_unit_error_errno(unit, r, "Failed to open network namespace path %s: %m", context->network_namespace_path);
                 }
         }
 
+        if (context->ipc_namespace_path && runtime && runtime->ipcns_storage_socket[0] >= 0) {
+                r = open_shareable_ns_path(runtime->ipcns_storage_socket, context->ipc_namespace_path, CLONE_NEWIPC);
+                if (r < 0) {
+                        *exit_status = EXIT_NAMESPACE;
+                        return log_unit_error_errno(unit, r, "Failed to open IPC namespace path %s: %m", context->ipc_namespace_path);
+                }
+        }
+
         r = setup_input(context, params, socket_fd, named_iofds);
         if (r < 0) {
                 *exit_status = EXIT_STDIN;
@@ -4186,7 +4208,7 @@ static int exec_child(
         if ((context->private_network || context->network_namespace_path) && runtime && runtime->netns_storage_socket[0] >= 0) {
 
                 if (ns_type_supported(NAMESPACE_NET)) {
-                        r = setup_netns(runtime->netns_storage_socket);
+                        r = setup_shareable_ns(runtime->netns_storage_socket, CLONE_NEWNET);
                         if (r == -EPERM)
                                 log_unit_warning_errno(unit, r,
                                                        "PrivateNetwork=yes is configured, but network namespace setup failed, ignoring: %m");
@@ -4202,6 +4224,25 @@ static int exec_child(
                         log_unit_warning(unit, "PrivateNetwork=yes is configured, but the kernel does not support network namespaces, ignoring.");
         }
 
+        if ((context->private_ipc || context->ipc_namespace_path) && runtime && runtime->ipcns_storage_socket[0] >= 0) {
+
+                if (ns_type_supported(NAMESPACE_IPC)) {
+                        r = setup_shareable_ns(runtime->ipcns_storage_socket, CLONE_NEWIPC);
+                        if (r == -EPERM)
+                                log_unit_warning_errno(unit, r,
+                                                       "PrivateIPC=yes is configured, but IPC namespace setup failed, ignoring: %m");
+                        else if (r < 0) {
+                                *exit_status = EXIT_NAMESPACE;
+                                return log_unit_error_errno(unit, r, "Failed to set up IPC namespacing: %m");
+                        }
+                } else if (context->ipc_namespace_path) {
+                        *exit_status = EXIT_NAMESPACE;
+                        return log_unit_error_errno(unit, SYNTHETIC_ERRNO(EOPNOTSUPP),
+                                                    "IPCNamespacePath= is not supported, refusing.");
+                } else
+                        log_unit_warning(unit, "PrivateIPC=yes is configured, but the kernel does not support IPC namespaces, ignoring.");
+        }
+
         needs_mount_namespace = exec_needs_mount_namespace(context, params, runtime);
         if (needs_mount_namespace) {
                 _cleanup_free_ char *error_path = NULL;
@@ -4305,7 +4346,7 @@ static int exec_child(
 #endif
 
         /* We repeat the fd closing here, to make sure that nothing is leaked from the PAM modules. Note that we are
-         * more aggressive this time since socket_fd and the netns fds we don't need anymore. We do keep the exec_fd
+         * more aggressive this time since socket_fd and the netns and ipcns fds we don't need anymore. We do keep the exec_fd
          * however if we have it as we want to keep it open until the final execve(). */
 
         r = close_all_fds(keep_fds, n_keep_fds);
@@ -4706,6 +4747,10 @@ int exec_spawn(Unit *unit,
                         r = cg_create(SYSTEMD_CGROUP_CONTROLLER, subcgroup_path);
                         if (r < 0)
                                 return log_unit_error_errno(unit, r, "Failed to create control group '%s': %m", subcgroup_path);
+
+                        /* Normally we would not propagate the oomd xattrs to children but since we created this
+                         * sub-cgroup internally we should do it. */
+                        cgroup_oomd_xattr_apply(unit, subcgroup_path);
                 }
         }
 
@@ -4812,6 +4857,7 @@ void exec_context_done(ExecContext *c) {
         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->extension_images = mount_image_free_many(c->extension_images, &c->n_extension_images);
         c->tty_path = mfree(c->tty_path);
         c->syslog_identifier = mfree(c->syslog_identifier);
         c->user = mfree(c->user);
@@ -5644,15 +5690,27 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
         for (size_t i = 0; i < c->n_mount_images; i++) {
                 MountOptions *o;
 
-                fprintf(f, "%sMountImages: %s%s:%s%s", prefix,
+                fprintf(f, "%sMountImages: %s%s:%s", prefix,
                         c->mount_images[i].ignore_enoent ? "-": "",
                         c->mount_images[i].source,
-                        c->mount_images[i].destination,
-                        LIST_IS_EMPTY(c->mount_images[i].mount_options) ? "": ":");
+                        c->mount_images[i].destination);
                 LIST_FOREACH(mount_options, o, c->mount_images[i].mount_options)
-                        fprintf(f, "%s:%s",
+                        fprintf(f, ":%s:%s",
+                                partition_designator_to_string(o->partition_designator),
+                                strempty(o->options));
+                fprintf(f, "\n");
+        }
+
+        for (size_t i = 0; i < c->n_extension_images; i++) {
+                MountOptions *o;
+
+                fprintf(f, "%sExtensionImages: %s%s", prefix,
+                        c->extension_images[i].ignore_enoent ? "-": "",
+                        c->extension_images[i].source);
+                LIST_FOREACH(mount_options, o, c->extension_images[i].mount_options)
+                        fprintf(f, ":%s:%s",
                                 partition_designator_to_string(o->partition_designator),
-                                o->options);
+                                strempty(o->options));
                 fprintf(f, "\n");
         }
 }
@@ -6031,6 +6089,7 @@ static ExecRuntime* exec_runtime_free(ExecRuntime *rt, bool destroy) {
         rt->tmp_dir = mfree(rt->tmp_dir);
         rt->var_tmp_dir = mfree(rt->var_tmp_dir);
         safe_close_pair(rt->netns_storage_socket);
+        safe_close_pair(rt->ipcns_storage_socket);
         return mfree(rt);
 }
 
@@ -6055,6 +6114,7 @@ static int exec_runtime_allocate(ExecRuntime **ret, const char *id) {
         *n = (ExecRuntime) {
                 .id = TAKE_PTR(id_copy),
                 .netns_storage_socket = { -1, -1 },
+                .ipcns_storage_socket = { -1, -1 },
         };
 
         *ret = n;
@@ -6067,6 +6127,7 @@ static int exec_runtime_add(
                 char **tmp_dir,
                 char **var_tmp_dir,
                 int netns_storage_socket[2],
+                int ipcns_storage_socket[2],
                 ExecRuntime **ret) {
 
         _cleanup_(exec_runtime_freep) ExecRuntime *rt = NULL;
@@ -6075,7 +6136,7 @@ static int exec_runtime_add(
         assert(m);
         assert(id);
 
-        /* tmp_dir, var_tmp_dir, netns_storage_socket fds are donated on success */
+        /* tmp_dir, var_tmp_dir, {net,ipc}ns_storage_socket fds are donated on success */
 
         r = exec_runtime_allocate(&rt, id);
         if (r < 0)
@@ -6094,6 +6155,11 @@ static int exec_runtime_add(
                 rt->netns_storage_socket[1] = TAKE_FD(netns_storage_socket[1]);
         }
 
+        if (ipcns_storage_socket) {
+                rt->ipcns_storage_socket[0] = TAKE_FD(ipcns_storage_socket[0]);
+                rt->ipcns_storage_socket[1] = TAKE_FD(ipcns_storage_socket[1]);
+        }
+
         rt->manager = m;
 
         if (ret)
@@ -6110,7 +6176,7 @@ static int exec_runtime_make(
                 ExecRuntime **ret) {
 
         _cleanup_(namespace_cleanup_tmpdirp) char *tmp_dir = NULL, *var_tmp_dir = NULL;
-        _cleanup_close_pair_ int netns_storage_socket[2] = { -1, -1 };
+        _cleanup_close_pair_ int netns_storage_socket[2] = { -1, -1 }, ipcns_storage_socket[2] = { -1, -1 };
         int r;
 
         assert(m);
@@ -6118,7 +6184,7 @@ static int exec_runtime_make(
         assert(id);
 
         /* It is not necessary to create ExecRuntime object. */
-        if (!c->private_network && !c->private_tmp && !c->network_namespace_path) {
+        if (!c->private_network && !c->private_ipc && !c->private_tmp && !c->network_namespace_path) {
                 *ret = NULL;
                 return 0;
         }
@@ -6137,7 +6203,12 @@ static int exec_runtime_make(
                         return -errno;
         }
 
-        r = exec_runtime_add(m, id, &tmp_dir, &var_tmp_dir, netns_storage_socket, ret);
+        if (c->private_ipc || c->ipc_namespace_path) {
+                if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, ipcns_storage_socket) < 0)
+                        return -errno;
+        }
+
+        r = exec_runtime_add(m, id, &tmp_dir, &var_tmp_dir, netns_storage_socket, ipcns_storage_socket, ret);
         if (r < 0)
                 return r;
 
@@ -6228,6 +6299,26 @@ int exec_runtime_serialize(const Manager *m, FILE *f, FDSet *fds) {
                         fprintf(f, " netns-socket-1=%i", copy);
                 }
 
+                if (rt->ipcns_storage_socket[0] >= 0) {
+                        int copy;
+
+                        copy = fdset_put_dup(fds, rt->ipcns_storage_socket[0]);
+                        if (copy < 0)
+                                return copy;
+
+                        fprintf(f, " ipcns-socket-0=%i", copy);
+                }
+
+                if (rt->ipcns_storage_socket[1] >= 0) {
+                        int copy;
+
+                        copy = fdset_put_dup(fds, rt->ipcns_storage_socket[1]);
+                        if (copy < 0)
+                                return copy;
+
+                        fprintf(f, " ipcns-socket-1=%i", copy);
+                }
+
                 fputc('\n', f);
         }
 
@@ -6309,6 +6400,28 @@ int exec_runtime_deserialize_compat(Unit *u, const char *key, const char *value,
 
                 safe_close(rt->netns_storage_socket[1]);
                 rt->netns_storage_socket[1] = fdset_remove(fds, fd);
+
+        } else if (streq(key, "ipcns-socket-0")) {
+                int fd;
+
+                if (safe_atoi(value, &fd) < 0 || !fdset_contains(fds, fd)) {
+                        log_unit_debug(u, "Failed to parse ipcns socket value: %s", value);
+                        return 0;
+                }
+
+                safe_close(rt->ipcns_storage_socket[0]);
+                rt->ipcns_storage_socket[0] = fdset_remove(fds, fd);
+
+        } else if (streq(key, "ipcns-socket-1")) {
+                int fd;
+
+                if (safe_atoi(value, &fd) < 0 || !fdset_contains(fds, fd)) {
+                        log_unit_debug(u, "Failed to parse ipcns socket value: %s", value);
+                        return 0;
+                }
+
+                safe_close(rt->ipcns_storage_socket[1]);
+                rt->ipcns_storage_socket[1] = fdset_remove(fds, fd);
         } else
                 return 0;
 
@@ -6332,7 +6445,7 @@ int exec_runtime_deserialize_compat(Unit *u, const char *key, const char *value,
 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};
+        int r, netns_fdpair[] = {-1, -1}, ipcns_fdpair[] = {-1, -1};
         const char *p, *v = value;
         size_t n;
 
@@ -6375,13 +6488,13 @@ int exec_runtime_deserialize_one(Manager *m, const char *value, FDSet *fds) {
                 n = strcspn(v, " ");
                 buf = strndupa(v, n);
 
-                r = safe_atoi(buf, &fdpair[0]);
+                r = safe_atoi(buf, &netns_fdpair[0]);
                 if (r < 0)
                         return log_debug_errno(r, "Unable to parse exec-runtime specification netns-socket-0=%s: %m", buf);
-                if (!fdset_contains(fds, fdpair[0]))
+                if (!fdset_contains(fds, netns_fdpair[0]))
                         return log_debug_errno(SYNTHETIC_ERRNO(EBADF),
-                                               "exec-runtime specification netns-socket-0= refers to unknown fd %d: %m", fdpair[0]);
-                fdpair[0] = fdset_remove(fds, fdpair[0]);
+                                               "exec-runtime specification netns-socket-0= refers to unknown fd %d: %m", netns_fdpair[0]);
+                netns_fdpair[0] = fdset_remove(fds, netns_fdpair[0]);
                 if (v[n] != ' ')
                         goto finalize;
                 p = v + n + 1;
@@ -6393,17 +6506,56 @@ int exec_runtime_deserialize_one(Manager *m, const char *value, FDSet *fds) {
 
                 n = strcspn(v, " ");
                 buf = strndupa(v, n);
-                r = safe_atoi(buf, &fdpair[1]);
+
+                r = safe_atoi(buf, &netns_fdpair[1]);
                 if (r < 0)
                         return log_debug_errno(r, "Unable to parse exec-runtime specification netns-socket-1=%s: %m", buf);
-                if (!fdset_contains(fds, fdpair[1]))
+                if (!fdset_contains(fds, netns_fdpair[1]))
+                        return log_debug_errno(SYNTHETIC_ERRNO(EBADF),
+                                               "exec-runtime specification netns-socket-1= refers to unknown fd %d: %m", netns_fdpair[1]);
+                netns_fdpair[1] = fdset_remove(fds, netns_fdpair[1]);
+                if (v[n] != ' ')
+                        goto finalize;
+                p = v + n + 1;
+        }
+
+        v = startswith(p, "ipcns-socket-0=");
+        if (v) {
+                char *buf;
+
+                n = strcspn(v, " ");
+                buf = strndupa(v, n);
+
+                r = safe_atoi(buf, &ipcns_fdpair[0]);
+                if (r < 0)
+                        return log_debug_errno(r, "Unable to parse exec-runtime specification ipcns-socket-0=%s: %m", buf);
+                if (!fdset_contains(fds, ipcns_fdpair[0]))
+                        return log_debug_errno(SYNTHETIC_ERRNO(EBADF),
+                                               "exec-runtime specification ipcns-socket-0= refers to unknown fd %d: %m", ipcns_fdpair[0]);
+                ipcns_fdpair[0] = fdset_remove(fds, ipcns_fdpair[0]);
+                if (v[n] != ' ')
+                        goto finalize;
+                p = v + n + 1;
+        }
+
+        v = startswith(p, "ipcns-socket-1=");
+        if (v) {
+                char *buf;
+
+                n = strcspn(v, " ");
+                buf = strndupa(v, n);
+
+                r = safe_atoi(buf, &ipcns_fdpair[1]);
+                if (r < 0)
+                        return log_debug_errno(r, "Unable to parse exec-runtime specification ipcns-socket-1=%s: %m", buf);
+                if (!fdset_contains(fds, ipcns_fdpair[1]))
                         return log_debug_errno(SYNTHETIC_ERRNO(EBADF),
-                                               "exec-runtime specification netns-socket-1= refers to unknown fd %d: %m", fdpair[1]);
-                fdpair[1] = fdset_remove(fds, fdpair[1]);
+                                               "exec-runtime specification ipcns-socket-1= refers to unknown fd %d: %m", ipcns_fdpair[1]);
+                ipcns_fdpair[1] = fdset_remove(fds, ipcns_fdpair[1]);
         }
 
 finalize:
-        r = exec_runtime_add(m, id, &tmp_dir, &var_tmp_dir, fdpair, NULL);
+        r = exec_runtime_add(m, id, &tmp_dir, &var_tmp_dir, netns_fdpair, ipcns_fdpair, NULL);
         if (r < 0)
                 return log_debug_errno(r, "Failed to add exec-runtime: %m");
         return 0;