]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
chase: add new flag CHASE_MUST_BE_SOCKET
authorLennart Poettering <lennart@amutable.com>
Fri, 6 Feb 2026 14:03:23 +0000 (15:03 +0100)
committerLennart Poettering <lennart@amutable.com>
Mon, 9 Feb 2026 09:44:47 +0000 (10:44 +0100)
Just like CHASE_MUST_BE_DIRECTORY and CHASE_MUST_BE_REGULAR, but test if
the inode is a socket.

src/basic/chase.c
src/basic/chase.h

index f360cc26a3c882079ac634c279e0e15d3795266d..abe85a2a0892b1fdd57d748f089f67abb8421b23 100644 (file)
          CHASE_STEP |                                   \
          CHASE_PROHIBIT_SYMLINKS |                      \
          CHASE_PARENT |                                 \
-         CHASE_MKDIR_0755)
+         CHASE_MKDIR_0755 |                             \
+         CHASE_MUST_BE_DIRECTORY |                      \
+         CHASE_MUST_BE_REGULAR |                        \
+         CHASE_MUST_BE_SOCKET)
 
 bool unsafe_transition(const struct stat *a, const struct stat *b) {
         /* Returns true if the transition from a to b is safe, i.e. that we never transition from unprivileged to
@@ -133,7 +136,6 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int
         int r;
 
         assert(!FLAGS_SET(flags, CHASE_PREFIX_ROOT));
-        assert(!FLAGS_SET(flags, CHASE_MUST_BE_DIRECTORY|CHASE_MUST_BE_REGULAR));
         assert(!FLAGS_SET(flags, CHASE_STEP|CHASE_EXTRACT_FILENAME));
         assert(!FLAGS_SET(flags, CHASE_NO_AUTOFS|CHASE_TRIGGER_AUTOFS));
         assert(dir_fd >= 0 || IN_SET(dir_fd, AT_FDCWD, XAT_FDROOT));
@@ -328,6 +330,10 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int
         if (FLAGS_SET(flags, CHASE_PARENT))
                 flags |= CHASE_MUST_BE_DIRECTORY;
 
+        /* If multiple flags are set now, fail immediately */
+        if (FLAGS_SET(flags, CHASE_MUST_BE_DIRECTORY) + FLAGS_SET(flags, CHASE_MUST_BE_REGULAR) + FLAGS_SET(flags, CHASE_MUST_BE_SOCKET) > 1)
+                return -EBADSLT;
+
         for (todo = buffer;;) {
                 _cleanup_free_ char *first = NULL;
                 _cleanup_close_ int child = -EBADF;
@@ -566,6 +572,12 @@ success:
                         if (r < 0)
                                 return r;
                 }
+
+                if (FLAGS_SET(flags, CHASE_MUST_BE_SOCKET)) {
+                        r = stat_verify_socket(&st);
+                        if (r < 0)
+                                return r;
+                }
         }
 
         if (ret_path) {
@@ -872,7 +884,7 @@ int chase_and_opendir(const char *path, const char *root, ChaseFlags chase_flags
         DIR *d;
         int r;
 
-        assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP|CHASE_MUST_BE_REGULAR)));
+        assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP|CHASE_MUST_BE_REGULAR|CHASE_MUST_BE_SOCKET)));
         assert(ret_dir);
 
         if (empty_or_root(root) && !ret_path && (chase_flags & CHASE_NO_SHORTCUT_MASK) == 0) {
@@ -970,7 +982,7 @@ int chase_and_fopen_unlocked(
         int mode_flags, r;
 
         assert(path);
-        assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP|CHASE_PARENT|CHASE_MUST_BE_DIRECTORY)));
+        assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP|CHASE_PARENT|CHASE_MUST_BE_DIRECTORY|CHASE_MUST_BE_SOCKET)));
         assert(open_flags);
         assert(ret_file);
 
@@ -1040,7 +1052,7 @@ int chase_and_openat(
         _cleanup_free_ char *p = NULL, *fname = NULL;
         int r;
 
-        assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP)));
+        assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP|CHASE_MUST_BE_SOCKET)));
 
         XOpenFlags xopen_flags = 0;
         if (FLAGS_SET(chase_flags, CHASE_MUST_BE_DIRECTORY))
@@ -1086,7 +1098,7 @@ int chase_and_opendirat(int dir_fd, const char *path, ChaseFlags chase_flags, ch
         DIR *d;
         int r;
 
-        assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP|CHASE_MUST_BE_REGULAR)));
+        assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP|CHASE_MUST_BE_REGULAR|CHASE_MUST_BE_SOCKET)));
         assert(ret_dir);
 
         if (dir_fd == AT_FDCWD && !ret_path && (chase_flags & CHASE_NO_SHORTCUT_MASK) == 0) {
index 948b83aad0775b7c7a26674343c6ef4609ddb9d3..d0674aae73c990b378c83b7910b7f4f8a8055ce6 100644 (file)
@@ -29,6 +29,7 @@ typedef enum ChaseFlags {
         CHASE_EXTRACT_FILENAME   = 1 << 13, /* Only return the last component of the resolved path */
         CHASE_MUST_BE_DIRECTORY  = 1 << 14, /* Fail if returned inode fd is not a dir */
         CHASE_MUST_BE_REGULAR    = 1 << 15, /* Fail if returned inode fd is not a regular file */
+        CHASE_MUST_BE_SOCKET     = 1 << 16, /* Fail if returned inode fd is not a socket */
 } ChaseFlags;
 
 bool unsafe_transition(const struct stat *a, const struct stat *b);