]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
creds-util: check for CAP_DAC_READ_SEARCH
authorAlberto Planas <aplanas@suse.com>
Fri, 13 Jan 2023 14:31:39 +0000 (15:31 +0100)
committerAlberto Planas <aplanas@suse.com>
Mon, 16 Jan 2023 12:31:17 +0000 (13:31 +0100)
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 <aplanas@suse.com>
src/shared/creds-util.c

index a68837b70bdd1f9007cf822f066a2275f7ae0d69..e60dce842566e1da2e1d6f886092da503ebfb348 100644 (file)
@@ -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;