From 1615578f2792fdeecaf65606861bd3db9eb949c3 Mon Sep 17 00:00:00 2001 From: Alberto Planas Date: Fri, 13 Jan 2023 15:31:39 +0100 Subject: [PATCH 1/3] creds-util: check for CAP_DAC_READ_SEARCH In make_credential_host_secret, the credential.secret file is generated first as a temporary anonymous file that is later instantiated with linkat(2). This system call requires CAP_DAC_READ_SEARCH capability when the flag AT_EMPTY_PATH is used. This patch check if the capability is effective, and if not uses the alternative codepath for creating named temporary files. Non-root users can now create per-user credentials with: export SYSTEMD_CREDENTIAL_SECRET=$HOME/.config/systemd/credential.secret systemd-creds setup Signed-off-by: Alberto Planas --- src/shared/creds-util.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/shared/creds-util.c b/src/shared/creds-util.c index a68837b70b..e60dce8425 100644 --- a/src/shared/creds-util.c +++ b/src/shared/creds-util.c @@ -9,6 +9,7 @@ #include "sd-id128.h" #include "blockdev-util.h" +#include "capability-util.h" #include "chattr-util.h" #include "constants.h" #include "creds-util.h" @@ -223,10 +224,15 @@ static int make_credential_host_secret( assert(dfd >= 0); assert(fn); - fd = openat(dfd, ".", O_CLOEXEC|O_WRONLY|O_TMPFILE, 0400); + /* For non-root users creating a temporary file using the openat(2) over "." will fail later, in the + * linkat(2) step at the end. The reason is that linkat(2) requires the CAP_DAC_READ_SEARCH + * capability when it uses the AT_EMPTY_PATH flag. */ + if (have_effective_cap(CAP_DAC_READ_SEARCH) > 0) { + fd = openat(dfd, ".", O_CLOEXEC|O_WRONLY|O_TMPFILE, 0400); + if (fd < 0) + log_debug_errno(errno, "Failed to create temporary credential file with O_TMPFILE, proceeding without: %m"); + } if (fd < 0) { - log_debug_errno(errno, "Failed to create temporary credential file with O_TMPFILE, proceeding without: %m"); - if (asprintf(&t, "credential.secret.%016" PRIx64, random_u64()) < 0) return -ENOMEM; From e653a194e490fae7d166f40762c334006d592051 Mon Sep 17 00:00:00 2001 From: Alberto Planas Date: Mon, 16 Jan 2023 11:16:53 +0100 Subject: [PATCH 2/3] creds-util: do not try TPM2 if there is not support During the credentials encryption, if systemd it is compiled with TPM2 support, it will try to use it depending on the key flags passed. The current code only checks if the system has a functional TPM2 if the case of the INITRD flag. This patch do a similar check in the case that it is outside initrd (but still automatic). Signed-off-by: Alberto Planas --- src/shared/creds-util.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/shared/creds-util.c b/src/shared/creds-util.c index e60dce8425..ed40b6c19a 100644 --- a/src/shared/creds-util.c +++ b/src/shared/creds-util.c @@ -659,16 +659,13 @@ int encrypt_credential_and_warn( #if HAVE_TPM2 bool try_tpm2; if (sd_id128_equal(with_key, _CRED_AUTO)) { - /* If automatic mode is selected and we are running in a container, let's not try TPM2. OTOH - * if user picks TPM2 explicitly, let's always honour the request and try. */ + /* If automatic mode is selected lets see if a TPM2 it is present. If we are running in a + * container tpm2_support will detect this, and will return a different flag combination of + * TPM2_SUPPORT_FULL, effectively skipping the use of TPM2 when inside one. */ - r = detect_container(); - if (r < 0) - log_debug_errno(r, "Failed to determine whether we are running in a container, ignoring: %m"); - else if (r > 0) - log_debug("Running in container, not attempting to use TPM2."); - - try_tpm2 = r <= 0; + try_tpm2 = tpm2_support() == TPM2_SUPPORT_FULL; + if (!try_tpm2) + log_debug("System lacks TPM2 support or running in a container, not attempting to use TPM2."); } else if (sd_id128_equal(with_key, _CRED_AUTO_INITRD)) { /* If automatic mode for initrds is selected, we'll use the TPM2 key if the firmware does it, * otherwise we'll use a fixed key */ From e37dfcec528b43e203d198f978f9eaa87787c762 Mon Sep 17 00:00:00 2001 From: Alberto Planas Date: Mon, 16 Jan 2023 13:35:49 +0100 Subject: [PATCH 3/3] creds-util: merge the TPM2 detection for initrd This patch merge the TPM2 detection paths when we are inside and outside an initrd. Signed-off-by: Alberto Planas --- src/shared/creds-util.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/shared/creds-util.c b/src/shared/creds-util.c index ed40b6c19a..5d04692a5c 100644 --- a/src/shared/creds-util.c +++ b/src/shared/creds-util.c @@ -658,7 +658,7 @@ int encrypt_credential_and_warn( #if HAVE_TPM2 bool try_tpm2; - if (sd_id128_equal(with_key, _CRED_AUTO)) { + if (sd_id128_in_set(with_key, _CRED_AUTO, _CRED_AUTO_INITRD)) { /* If automatic mode is selected lets see if a TPM2 it is present. If we are running in a * container tpm2_support will detect this, and will return a different flag combination of * TPM2_SUPPORT_FULL, effectively skipping the use of TPM2 when inside one. */ @@ -666,13 +666,6 @@ int encrypt_credential_and_warn( try_tpm2 = tpm2_support() == TPM2_SUPPORT_FULL; if (!try_tpm2) log_debug("System lacks TPM2 support or running in a container, not attempting to use TPM2."); - } else if (sd_id128_equal(with_key, _CRED_AUTO_INITRD)) { - /* If automatic mode for initrds is selected, we'll use the TPM2 key if the firmware does it, - * otherwise we'll use a fixed key */ - - try_tpm2 = efi_has_tpm2(); - if (!try_tpm2) - log_debug("Firmware lacks TPM2 support, not attempting to use TPM2."); } else try_tpm2 = sd_id128_in_set(with_key, CRED_AES256_GCM_BY_TPM2_HMAC, @@ -713,7 +706,7 @@ int encrypt_credential_and_warn( &tpm2_primary_alg); if (r < 0) { if (sd_id128_equal(with_key, _CRED_AUTO_INITRD)) - log_warning("Firmware reported a TPM2 being present and used, but we didn't manage to talk to it. Credential will be refused if SecureBoot is enabled."); + log_warning("TPM2 present and used, but we didn't manage to talk to it. Credential will be refused if SecureBoot is enabled."); else if (!sd_id128_equal(with_key, _CRED_AUTO)) return r;