core/exec-credential: only pass needed bits of ExecParameters down in exec_setup_credentials()
No functional change, preparation for credential reloading support, where we'd operate on Unit rather than ExecParameters.
This commit is contained in:
+92
-87
@@ -310,6 +310,34 @@ int exec_context_destroy_credentials(const ExecContext *c, const char *runtime_p
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef struct SetupCredentialsContext {
|
||||
RuntimeScope scope;
|
||||
|
||||
const ExecContext *exec_context;
|
||||
const char *unit;
|
||||
|
||||
const char *runtime_prefix;
|
||||
|
||||
const char *received_credentials_directory;
|
||||
const char *received_encrypted_credentials_directory;
|
||||
|
||||
bool always_ipc;
|
||||
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
} SetupCredentialsContext;
|
||||
|
||||
typedef struct LoadCredentialArguments {
|
||||
const SetupCredentialsContext *context;
|
||||
|
||||
bool encrypted;
|
||||
|
||||
int write_dfd;
|
||||
bool ownership_ok;
|
||||
|
||||
uint64_t left;
|
||||
} LoadCredentialArguments;
|
||||
|
||||
typedef enum CredentialSearchPath {
|
||||
CREDENTIAL_SEARCH_PATH_TRUSTED,
|
||||
CREDENTIAL_SEARCH_PATH_ENCRYPTED,
|
||||
@@ -318,11 +346,15 @@ typedef enum CredentialSearchPath {
|
||||
_CREDENTIAL_SEARCH_PATH_INVALID = -EINVAL,
|
||||
} CredentialSearchPath;
|
||||
|
||||
static int credential_search_path(const ExecParameters *params, CredentialSearchPath path, char ***ret) {
|
||||
static int credential_search_path(
|
||||
const SetupCredentialsContext *context,
|
||||
CredentialSearchPath path,
|
||||
char ***ret) {
|
||||
|
||||
_cleanup_strv_free_ char **l = NULL;
|
||||
int r;
|
||||
|
||||
assert(params);
|
||||
assert(context);
|
||||
assert(path >= 0 && path < _CREDENTIAL_SEARCH_PATH_MAX);
|
||||
assert(ret);
|
||||
|
||||
@@ -331,12 +363,12 @@ static int credential_search_path(const ExecParameters *params, CredentialSearch
|
||||
* credentials, we'll look in /etc/credstore.encrypted/ (and similar dirs). */
|
||||
|
||||
if (IN_SET(path, CREDENTIAL_SEARCH_PATH_ENCRYPTED, CREDENTIAL_SEARCH_PATH_ALL)) {
|
||||
r = strv_extend(&l, params->received_encrypted_credentials_directory);
|
||||
r = strv_extend(&l, context->received_encrypted_credentials_directory);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
_cleanup_strv_free_ char **add = NULL;
|
||||
r = credential_store_path_encrypted(params->runtime_scope, &add);
|
||||
r = credential_store_path_encrypted(context->scope, &add);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -346,12 +378,12 @@ static int credential_search_path(const ExecParameters *params, CredentialSearch
|
||||
}
|
||||
|
||||
if (IN_SET(path, CREDENTIAL_SEARCH_PATH_TRUSTED, CREDENTIAL_SEARCH_PATH_ALL)) {
|
||||
r = strv_extend(&l, params->received_credentials_directory);
|
||||
r = strv_extend(&l, context->received_credentials_directory);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
_cleanup_strv_free_ char **add = NULL;
|
||||
r = credential_store_path(params->runtime_scope, &add);
|
||||
r = credential_store_path(context->scope, &add);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -369,23 +401,6 @@ static int credential_search_path(const ExecParameters *params, CredentialSearch
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct load_cred_args {
|
||||
const ExecContext *context;
|
||||
const ExecParameters *params;
|
||||
const char *unit;
|
||||
|
||||
bool always_ipc;
|
||||
|
||||
bool encrypted;
|
||||
|
||||
int write_dfd;
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
bool ownership_ok;
|
||||
|
||||
uint64_t left;
|
||||
};
|
||||
|
||||
static int write_credential(
|
||||
int dfd,
|
||||
const char *id,
|
||||
@@ -431,7 +446,7 @@ static int write_credential(
|
||||
}
|
||||
|
||||
static int maybe_decrypt_and_write_credential(
|
||||
struct load_cred_args *args,
|
||||
LoadCredentialArguments *args,
|
||||
const char *id,
|
||||
const char *data,
|
||||
size_t size,
|
||||
@@ -449,7 +464,7 @@ static int maybe_decrypt_and_write_credential(
|
||||
if (args->encrypted) {
|
||||
CredentialFlags flags = 0; /* only allow user creds in user scope */
|
||||
|
||||
switch (args->params->runtime_scope) {
|
||||
switch (args->context->scope) {
|
||||
|
||||
case RUNTIME_SCOPE_SYSTEM:
|
||||
/* In system mode talk directly to the TPM – unless we live in a device sandbox
|
||||
@@ -457,7 +472,7 @@ static int maybe_decrypt_and_write_credential(
|
||||
|
||||
flags |= CREDENTIAL_ANY_SCOPE;
|
||||
|
||||
if (!args->always_ipc) {
|
||||
if (!args->context->always_ipc) {
|
||||
r = decrypt_credential_and_warn(
|
||||
id,
|
||||
now(CLOCK_REALTIME),
|
||||
@@ -506,7 +521,7 @@ static int maybe_decrypt_and_write_credential(
|
||||
if (add > args->left)
|
||||
return -E2BIG;
|
||||
|
||||
r = write_credential(args->write_dfd, id, data, size, args->uid, args->gid, args->ownership_ok);
|
||||
r = write_credential(args->write_dfd, id, data, size, args->context->uid, args->context->gid, args->ownership_ok);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to write credential '%s': %m", id);
|
||||
|
||||
@@ -516,7 +531,7 @@ static int maybe_decrypt_and_write_credential(
|
||||
}
|
||||
|
||||
static int load_credential_glob(
|
||||
struct load_cred_args *args,
|
||||
LoadCredentialArguments *args,
|
||||
const ExecImportCredential *ic,
|
||||
char * const *search_path,
|
||||
ReadFullFileFlags flags) {
|
||||
@@ -595,7 +610,7 @@ static int load_credential_glob(
|
||||
}
|
||||
|
||||
static int load_credential(
|
||||
struct load_cred_args *args,
|
||||
LoadCredentialArguments *args,
|
||||
const char *id,
|
||||
int read_dfd,
|
||||
const char *path) {
|
||||
@@ -611,9 +626,8 @@ static int load_credential(
|
||||
|
||||
assert(args);
|
||||
assert(args->context);
|
||||
assert(args->params);
|
||||
assert(args->unit);
|
||||
assert(args->write_dfd >= 0);
|
||||
assert(args->context->exec_context);
|
||||
assert(args->context->unit);
|
||||
assert(id);
|
||||
assert(read_dfd >= 0 || read_dfd == AT_FDCWD);
|
||||
assert(path);
|
||||
@@ -641,7 +655,7 @@ static int load_credential(
|
||||
|
||||
/* 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(), args->unit, id) < 0)
|
||||
if (asprintf(&bindname, "@%" PRIx64 "/unit/%s/%s", random_u64(), args->context->unit, id) < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
missing_ok = false;
|
||||
@@ -652,7 +666,7 @@ static int load_credential(
|
||||
* directory we received ourselves. We don't support the AF_UNIX stuff in this mode, since we
|
||||
* are operating on a credential store, i.e. this is guaranteed to be regular files. */
|
||||
|
||||
r = credential_search_path(args->params, CREDENTIAL_SEARCH_PATH_ALL, &search_path);
|
||||
r = credential_search_path(args->context, CREDENTIAL_SEARCH_PATH_ALL, &search_path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -696,7 +710,7 @@ static int load_credential(
|
||||
assert_not_reached();
|
||||
|
||||
if (r == -ENOENT) {
|
||||
bool in_set_credentials = hashmap_contains(args->context->set_credentials, id);
|
||||
bool in_set_credentials = hashmap_contains(args->context->exec_context->set_credentials, id);
|
||||
if (missing_ok || in_set_credentials) {
|
||||
/* Make a missing inherited credential non-fatal, let's just continue. After all apps
|
||||
* will get clear errors if we don't pass such a missing credential on as they
|
||||
@@ -725,7 +739,7 @@ static int load_cred_recurse_dir_cb(
|
||||
const struct statx *sx,
|
||||
void *userdata) {
|
||||
|
||||
struct load_cred_args *args = ASSERT_PTR(userdata);
|
||||
LoadCredentialArguments *args = ASSERT_PTR(userdata);
|
||||
_cleanup_free_ char *sub_id = NULL;
|
||||
int r;
|
||||
|
||||
@@ -782,38 +796,27 @@ static bool device_nodes_restricted(
|
||||
}
|
||||
|
||||
static int acquire_credentials(
|
||||
const ExecContext *context,
|
||||
const CGroupContext *cgroup_context,
|
||||
const ExecParameters *params,
|
||||
const char *unit,
|
||||
const SetupCredentialsContext *context,
|
||||
int dfd,
|
||||
uid_t uid,
|
||||
gid_t gid,
|
||||
bool ownership_ok) {
|
||||
|
||||
int r;
|
||||
|
||||
assert(context);
|
||||
assert(cgroup_context);
|
||||
assert(params);
|
||||
assert(unit);
|
||||
assert(context->exec_context);
|
||||
assert(dfd >= 0);
|
||||
|
||||
struct load_cred_args args = {
|
||||
LoadCredentialArguments args = {
|
||||
.context = context,
|
||||
.params = params,
|
||||
.unit = unit,
|
||||
.always_ipc = device_nodes_restricted(context, cgroup_context),
|
||||
|
||||
.write_dfd = dfd,
|
||||
.uid = uid,
|
||||
.gid = gid,
|
||||
.ownership_ok = ownership_ok,
|
||||
.left = CREDENTIALS_TOTAL_SIZE_MAX,
|
||||
};
|
||||
|
||||
/* First, load credentials off disk (or acquire via AF_UNIX socket) */
|
||||
ExecLoadCredential *lc;
|
||||
HASHMAP_FOREACH(lc, context->load_credentials) {
|
||||
HASHMAP_FOREACH(lc, context->exec_context->load_credentials) {
|
||||
_cleanup_close_ int sub_fd = -EBADF;
|
||||
|
||||
args.encrypted = lc->encrypted;
|
||||
@@ -852,10 +855,10 @@ static int acquire_credentials(
|
||||
/* Next, look for system credentials and credentials in the credentials store. Note that these do not
|
||||
* override any credentials found earlier. */
|
||||
ExecImportCredential *ic;
|
||||
ORDERED_SET_FOREACH(ic, context->import_credentials) {
|
||||
ORDERED_SET_FOREACH(ic, context->exec_context->import_credentials) {
|
||||
_cleanup_free_ char **search_path = NULL;
|
||||
|
||||
r = credential_search_path(params, CREDENTIAL_SEARCH_PATH_TRUSTED, &search_path);
|
||||
r = credential_search_path(context, CREDENTIAL_SEARCH_PATH_TRUSTED, &search_path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -871,7 +874,7 @@ static int acquire_credentials(
|
||||
|
||||
search_path = strv_free(search_path);
|
||||
|
||||
r = credential_search_path(params, CREDENTIAL_SEARCH_PATH_ENCRYPTED, &search_path);
|
||||
r = credential_search_path(context, CREDENTIAL_SEARCH_PATH_ENCRYPTED, &search_path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -889,7 +892,7 @@ static int acquire_credentials(
|
||||
/* Finally, we add in literally specified credentials. If the credentials already exist, we'll not
|
||||
* add them, so that they can act as a "default" if the same credential is specified multiple times. */
|
||||
ExecSetCredential *sc;
|
||||
HASHMAP_FOREACH(sc, context->set_credentials) {
|
||||
HASHMAP_FOREACH(sc, context->exec_context->set_credentials) {
|
||||
args.encrypted = sc->encrypted;
|
||||
|
||||
if (faccessat(dfd, sc->id, F_OK, AT_SYMLINK_NOFOLLOW) >= 0) {
|
||||
@@ -937,13 +940,8 @@ static int credentials_dir_finalize_permissions(int dfd, uid_t uid, gid_t gid, b
|
||||
}
|
||||
|
||||
static int setup_credentials_plain_dir(
|
||||
const ExecContext *context,
|
||||
const CGroupContext *cgroup_context,
|
||||
const ExecParameters *params,
|
||||
const char *unit,
|
||||
const char *cred_dir,
|
||||
uid_t uid,
|
||||
gid_t gid) {
|
||||
const SetupCredentialsContext *context,
|
||||
const char *cred_dir) {
|
||||
|
||||
_cleanup_free_ char *t = NULL, *workspace = NULL;
|
||||
_cleanup_(rm_rf_safep) const char *workspace_rm = NULL;
|
||||
@@ -951,13 +949,13 @@ static int setup_credentials_plain_dir(
|
||||
int r;
|
||||
|
||||
assert(context);
|
||||
assert(params);
|
||||
assert(unit);
|
||||
assert(context->unit);
|
||||
assert(context->runtime_prefix);
|
||||
assert(cred_dir);
|
||||
|
||||
/* Temporary workspace, that remains inaccessible all the time. We prepare stuff there before moving
|
||||
* it into place, so that users can't access half-initialized credential stores. */
|
||||
t = path_join(params->prefix[EXEC_DIRECTORY_RUNTIME], "systemd/temporary-credentials");
|
||||
t = path_join(context->runtime_prefix, "systemd/temporary-credentials");
|
||||
if (!t)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -965,7 +963,7 @@ static int setup_credentials_plain_dir(
|
||||
if (r < 0 && r != -EEXIST)
|
||||
return r;
|
||||
|
||||
workspace = path_join(t, unit);
|
||||
workspace = path_join(t, context->unit);
|
||||
if (!workspace)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -976,7 +974,7 @@ static int setup_credentials_plain_dir(
|
||||
|
||||
(void) label_fix_full(dfd, /* inode_path= */ NULL, cred_dir, /* flags= */ 0);
|
||||
|
||||
r = acquire_credentials(context, cgroup_context, params, unit, dfd, uid, gid, /* ownership_ok= */ false);
|
||||
r = acquire_credentials(context, dfd, /* ownership_ok= */ false);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -998,7 +996,7 @@ static int setup_credentials_plain_dir(
|
||||
|
||||
/* rename() requires both the source and target to be writable, hence lock down write permission
|
||||
* as last step. */
|
||||
r = credentials_dir_finalize_permissions(dfd, uid, gid, /* ownership_ok= */ false);
|
||||
r = credentials_dir_finalize_permissions(dfd, context->uid, context->gid, /* ownership_ok= */ false);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to adjust ACLs of credentials dir: %m");
|
||||
|
||||
@@ -1006,21 +1004,15 @@ static int setup_credentials_plain_dir(
|
||||
}
|
||||
|
||||
static int setup_credentials_internal(
|
||||
const ExecContext *context,
|
||||
const CGroupContext *cgroup_context,
|
||||
const ExecParameters *params,
|
||||
const char *unit,
|
||||
const char *cred_dir,
|
||||
uid_t uid,
|
||||
gid_t gid) {
|
||||
const SetupCredentialsContext *context,
|
||||
bool may_reuse,
|
||||
const char *cred_dir) {
|
||||
|
||||
_cleanup_close_ int fs_fd = -EBADF, mfd = -EBADF, dfd = -EBADF;
|
||||
bool dir_mounted;
|
||||
int r;
|
||||
|
||||
assert(context);
|
||||
assert(params);
|
||||
assert(unit);
|
||||
assert(cred_dir);
|
||||
|
||||
r = path_is_mount_point(cred_dir);
|
||||
@@ -1028,7 +1020,7 @@ static int setup_credentials_internal(
|
||||
return log_debug_errno(r, "Failed to determine if '%s' is a mountpoint: %m", cred_dir);
|
||||
dir_mounted = r > 0;
|
||||
|
||||
if (!FLAGS_SET(params->flags, EXEC_SETUP_CREDENTIALS_FRESH)) {
|
||||
if (may_reuse) {
|
||||
bool populated;
|
||||
|
||||
/* If the cred dir is a mount, let's treat it as populated, and only look at the contents
|
||||
@@ -1044,7 +1036,7 @@ static int setup_credentials_internal(
|
||||
populated = r == 0;
|
||||
}
|
||||
if (populated) {
|
||||
log_debug("Credential dir for unit '%s' already set up, skipping.", unit);
|
||||
log_debug("Credential dir for unit '%s' already set up, skipping.", context->unit);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -1052,7 +1044,7 @@ static int setup_credentials_internal(
|
||||
mfd = fsmount_credentials_fs(&fs_fd);
|
||||
if (ERRNO_IS_NEG_PRIVILEGE(mfd) && !dir_mounted) {
|
||||
log_debug_errno(mfd, "Lacking privilege to mount credentials fs, falling back to plain directory.");
|
||||
return setup_credentials_plain_dir(context, cgroup_context, params, unit, cred_dir, uid, gid);
|
||||
return setup_credentials_plain_dir(context, cred_dir);
|
||||
}
|
||||
if (mfd < 0)
|
||||
return log_debug_errno(mfd, "Failed to mount credentials fs: %m");
|
||||
@@ -1063,11 +1055,11 @@ static int setup_credentials_internal(
|
||||
|
||||
(void) label_fix_full(dfd, /* inode_path= */ NULL, cred_dir, /* flags= */ 0);
|
||||
|
||||
r = acquire_credentials(context, cgroup_context, params, unit, dfd, uid, gid, /* ownership_ok= */ true);
|
||||
r = acquire_credentials(context, dfd, /* ownership_ok= */ true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = credentials_dir_finalize_permissions(dfd, uid, gid, /* ownership_ok= */ true);
|
||||
r = credentials_dir_finalize_permissions(dfd, context->uid, context->gid, /* ownership_ok= */ true);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to adjust ACLs of credentials dir: %m");
|
||||
|
||||
@@ -1112,7 +1104,6 @@ int exec_setup_credentials(
|
||||
const ExecContext *context,
|
||||
const CGroupContext *cgroup_context,
|
||||
const ExecParameters *params,
|
||||
const char *unit,
|
||||
uid_t uid,
|
||||
gid_t gid) {
|
||||
|
||||
@@ -1121,7 +1112,6 @@ int exec_setup_credentials(
|
||||
|
||||
assert(context);
|
||||
assert(params);
|
||||
assert(unit);
|
||||
|
||||
if (!exec_params_need_credentials(params) || !exec_context_has_credentials(context))
|
||||
return 0;
|
||||
@@ -1139,7 +1129,7 @@ int exec_setup_credentials(
|
||||
if (r < 0 && r != -EEXIST)
|
||||
return r;
|
||||
|
||||
p = path_join(q, unit);
|
||||
p = path_join(q, params->unit_id);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -1147,7 +1137,22 @@ int exec_setup_credentials(
|
||||
if (r < 0 && r != -EEXIST)
|
||||
return r;
|
||||
|
||||
r = setup_credentials_internal(context, cgroup_context, params, unit, p, uid, gid);
|
||||
SetupCredentialsContext ctx = {
|
||||
.scope = params->runtime_scope,
|
||||
.exec_context = context,
|
||||
.unit = params->unit_id,
|
||||
|
||||
.runtime_prefix = params->prefix[EXEC_DIRECTORY_RUNTIME],
|
||||
.received_credentials_directory = params->received_credentials_directory,
|
||||
.received_encrypted_credentials_directory = params->received_encrypted_credentials_directory,
|
||||
|
||||
.always_ipc = device_nodes_restricted(context, cgroup_context),
|
||||
|
||||
.uid = uid,
|
||||
.gid = gid,
|
||||
};
|
||||
|
||||
r = setup_credentials_internal(&ctx, /* may_reuse = */ !FLAGS_SET(params->flags, EXEC_SETUP_CREDENTIALS_FRESH), p);
|
||||
if (r < 0)
|
||||
(void) rmdir(p);
|
||||
|
||||
|
||||
@@ -57,7 +57,6 @@ int exec_setup_credentials(
|
||||
const ExecContext *context,
|
||||
const CGroupContext *cgroup_context,
|
||||
const ExecParameters *params,
|
||||
const char *unit,
|
||||
uid_t uid,
|
||||
gid_t gid);
|
||||
|
||||
|
||||
@@ -5705,7 +5705,7 @@ int exec_invoke(
|
||||
return log_error_errno(r, "Failed to set up special execution directory in %s: %m", params->prefix[dt]);
|
||||
}
|
||||
|
||||
r = exec_setup_credentials(context, cgroup_context, params, params->unit_id, uid, gid);
|
||||
r = exec_setup_credentials(context, cgroup_context, params, uid, gid);
|
||||
if (r < 0) {
|
||||
*exit_status = EXIT_CREDENTIALS;
|
||||
return log_error_errno(r, "Failed to set up credentials: %m");
|
||||
|
||||
Reference in New Issue
Block a user