1
0
mirror of https://github.com/systemd/systemd.git synced 2025-03-19 22:50:17 +03:00

pid1: search for creds in LoadCredential=/LoadCredentialEncrypted=

This adds support for searching for credentials more comprehensively.

Specifically, unless an absolute source path is specified we'll now
search for the credentials in the system credentials first, and then in
/etc/credstore/, /run/credstore/, and /usr/lib/credstore, making these
dirs hence the recommended place for credentials to leave in the system.

For LoadCredentialEncrypted= we'll also look into
/etc/credstore.encrypted/, /run/credstore.encrypted/, …. These dirs are
hence suitable for credentials whose provenience isn't trusted (e.g.
UEFI creds from systemd-stub), and thus require to be authenticated
before use.
This commit is contained in:
Lennart Poettering 2022-04-21 15:32:21 +02:00
parent 4b9a4b0179
commit 2ad591a3a3
5 changed files with 133 additions and 27 deletions

View File

@ -2595,6 +2595,42 @@ static int write_credential(
return 0;
}
static char **credential_search_path(
const ExecParameters *params,
bool encrypted) {
_cleanup_strv_free_ char **l = NULL;
assert(params);
/* Assemble a search path to find credentials in. We'll look in /etc/credstore/ (and similar
* directories in /usr/lib/ + /run/) for all types of credentials. If we are looking for encrypted
* credentials, also look in /etc/credstore.encrypted/ (and similar dirs). */
if (encrypted) {
if (strv_extend(&l, params->received_encrypted_credentials_directory) < 0)
return NULL;
if (strv_extend_strv(&l, CONF_PATHS_STRV("credstore.encrypted"), /* filter_duplicates= */ true) < 0)
return NULL;
}
if (params->received_credentials_directory)
if (strv_extend(&l, params->received_credentials_directory) < 0)
return NULL;
if (strv_extend_strv(&l, CONF_PATHS_STRV("credstore"), /* filter_duplicates= */ true) < 0)
return NULL;
if (DEBUG_LOGGING) {
_cleanup_free_ char *t = strv_join(l, ":");
log_debug("Credential search path is: %s", t);
}
return TAKE_PTR(l);
}
static int load_credential(
const ExecContext *context,
const ExecParameters *params,
@ -2609,11 +2645,12 @@ static int load_credential(
uint64_t *left) {
ReadFullFileFlags flags = READ_FULL_FILE_SECURE|READ_FULL_FILE_FAIL_WHEN_LARGER;
_cleanup_strv_free_ char **search_path = NULL;
_cleanup_(erase_and_freep) char *data = NULL;
_cleanup_free_ char *j = NULL, *bindname = NULL;
_cleanup_free_ char *bindname = NULL;
const char *source = NULL;
bool missing_ok = true;
const char *source;
size_t size, add;
size_t size, add, maxsz;
int r;
assert(context);
@ -2624,10 +2661,25 @@ static int load_credential(
assert(write_dfd >= 0);
assert(left);
if (path_is_absolute(path) || read_dfd >= 0) {
/* If this is an absolute path (or a directory fd is specifier relative which to read), read
* the data directly from it, and support AF_UNIX sockets */
if (read_dfd >= 0) {
/* If a directory fd is specified, then read the file directly from that dir. In this case we
* won't do AF_UNIX stuff (we simply don't want to recursively iterate down a tree of AF_UNIX
* IPC sockets). It's OK if a file vanishes here in the time we enumerate it and intend to
* open it. */
if (!filename_is_valid(path)) /* safety check */
return -EINVAL;
missing_ok = true;
source = path;
} else if (path_is_absolute(path)) {
/* If this is an absolute path, read the data directly from it, and support AF_UNIX
* sockets */
if (!path_is_valid(path)) /* safety check */
return -EINVAL;
flags |= READ_FULL_FILE_CONNECT_SOCKET;
/* Pass some minimal info about the unit and the credential name we are looking to acquire
@ -2636,25 +2688,50 @@ static int load_credential(
return -ENOMEM;
missing_ok = false;
source = path;
} 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
* on a credential store, i.e. this is guaranteed to be regular files. */
j = path_join(params->received_credentials, path);
if (!j)
} else if (credential_name_valid(path)) {
/* If this is a relative path, take it as credential name relative to the credentials
* 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. */
search_path = credential_search_path(params, encrypted);
if (!search_path)
return -ENOMEM;
source = j;
missing_ok = true;
} else
source = NULL;
if (source)
if (encrypted)
flags |= READ_FULL_FILE_UNBASE64;
maxsz = encrypted ? CREDENTIAL_ENCRYPTED_SIZE_MAX : CREDENTIAL_SIZE_MAX;
if (search_path) {
STRV_FOREACH(d, search_path) {
_cleanup_free_ char *j = NULL;
j = path_join(*d, path);
if (!j)
return -ENOMEM;
r = read_full_file_full(
AT_FDCWD, j, /* path is absolute, hence pass AT_FDCWD as nop dir fd here */
UINT64_MAX,
maxsz,
flags,
NULL,
&data, &size);
if (r != -ENOENT)
break;
}
} else if (source)
r = read_full_file_full(
read_dfd, source,
UINT64_MAX,
encrypted ? CREDENTIAL_ENCRYPTED_SIZE_MAX : CREDENTIAL_SIZE_MAX,
flags | (encrypted ? READ_FULL_FILE_UNBASE64 : 0),
maxsz,
flags,
bindname,
&data, &size);
else

View File

@ -406,7 +406,8 @@ struct ExecParameters {
const char *cgroup_path;
char **prefix;
const char *received_credentials;
const char *received_credentials_directory;
const char *received_encrypted_credentials_directory;
const char *confirm_spawn;

View File

@ -777,9 +777,37 @@ static int manager_setup_sigchld_event_source(Manager *m) {
return 0;
}
static int manager_find_credentials_dirs(Manager *m) {
const char *e;
int r;
assert(m);
r = get_credentials_dir(&e);
if (r < 0) {
if (r != -ENXIO)
log_debug_errno(r, "Failed to determine credentials directory, ignoring: %m");
} else {
m->received_credentials_directory = strdup(e);
if (!m->received_credentials_directory)
return -ENOMEM;
}
r = get_encrypted_credentials_dir(&e);
if (r < 0) {
if (r != -ENXIO)
log_debug_errno(r, "Failed to determine encrypted credentials directory, ignoring: %m");
} else {
m->received_encrypted_credentials_directory = strdup(e);
if (!m->received_encrypted_credentials_directory)
return -ENOMEM;
}
return 0;
}
int manager_new(LookupScope scope, ManagerTestRunFlags test_run_flags, Manager **_m) {
_cleanup_(manager_freep) Manager *m = NULL;
const char *e;
int r;
assert(_m);
@ -883,12 +911,9 @@ int manager_new(LookupScope scope, ManagerTestRunFlags test_run_flags, Manager *
if (r < 0)
return r;
r = get_credentials_dir(&e);
if (r >= 0) {
m->received_credentials = strdup(e);
if (!m->received_credentials)
return -ENOMEM;
}
r = manager_find_credentials_dirs(m);
if (r < 0)
return r;
r = sd_event_default(&m->event);
if (r < 0)
@ -1533,7 +1558,8 @@ Manager* manager_free(Manager *m) {
for (ExecDirectoryType dt = 0; dt < _EXEC_DIRECTORY_TYPE_MAX; dt++)
m->prefix[dt] = mfree(m->prefix[dt]);
free(m->received_credentials);
free(m->received_credentials_directory);
free(m->received_encrypted_credentials_directory);
free(m->watchdog_pretimeout_governor);
free(m->watchdog_pretimeout_governor_overridden);

View File

@ -438,7 +438,8 @@ struct Manager {
/* Prefixes of e.g. RuntimeDirectory= */
char *prefix[_EXEC_DIRECTORY_TYPE_MAX];
char *received_credentials;
char *received_credentials_directory;
char *received_encrypted_credentials_directory;
/* Used in the SIGCHLD and sd_notify() message invocation logic to avoid that we dispatch the same event
* multiple times on the same unit. */

View File

@ -5032,7 +5032,8 @@ int unit_set_exec_params(Unit *u, ExecParameters *p) {
p->cgroup_path = u->cgroup_path;
SET_FLAG(p->flags, EXEC_CGROUP_DELEGATE, unit_cgroup_delegate(u));
p->received_credentials = u->manager->received_credentials;
p->received_credentials_directory = u->manager->received_credentials_directory;
p->received_encrypted_credentials_directory = u->manager->received_encrypted_credentials_directory;
return 0;
}