-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <errno.h>
#include <fcntl.h>
#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
static int acquire_credentials(
const ExecContext *context,
const ExecParameters *params,
+ const char *unit,
const char *p,
uid_t uid,
bool ownership_ok) {
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;
/* 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
} 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 &&
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 */
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;
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 */
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 */
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)
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 {
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;
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") &&
/* 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. */
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]);