]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/core/execute.c
Merge pull request #17079 from keszybz/late-exec-resolution
[thirdparty/systemd.git] / src / core / execute.c
index 11e172f61b4d1602ff978f825b2edff806df3ed5..8f901fa7154d460efe03e9367444787e46f89c2e 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include <errno.h>
 #include <fcntl.h>
@@ -73,6 +73,7 @@
 #include "parse-util.h"
 #include "path-util.h"
 #include "process-util.h"
+#include "random-util.h"
 #include "rlimit-util.h"
 #include "rm-rf.h"
 #if HAVE_SECCOMP
@@ -2509,6 +2510,7 @@ static int write_credential(
 static int acquire_credentials(
                 const ExecContext *context,
                 const ExecParameters *params,
+                const char *unit,
                 const char *p,
                 uid_t uid,
                 bool ownership_ok) {
@@ -2546,7 +2548,7 @@ static int acquire_credentials(
         STRV_FOREACH_PAIR(id, fn, context->load_credentials) {
                 ReadFullFileFlags flags = READ_FULL_FILE_SECURE;
                 _cleanup_(erase_and_freep) char *data = NULL;
-                _cleanup_free_ char *j = NULL;
+                _cleanup_free_ char *j = NULL, *bindname = NULL;
                 const char *source;
                 size_t size, add;
 
@@ -2554,6 +2556,12 @@ static int acquire_credentials(
                         /* If this is an absolute path, read the data directly from it, and support AF_UNIX sockets */
                         source = *fn;
                         flags |= READ_FULL_FILE_CONNECT_SOCKET;
+
+                        /* Pass some minimal info about the unit and the credential name we are looking to acquire
+                         * via the source socket address in case we read off an AF_UNIX socket. */
+                        if (asprintf(&bindname, "@%" PRIx64"/unit/%s/%s", random_u64(), unit, *id) < 0)
+                                return -ENOMEM;
+
                 } else if (params->received_credentials) {
                         /* If this is a relative path, take it relative to the credentials we received
                          * ourselves. We don't support the AF_UNIX stuff in this mode, since we are operating
@@ -2566,8 +2574,9 @@ static int acquire_credentials(
                 } else
                         source = NULL;
 
+
                 if (source)
-                        r = read_full_file_full(AT_FDCWD, source, flags, &data, &size);
+                        r = read_full_file_full(AT_FDCWD, source, UINT64_MAX, SIZE_MAX, flags, bindname, &data, &size);
                 else
                         r = -ENOENT;
                 if (r == -ENOENT &&
@@ -2613,6 +2622,7 @@ static int acquire_credentials(
 static int setup_credentials_internal(
                 const ExecContext *context,
                 const ExecParameters *params,
+                const char *unit,
                 const char *final,        /* This is where the credential store shall eventually end up at */
                 const char *workspace,    /* This is where we can prepare it before moving it to the final place */
                 bool reuse_workspace,     /* Whether to reuse any existing workspace mount if it already is a mount */
@@ -2724,7 +2734,7 @@ static int setup_credentials_internal(
         assert(!must_mount || workspace_mounted > 0);
         where = workspace_mounted ? workspace : final;
 
-        r = acquire_credentials(context, params, where, uid, workspace_mounted);
+        r = acquire_credentials(context, params, unit, where, uid, workspace_mounted);
         if (r < 0)
                 return r;
 
@@ -2824,6 +2834,7 @@ static int setup_credentials(
                 r = setup_credentials_internal(
                                 context,
                                 params,
+                                unit,
                                 p,       /* final mount point */
                                 u,       /* temporary workspace to overmount */
                                 true,    /* reuse the workspace if it is already a mount */
@@ -2861,6 +2872,7 @@ static int setup_credentials(
                 r = setup_credentials_internal(
                                 context,
                                 params,
+                                unit,
                                 p,           /* final mount point */
                                 "/dev/shm",  /* temporary workspace to overmount */
                                 false,       /* do not reuse /dev/shm if it is already a mount, under no circumstances */
@@ -3793,23 +3805,20 @@ static int exec_child(
                 r = dynamic_creds_realize(dcreds, suggested_paths, &uid, &gid);
                 if (r < 0) {
                         *exit_status = EXIT_USER;
-                        if (r == -EILSEQ) {
-                                log_unit_error(unit, "Failed to update dynamic user credentials: User or group with specified name already exists.");
-                                return -EOPNOTSUPP;
-                        }
+                        if (r == -EILSEQ)
+                                return log_unit_error_errno(unit, SYNTHETIC_ERRNO(EOPNOTSUPP),
+                                                            "Failed to update dynamic user credentials: User or group with specified name already exists.");
                         return log_unit_error_errno(unit, r, "Failed to update dynamic user credentials: %m");
                 }
 
                 if (!uid_is_valid(uid)) {
                         *exit_status = EXIT_USER;
-                        log_unit_error(unit, "UID validation failed for \""UID_FMT"\"", uid);
-                        return -ESRCH;
+                        return log_unit_error_errno(unit, SYNTHETIC_ERRNO(ESRCH), "UID validation failed for \""UID_FMT"\"", uid);
                 }
 
                 if (!gid_is_valid(gid)) {
                         *exit_status = EXIT_USER;
-                        log_unit_error(unit, "GID validation failed for \""GID_FMT"\"", gid);
-                        return -ESRCH;
+                        return log_unit_error_errno(unit, SYNTHETIC_ERRNO(ESRCH), "GID validation failed for \""GID_FMT"\"", gid);
                 }
 
                 if (dcreds->user)
@@ -4625,15 +4634,11 @@ int exec_spawn(Unit *unit,
             context->std_output == EXEC_OUTPUT_SOCKET ||
             context->std_error == EXEC_OUTPUT_SOCKET) {
 
-                if (params->n_socket_fds > 1) {
-                        log_unit_error(unit, "Got more than one socket.");
-                        return -EINVAL;
-                }
+                if (params->n_socket_fds > 1)
+                        return log_unit_error_errno(unit, SYNTHETIC_ERRNO(EINVAL), "Got more than one socket.");
 
-                if (params->n_socket_fds == 0) {
-                        log_unit_error(unit, "Got no socket.");
-                        return -EINVAL;
-                }
+                if (params->n_socket_fds == 0)
+                        return log_unit_error_errno(unit, SYNTHETIC_ERRNO(EINVAL), "Got no socket.");
 
                 socket_fd = params->fds[0];
         } else {
@@ -6077,7 +6082,12 @@ static int exec_runtime_add(
         return 0;
 }
 
-static int exec_runtime_make(Manager *m, const ExecContext *c, const char *id, ExecRuntime **ret) {
+static int exec_runtime_make(
+                Manager *m,
+                const ExecContext *c,
+                const char *id,
+                ExecRuntime **ret) {
+
         _cleanup_(namespace_cleanup_tmpdirp) char *tmp_dir = NULL, *var_tmp_dir = NULL;
         _cleanup_close_pair_ int netns_storage_socket[2] = { -1, -1 };
         int r;
@@ -6087,8 +6097,10 @@ static int exec_runtime_make(Manager *m, const ExecContext *c, const char *id, E
         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_tmp && !c->network_namespace_path) {
+                *ret = NULL;
                 return 0;
+        }
 
         if (c->private_tmp &&
             !(prefixed_path_strv_contains(c->inaccessible_paths, "/tmp") &&
@@ -6124,14 +6136,20 @@ int exec_runtime_acquire(Manager *m, const ExecContext *c, const char *id, bool
                 /* We already have a ExecRuntime object, let's increase the ref count and reuse it */
                 goto ref;
 
-        if (!create)
+        if (!create) {
+                *ret = NULL;
                 return 0;
+        }
 
         /* If not found, then create a new object. */
         r = exec_runtime_make(m, c, id, &rt);
-        if (r <= 0)
-                /* When r == 0, it is not necessary to create ExecRuntime object. */
+        if (r < 0)
                 return r;
+        if (r == 0) {
+                /* When r == 0, it is not necessary to create ExecRuntime object. */
+                *ret = NULL;
+                return 0;
+        }
 
 ref:
         /* increment reference counter. */
@@ -6357,7 +6375,7 @@ int exec_runtime_deserialize_one(Manager *m, const char *value, FDSet *fds) {
                 r = safe_atoi(buf, &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[0]))
+                if (!fdset_contains(fds, 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]);