From: Lennart Poettering Date: Thu, 21 Apr 2022 13:32:21 +0000 (+0200) Subject: pid1: search for creds in LoadCredential=/LoadCredentialEncrypted= X-Git-Tag: v251-rc2~38^2~5 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2ad591a3a3d0e0da43c0e3252cc15bd00af9bfb7;p=thirdparty%2Fsystemd.git 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. --- diff --git a/src/core/execute.c b/src/core/execute.c index b3e64ade1bd..2762b102879 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -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 (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. */ - } 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) + 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 diff --git a/src/core/execute.h b/src/core/execute.h index 43070ce1117..904e7943f32 100644 --- a/src/core/execute.h +++ b/src/core/execute.h @@ -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; diff --git a/src/core/manager.c b/src/core/manager.c index a68324affc5..18daff66c78 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -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); diff --git a/src/core/manager.h b/src/core/manager.h index 6f4bbb36ab1..fd5da52b7f9 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -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. */ diff --git a/src/core/unit.c b/src/core/unit.c index 5ab7601ed86..ff1288dcac0 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -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; }