]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
chase: introduce flags that verify that chased inode is regular file or dir
authorLennart Poettering <lennart@poettering.net>
Mon, 13 Jan 2025 12:12:23 +0000 (13:12 +0100)
committerLennart Poettering <lennart@poettering.net>
Mon, 20 Jan 2025 10:35:03 +0000 (11:35 +0100)
This also implies the new CHASE_MUST_BE_DIRECTORY flag in case the
specified path ends in a slash. This makes the rules stricter, it means
we'll be closer to how this is handled in kernel: if a path ends in a
slash it can never refer to a non-directory.

src/basic/chase.c
src/basic/chase.h
src/shared/machine-id-setup.c

index a0edb7e11c857f50aee05f631cc1ca0dd2fa1364..2022e7a169c879c62661468f41e8b314abdb0169 100644 (file)
@@ -89,6 +89,7 @@ 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_TRAIL_SLASH|CHASE_EXTRACT_FILENAME));
         assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
@@ -243,8 +244,15 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int
         if (root_fd < 0)
                 return -errno;
 
-        if (FLAGS_SET(flags, CHASE_TRAIL_SLASH))
-                append_trail_slash = ENDSWITH_SET(buffer, "/", "/.");
+        if (ENDSWITH_SET(buffer, "/", "/.")) {
+                flags |= CHASE_MUST_BE_DIRECTORY;
+                if (FLAGS_SET(flags, CHASE_TRAIL_SLASH))
+                        append_trail_slash = true;
+        } else if (dot_or_dot_dot(buffer) || endswith(buffer, "/.."))
+                flags |= CHASE_MUST_BE_DIRECTORY;
+
+        if (FLAGS_SET(flags, CHASE_PARENT))
+                flags |= CHASE_MUST_BE_DIRECTORY;
 
         for (todo = buffer;;) {
                 _cleanup_free_ char *first = NULL;
@@ -476,12 +484,18 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int
                 close_and_replace(fd, child);
         }
 
-        if (FLAGS_SET(flags, CHASE_PARENT)) {
+        if (FLAGS_SET(flags, CHASE_MUST_BE_DIRECTORY)) {
                 r = stat_verify_directory(&st);
                 if (r < 0)
                         return r;
         }
 
+        if (FLAGS_SET(flags, CHASE_MUST_BE_REGULAR)) {
+                r = stat_verify_regular(&st);
+                if (r < 0)
+                        return r;
+        }
+
         if (ret_path) {
                 if (FLAGS_SET(flags, CHASE_EXTRACT_FILENAME) && done) {
                         _cleanup_free_ char *f = NULL;
index cedd7097fb893ae66a7b79502fb2a6bedf6d0e2b..eda7cad0b76d2fd6fb11d94ad2e37744c60c4ba8 100644 (file)
@@ -29,6 +29,8 @@ typedef enum ChaseFlags {
                                              * file points to the last path component does not exist. */
         CHASE_MKDIR_0755         = 1 << 11, /* Create any missing directories in the given path. */
         CHASE_EXTRACT_FILENAME   = 1 << 12, /* Only return the last component of the resolved path */
+        CHASE_MUST_BE_DIRECTORY  = 1 << 13, /* Fail if returned inode fd is not a dir */
+        CHASE_MUST_BE_REGULAR    = 1 << 14, /* Fail if returned inode fd is not a regular file */
 } ChaseFlags;
 
 bool unsafe_transition(const struct stat *a, const struct stat *b);
index ee7e08b086a834588bdb9f29a909f3331c6c3159..bc4d890d354b6f980dd48da646ffc0ae5da0a0e8 100644 (file)
@@ -74,7 +74,7 @@ static int acquire_machine_id(const char *root, bool machine_id_from_firmware, s
         }
 
         /* Then, try reading the D-Bus machine ID, unless it is a symlink */
-        fd = chase_and_open("/var/lib/dbus/machine-id", root, CHASE_PREFIX_ROOT | CHASE_NOFOLLOW, O_RDONLY|O_CLOEXEC|O_NOCTTY, NULL);
+        fd = chase_and_open("/var/lib/dbus/machine-id", root, CHASE_PREFIX_ROOT|CHASE_NOFOLLOW|CHASE_MUST_BE_REGULAR, O_RDONLY|O_CLOEXEC|O_NOCTTY, NULL);
         if (fd >= 0 && id128_read_fd(fd, ID128_FORMAT_PLAIN | ID128_REFUSE_NULL, ret) >= 0) {
                 log_info("Initializing machine ID from D-Bus machine ID.");
                 return 0;
@@ -140,12 +140,12 @@ int machine_id_setup(const char *root, sd_id128_t machine_id, MachineIdSetupFlag
         WITH_UMASK(0000) {
                 _cleanup_close_ int inode_fd = -EBADF;
 
-                r = chase("/etc/machine-id", root, CHASE_PREFIX_ROOT, &etc_machine_id, &inode_fd);
+                r = chase("/etc/machine-id", root, CHASE_PREFIX_ROOT|CHASE_MUST_BE_REGULAR, &etc_machine_id, &inode_fd);
                 if (r == -ENOENT) {
                         _cleanup_close_ int etc_fd = -EBADF;
                         _cleanup_free_ char *etc = NULL;
 
-                        r = chase("/etc/", root, CHASE_PREFIX_ROOT|CHASE_MKDIR_0755, &etc, &etc_fd);
+                        r = chase("/etc/", root, CHASE_PREFIX_ROOT|CHASE_MKDIR_0755|CHASE_MUST_BE_DIRECTORY, &etc, &etc_fd);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to open '/etc/': %m");
 
@@ -250,7 +250,7 @@ int machine_id_setup(const char *root, sd_id128_t machine_id, MachineIdSetupFlag
         if (write_run_machine_id) {
                 _cleanup_free_ char *run = NULL;
 
-                r = chase("/run/", root, CHASE_PREFIX_ROOT|CHASE_MKDIR_0755, &run, &run_fd);
+                r = chase("/run/", root, CHASE_PREFIX_ROOT|CHASE_MKDIR_0755|CHASE_MUST_BE_DIRECTORY, &run, &run_fd);
                 if (r < 0)
                         return log_error_errno(r, "Failed to open '/run/': %m");
 
@@ -266,7 +266,7 @@ int machine_id_setup(const char *root, sd_id128_t machine_id, MachineIdSetupFlag
 
                 unlink_run_machine_id = true;
         } else {
-                r = chase("/run/machine-id", root, CHASE_PREFIX_ROOT, &run_machine_id, /* ret_inode_fd= */ NULL);
+                r = chase("/run/machine-id", root, CHASE_PREFIX_ROOT|CHASE_MUST_BE_REGULAR, &run_machine_id, /* ret_inode_fd= */ NULL);
                 if (r < 0)
                         return log_error_errno(r, "Failed to open '/run/machine-id': %m");
         }
@@ -321,7 +321,7 @@ int machine_id_commit(const char *root) {
 
         _cleanup_close_ int etc_fd = -EBADF;
         _cleanup_free_ char *etc = NULL;
-        r = chase("/etc/", root, CHASE_PREFIX_ROOT, &etc, &etc_fd);
+        r = chase("/etc/", root, CHASE_PREFIX_ROOT|CHASE_MUST_BE_DIRECTORY, &etc, &etc_fd);
         if (r < 0)
                 return log_error_errno(r, "Failed to open /etc/: %m");
 
@@ -369,7 +369,7 @@ int machine_id_commit(const char *root) {
 
         /* Open /etc/ again after we transitioned into our own private mount namespace */
         _cleanup_close_ int etc_fd_again = -EBADF;
-        r = chase("/etc/", root, CHASE_PREFIX_ROOT, /* ret_path= */ NULL, &etc_fd_again);
+        r = chase("/etc/", root, CHASE_PREFIX_ROOT|CHASE_MUST_BE_DIRECTORY, /* ret_path= */ NULL, &etc_fd_again);
         if (r < 0)
                 return log_error_errno(r, "Failed to open /etc/: %m");