]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
basic: spit out chase_symlinks() from fs-util.[ch] → chase-symlinks.[ch]
authorLennart Poettering <lennart@poettering.net>
Tue, 5 Oct 2021 13:12:27 +0000 (15:12 +0200)
committerLennart Poettering <lennart@poettering.net>
Tue, 5 Oct 2021 14:14:37 +0000 (16:14 +0200)
48 files changed:
src/basic/chase-symlinks.c [new file with mode: 0644]
src/basic/chase-symlinks.h [new file with mode: 0644]
src/basic/fileio.c
src/basic/fs-util.c
src/basic/fs-util.h
src/basic/meson.build
src/basic/mkdir.c
src/basic/mountpoint-util.c
src/basic/os-util.c
src/basic/path-util.c
src/basic/stat-util.c
src/basic/unit-file.c
src/core/dbus-manager.c
src/core/execute.c
src/core/namespace.c
src/core/service.c
src/core/socket.c
src/core/unit.c
src/delta/delta.c
src/dissect/dissect.c
src/firstboot/firstboot.c
src/fstab-generator/fstab-generator.c
src/journal/journalctl.c
src/libsystemd/sd-device/sd-device.c
src/mount/mount-tool.c
src/nspawn/nspawn-bind-user.c
src/nspawn/nspawn-mount.c
src/nspawn/nspawn.c
src/partition/repart.c
src/portable/portable.c
src/portable/portablectl.c
src/shared/discover-image.c
src/shared/dissect-image.c
src/shared/dropin.c
src/shared/install.c
src/shared/mount-util.c
src/shared/specifier.c
src/shared/switch-root.c
src/shared/user-record.c
src/sysext/sysext.c
src/systemctl/systemctl-util.c
src/test/test-chase-symlinks.c
src/test/test-copy.c
src/test/test-fs-util.c
src/tmpfiles/offline-passwd.c
src/tmpfiles/tmpfiles.c
src/udev/udev-builtin-net_id.c
src/volatile-root/volatile-root.c

diff --git a/src/basic/chase-symlinks.c b/src/basic/chase-symlinks.c
new file mode 100644 (file)
index 0000000..dd3a217
--- /dev/null
@@ -0,0 +1,517 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <linux/magic.h>
+
+#include "alloc-util.h"
+#include "chase-symlinks.h"
+#include "fd-util.h"
+#include "fs-util.h"
+#include "glyph-util.h"
+#include "log.h"
+#include "path-util.h"
+#include "string-util.h"
+#include "user-util.h"
+
+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
+         * privileged files or directories. Why bother? So that unprivileged code can't symlink to privileged files
+         * making us believe we read something safe even though it isn't safe in the specific context we open it in. */
+
+        if (a->st_uid == 0) /* Transitioning from privileged to unprivileged is always fine */
+                return false;
+
+        return a->st_uid != b->st_uid; /* Otherwise we need to stay within the same UID */
+}
+
+static int log_unsafe_transition(int a, int b, const char *path, unsigned flags) {
+        _cleanup_free_ char *n1 = NULL, *n2 = NULL, *user_a = NULL, *user_b = NULL;
+        struct stat st;
+
+        if (!FLAGS_SET(flags, CHASE_WARN))
+                return -ENOLINK;
+
+        (void) fd_get_path(a, &n1);
+        (void) fd_get_path(b, &n2);
+
+        if (fstat(a, &st) == 0)
+                user_a = uid_to_name(st.st_uid);
+        if (fstat(b, &st) == 0)
+                user_b = uid_to_name(st.st_uid);
+
+        return log_warning_errno(SYNTHETIC_ERRNO(ENOLINK),
+                                 "Detected unsafe path transition %s (owned by %s) %s %s (owned by %s) during canonicalization of %s.",
+                                 strna(n1), strna(user_a), special_glyph(SPECIAL_GLYPH_ARROW), strna(n2), strna(user_b), path);
+}
+
+static int log_autofs_mount_point(int fd, const char *path, unsigned flags) {
+        _cleanup_free_ char *n1 = NULL;
+
+        if (!FLAGS_SET(flags, CHASE_WARN))
+                return -EREMOTE;
+
+        (void) fd_get_path(fd, &n1);
+
+        return log_warning_errno(SYNTHETIC_ERRNO(EREMOTE),
+                                 "Detected autofs mount point %s during canonicalization of %s.",
+                                 strna(n1), path);
+}
+
+int chase_symlinks(const char *path, const char *original_root, unsigned flags, char **ret_path, int *ret_fd) {
+        _cleanup_free_ char *buffer = NULL, *done = NULL, *root = NULL;
+        _cleanup_close_ int fd = -1;
+        unsigned max_follow = CHASE_SYMLINKS_MAX; /* how many symlinks to follow before giving up and returning ELOOP */
+        bool exists = true, append_trail_slash = false;
+        struct stat previous_stat;
+        const char *todo;
+        int r;
+
+        assert(path);
+
+        /* Either the file may be missing, or we return an fd to the final object, but both make no sense */
+        if ((flags & CHASE_NONEXISTENT) && ret_fd)
+                return -EINVAL;
+
+        if ((flags & CHASE_STEP) && ret_fd)
+                return -EINVAL;
+
+        if (isempty(path))
+                return -EINVAL;
+
+        /* This is a lot like canonicalize_file_name(), but takes an additional "root" parameter, that allows following
+         * symlinks relative to a root directory, instead of the root of the host.
+         *
+         * Note that "root" primarily matters if we encounter an absolute symlink. It is also used when following
+         * relative symlinks to ensure they cannot be used to "escape" the root directory. The path parameter passed is
+         * assumed to be already prefixed by it, except if the CHASE_PREFIX_ROOT flag is set, in which case it is first
+         * prefixed accordingly.
+         *
+         * Algorithmically this operates on two path buffers: "done" are the components of the path we already
+         * processed and resolved symlinks, "." and ".." of. "todo" are the components of the path we still need to
+         * process. On each iteration, we move one component from "todo" to "done", processing it's special meaning
+         * each time. The "todo" path always starts with at least one slash, the "done" path always ends in no
+         * slash. We always keep an O_PATH fd to the component we are currently processing, thus keeping lookup races
+         * to a minimum.
+         *
+         * Suggested usage: whenever you want to canonicalize a path, use this function. Pass the absolute path you got
+         * as-is: fully qualified and relative to your host's root. Optionally, specify the root parameter to tell this
+         * function what to do when encountering a symlink with an absolute path as directory: prefix it by the
+         * specified path.
+         *
+         * There are five ways to invoke this function:
+         *
+         * 1. Without CHASE_STEP or ret_fd: in this case the path is resolved and the normalized path is
+         *    returned in `ret_path`. The return value is < 0 on error. If CHASE_NONEXISTENT is also set, 0
+         *    is returned if the file doesn't exist, > 0 otherwise. If CHASE_NONEXISTENT is not set, >= 0 is
+         *    returned if the destination was found, -ENOENT if it wasn't.
+         *
+         * 2. With ret_fd: in this case the destination is opened after chasing it as O_PATH and this file
+         *    descriptor is returned as return value. This is useful to open files relative to some root
+         *    directory. Note that the returned O_PATH file descriptors must be converted into a regular one (using
+         *    fd_reopen() or such) before it can be used for reading/writing. ret_fd may not be combined with
+         *    CHASE_NONEXISTENT.
+         *
+         * 3. With CHASE_STEP: in this case only a single step of the normalization is executed, i.e. only the first
+         *    symlink or ".." component of the path is resolved, and the resulting path is returned. This is useful if
+         *    a caller wants to trace the path through the file system verbosely. Returns < 0 on error, > 0 if the
+         *    path is fully normalized, and == 0 for each normalization step. This may be combined with
+         *    CHASE_NONEXISTENT, in which case 1 is returned when a component is not found.
+         *
+         * 4. With CHASE_SAFE: in this case the path must not contain unsafe transitions, i.e. transitions from
+         *    unprivileged to privileged files or directories. In such cases the return value is -ENOLINK. If
+         *    CHASE_WARN is also set, a warning describing the unsafe transition is emitted.
+         *
+         * 5. With CHASE_NO_AUTOFS: in this case if an autofs mount point is encountered, path normalization
+         *    is aborted and -EREMOTE is returned. If CHASE_WARN is also set, a warning showing the path of
+         *    the mount point is emitted.
+         */
+
+        /* A root directory of "/" or "" is identical to none */
+        if (empty_or_root(original_root))
+                original_root = NULL;
+
+        if (!original_root && !ret_path && !(flags & (CHASE_NONEXISTENT|CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_STEP)) && ret_fd) {
+                /* Shortcut the ret_fd case if the caller isn't interested in the actual path and has no root set
+                 * and doesn't care about any of the other special features we provide either. */
+                r = open(path, O_PATH|O_CLOEXEC|((flags & CHASE_NOFOLLOW) ? O_NOFOLLOW : 0));
+                if (r < 0)
+                        return -errno;
+
+                *ret_fd = r;
+                return 0;
+        }
+
+        if (original_root) {
+                r = path_make_absolute_cwd(original_root, &root);
+                if (r < 0)
+                        return r;
+
+                /* Simplify the root directory, so that it has no duplicate slashes and nothing at the
+                 * end. While we won't resolve the root path we still simplify it. Note that dropping the
+                 * trailing slash should not change behaviour, since when opening it we specify O_DIRECTORY
+                 * anyway. Moreover at the end of this function after processing everything we'll always turn
+                 * the empty string back to "/". */
+                delete_trailing_chars(root, "/");
+                path_simplify(root);
+
+                if (flags & CHASE_PREFIX_ROOT) {
+                        /* We don't support relative paths in combination with a root directory */
+                        if (!path_is_absolute(path))
+                                return -EINVAL;
+
+                        path = prefix_roota(root, path);
+                }
+        }
+
+        r = path_make_absolute_cwd(path, &buffer);
+        if (r < 0)
+                return r;
+
+        fd = open(root ?: "/", O_CLOEXEC|O_DIRECTORY|O_PATH);
+        if (fd < 0)
+                return -errno;
+
+        if (flags & CHASE_SAFE)
+                if (fstat(fd, &previous_stat) < 0)
+                        return -errno;
+
+        if (flags & CHASE_TRAIL_SLASH)
+                append_trail_slash = endswith(buffer, "/") || endswith(buffer, "/.");
+
+        if (root) {
+                /* If we are operating on a root directory, let's take the root directory as it is. */
+
+                todo = path_startswith(buffer, root);
+                if (!todo)
+                        return log_full_errno(flags & CHASE_WARN ? LOG_WARNING : LOG_DEBUG,
+                                              SYNTHETIC_ERRNO(ECHRNG),
+                                              "Specified path '%s' is outside of specified root directory '%s', refusing to resolve.",
+                                              path, root);
+
+                done = strdup(root);
+        } else {
+                todo = buffer;
+                done = strdup("/");
+        }
+
+        for (;;) {
+                _cleanup_free_ char *first = NULL;
+                _cleanup_close_ int child = -1;
+                struct stat st;
+                const char *e;
+
+                r = path_find_first_component(&todo, true, &e);
+                if (r < 0)
+                        return r;
+                if (r == 0) { /* We reached the end. */
+                        if (append_trail_slash)
+                                if (!strextend(&done, "/"))
+                                        return -ENOMEM;
+                        break;
+                }
+
+                first = strndup(e, r);
+                if (!first)
+                        return -ENOMEM;
+
+                /* Two dots? Then chop off the last bit of what we already found out. */
+                if (path_equal(first, "..")) {
+                        _cleanup_free_ char *parent = NULL;
+                        _cleanup_close_ int fd_parent = -1;
+
+                        /* If we already are at the top, then going up will not change anything. This is in-line with
+                         * how the kernel handles this. */
+                        if (empty_or_root(done))
+                                continue;
+
+                        parent = dirname_malloc(done);
+                        if (!parent)
+                                return -ENOMEM;
+
+                        /* Don't allow this to leave the root dir.  */
+                        if (root &&
+                            path_startswith(done, root) &&
+                            !path_startswith(parent, root))
+                                continue;
+
+                        free_and_replace(done, parent);
+
+                        if (flags & CHASE_STEP)
+                                goto chased_one;
+
+                        fd_parent = openat(fd, "..", O_CLOEXEC|O_NOFOLLOW|O_PATH);
+                        if (fd_parent < 0)
+                                return -errno;
+
+                        if (flags & CHASE_SAFE) {
+                                if (fstat(fd_parent, &st) < 0)
+                                        return -errno;
+
+                                if (unsafe_transition(&previous_stat, &st))
+                                        return log_unsafe_transition(fd, fd_parent, path, flags);
+
+                                previous_stat = st;
+                        }
+
+                        safe_close(fd);
+                        fd = TAKE_FD(fd_parent);
+
+                        continue;
+                }
+
+                /* Otherwise let's see what this is. */
+                child = openat(fd, first, O_CLOEXEC|O_NOFOLLOW|O_PATH);
+                if (child < 0) {
+                        if (errno == ENOENT &&
+                            (flags & CHASE_NONEXISTENT) &&
+                            (isempty(todo) || path_is_safe(todo))) {
+                                /* If CHASE_NONEXISTENT is set, and the path does not exist, then
+                                 * that's OK, return what we got so far. But don't allow this if the
+                                 * remaining path contains "../" or something else weird. */
+
+                                if (!path_extend(&done, first, todo))
+                                        return -ENOMEM;
+
+                                exists = false;
+                                break;
+                        }
+
+                        return -errno;
+                }
+
+                if (fstat(child, &st) < 0)
+                        return -errno;
+                if ((flags & CHASE_SAFE) &&
+                    unsafe_transition(&previous_stat, &st))
+                        return log_unsafe_transition(fd, child, path, flags);
+
+                previous_stat = st;
+
+                if ((flags & CHASE_NO_AUTOFS) &&
+                    fd_is_fs_type(child, AUTOFS_SUPER_MAGIC) > 0)
+                        return log_autofs_mount_point(child, path, flags);
+
+                if (S_ISLNK(st.st_mode) && !((flags & CHASE_NOFOLLOW) && isempty(todo))) {
+                        _cleanup_free_ char *destination = NULL;
+
+                        /* This is a symlink, in this case read the destination. But let's make sure we
+                         * don't follow symlinks without bounds. */
+                        if (--max_follow <= 0)
+                                return -ELOOP;
+
+                        r = readlinkat_malloc(fd, first, &destination);
+                        if (r < 0)
+                                return r;
+                        if (isempty(destination))
+                                return -EINVAL;
+
+                        if (path_is_absolute(destination)) {
+
+                                /* An absolute destination. Start the loop from the beginning, but use the root
+                                 * directory as base. */
+
+                                safe_close(fd);
+                                fd = open(root ?: "/", O_CLOEXEC|O_DIRECTORY|O_PATH);
+                                if (fd < 0)
+                                        return -errno;
+
+                                if (flags & CHASE_SAFE) {
+                                        if (fstat(fd, &st) < 0)
+                                                return -errno;
+
+                                        if (unsafe_transition(&previous_stat, &st))
+                                                return log_unsafe_transition(child, fd, path, flags);
+
+                                        previous_stat = st;
+                                }
+
+                                /* Note that we do not revalidate the root, we take it as is. */
+                                r = free_and_strdup(&done, empty_to_root(root));
+                                if (r < 0)
+                                        return r;
+                        }
+
+                        /* Prefix what's left to do with what we just read, and start the loop again, but
+                         * remain in the current directory. */
+                        if (!path_extend(&destination, todo))
+                                return -ENOMEM;
+
+                        free_and_replace(buffer, destination);
+                        todo = buffer;
+
+                        if (flags & CHASE_STEP)
+                                goto chased_one;
+
+                        continue;
+                }
+
+                /* If this is not a symlink, then let's just add the name we read to what we already verified. */
+                if (!path_extend(&done, first))
+                        return -ENOMEM;
+
+                /* And iterate again, but go one directory further down. */
+                safe_close(fd);
+                fd = TAKE_FD(child);
+        }
+
+        if (ret_path)
+                *ret_path = TAKE_PTR(done);
+
+        if (ret_fd) {
+                /* Return the O_PATH fd we currently are looking to the caller. It can translate it to a
+                 * proper fd by opening /proc/self/fd/xyz. */
+
+                assert(fd >= 0);
+                *ret_fd = TAKE_FD(fd);
+        }
+
+        if (flags & CHASE_STEP)
+                return 1;
+
+        return exists;
+
+chased_one:
+        if (ret_path) {
+                const char *e;
+
+                /* todo may contain slashes at the beginning. */
+                r = path_find_first_component(&todo, true, &e);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        *ret_path = TAKE_PTR(done);
+                else {
+                        char *c;
+
+                        c = path_join(done, e);
+                        if (!c)
+                                return -ENOMEM;
+
+                        *ret_path = c;
+                }
+        }
+
+        return 0;
+}
+
+int chase_symlinks_and_open(
+                const char *path,
+                const char *root,
+                unsigned chase_flags,
+                int open_flags,
+                char **ret_path) {
+
+        _cleanup_close_ int path_fd = -1;
+        _cleanup_free_ char *p = NULL;
+        int r;
+
+        if (chase_flags & CHASE_NONEXISTENT)
+                return -EINVAL;
+
+        if (empty_or_root(root) && !ret_path && (chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE)) == 0) {
+                /* Shortcut this call if none of the special features of this call are requested */
+                r = open(path, open_flags);
+                if (r < 0)
+                        return -errno;
+
+                return r;
+        }
+
+        r = chase_symlinks(path, root, chase_flags, ret_path ? &p : NULL, &path_fd);
+        if (r < 0)
+                return r;
+        assert(path_fd >= 0);
+
+        r = fd_reopen(path_fd, open_flags);
+        if (r < 0)
+                return r;
+
+        if (ret_path)
+                *ret_path = TAKE_PTR(p);
+
+        return r;
+}
+
+int chase_symlinks_and_opendir(
+                const char *path,
+                const char *root,
+                unsigned chase_flags,
+                char **ret_path,
+                DIR **ret_dir) {
+
+        _cleanup_close_ int path_fd = -1;
+        _cleanup_free_ char *p = NULL;
+        DIR *d;
+        int r;
+
+        if (!ret_dir)
+                return -EINVAL;
+        if (chase_flags & CHASE_NONEXISTENT)
+                return -EINVAL;
+
+        if (empty_or_root(root) && !ret_path && (chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE)) == 0) {
+                /* Shortcut this call if none of the special features of this call are requested */
+                d = opendir(path);
+                if (!d)
+                        return -errno;
+
+                *ret_dir = d;
+                return 0;
+        }
+
+        r = chase_symlinks(path, root, chase_flags, ret_path ? &p : NULL, &path_fd);
+        if (r < 0)
+                return r;
+        assert(path_fd >= 0);
+
+        d = opendir(FORMAT_PROC_FD_PATH(path_fd));
+        if (!d)
+                return -errno;
+
+        if (ret_path)
+                *ret_path = TAKE_PTR(p);
+
+        *ret_dir = d;
+        return 0;
+}
+
+int chase_symlinks_and_stat(
+                const char *path,
+                const char *root,
+                unsigned chase_flags,
+                char **ret_path,
+                struct stat *ret_stat,
+                int *ret_fd) {
+
+        _cleanup_close_ int path_fd = -1;
+        _cleanup_free_ char *p = NULL;
+        int r;
+
+        assert(path);
+        assert(ret_stat);
+
+        if (chase_flags & CHASE_NONEXISTENT)
+                return -EINVAL;
+
+        if (empty_or_root(root) && !ret_path && (chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE)) == 0) {
+                /* Shortcut this call if none of the special features of this call are requested */
+                if (stat(path, ret_stat) < 0)
+                        return -errno;
+
+                return 1;
+        }
+
+        r = chase_symlinks(path, root, chase_flags, ret_path ? &p : NULL, &path_fd);
+        if (r < 0)
+                return r;
+        assert(path_fd >= 0);
+
+        if (fstat(path_fd, ret_stat) < 0)
+                return -errno;
+
+        if (ret_path)
+                *ret_path = TAKE_PTR(p);
+        if (ret_fd)
+                *ret_fd = TAKE_FD(path_fd);
+
+        return 1;
+}
diff --git a/src/basic/chase-symlinks.h b/src/basic/chase-symlinks.h
new file mode 100644 (file)
index 0000000..7191a45
--- /dev/null
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include <dirent.h>
+#include <stdio.h>
+
+#include "stat-util.h"
+
+enum {
+        CHASE_PREFIX_ROOT = 1 << 0, /* The specified path will be prefixed by the specified root before beginning the iteration */
+        CHASE_NONEXISTENT = 1 << 1, /* It's OK if the path doesn't actually exist. */
+        CHASE_NO_AUTOFS   = 1 << 2, /* Return -EREMOTE if autofs mount point found */
+        CHASE_SAFE        = 1 << 3, /* Return -EPERM if we ever traverse from unprivileged to privileged files or directories */
+        CHASE_TRAIL_SLASH = 1 << 4, /* Any trailing slash will be preserved */
+        CHASE_STEP        = 1 << 5, /* Just execute a single step of the normalization */
+        CHASE_NOFOLLOW    = 1 << 6, /* Do not follow the path's right-most component. With ret_fd, when the path's
+                                     * right-most component refers to symlink, return O_PATH fd of the symlink. */
+        CHASE_WARN        = 1 << 7, /* Emit an appropriate warning when an error is encountered */
+};
+
+bool unsafe_transition(const struct stat *a, const struct stat *b);
+
+/* How many iterations to execute before returning -ELOOP */
+#define CHASE_SYMLINKS_MAX 32
+
+int chase_symlinks(const char *path_with_prefix, const char *root, unsigned flags, char **ret_path, int *ret_fd);
+
+int chase_symlinks_and_open(const char *path, const char *root, unsigned chase_flags, int open_flags, char **ret_path);
+int chase_symlinks_and_opendir(const char *path, const char *root, unsigned chase_flags, char **ret_path, DIR **ret_dir);
+int chase_symlinks_and_stat(const char *path, const char *root, unsigned chase_flags, char **ret_path, struct stat *ret_stat, int *ret_fd);
index a268a41addf2764ffa51d6706300b8a24a9a9074..4911ac7c6dc0f3e872e9455c1a4931587d5cd70a 100644 (file)
@@ -13,6 +13,7 @@
 #include <unistd.h>
 
 #include "alloc-util.h"
+#include "chase-symlinks.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "fs-util.h"
index a83f35a4c98d328fc551484364d1ea6ac18ca602..847ebd1841dcced70edab6ee123898374fff0c90 100644 (file)
@@ -12,7 +12,6 @@
 #include "fd-util.h"
 #include "fileio.h"
 #include "fs-util.h"
-#include "glyph-util.h"
 #include "log.h"
 #include "macro.h"
 #include "missing_fcntl.h"
@@ -682,510 +681,6 @@ int unlink_or_warn(const char *filename) {
         return 0;
 }
 
-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
-         * privileged files or directories. Why bother? So that unprivileged code can't symlink to privileged files
-         * making us believe we read something safe even though it isn't safe in the specific context we open it in. */
-
-        if (a->st_uid == 0) /* Transitioning from privileged to unprivileged is always fine */
-                return false;
-
-        return a->st_uid != b->st_uid; /* Otherwise we need to stay within the same UID */
-}
-
-static int log_unsafe_transition(int a, int b, const char *path, unsigned flags) {
-        _cleanup_free_ char *n1 = NULL, *n2 = NULL, *user_a = NULL, *user_b = NULL;
-        struct stat st;
-
-        if (!FLAGS_SET(flags, CHASE_WARN))
-                return -ENOLINK;
-
-        (void) fd_get_path(a, &n1);
-        (void) fd_get_path(b, &n2);
-
-        if (fstat(a, &st) == 0)
-                user_a = uid_to_name(st.st_uid);
-        if (fstat(b, &st) == 0)
-                user_b = uid_to_name(st.st_uid);
-
-        return log_warning_errno(SYNTHETIC_ERRNO(ENOLINK),
-                                 "Detected unsafe path transition %s (owned by %s) %s %s (owned by %s) during canonicalization of %s.",
-                                 strna(n1), strna(user_a), special_glyph(SPECIAL_GLYPH_ARROW), strna(n2), strna(user_b), path);
-}
-
-static int log_autofs_mount_point(int fd, const char *path, unsigned flags) {
-        _cleanup_free_ char *n1 = NULL;
-
-        if (!FLAGS_SET(flags, CHASE_WARN))
-                return -EREMOTE;
-
-        (void) fd_get_path(fd, &n1);
-
-        return log_warning_errno(SYNTHETIC_ERRNO(EREMOTE),
-                                 "Detected autofs mount point %s during canonicalization of %s.",
-                                 strna(n1), path);
-}
-
-int chase_symlinks(const char *path, const char *original_root, unsigned flags, char **ret_path, int *ret_fd) {
-        _cleanup_free_ char *buffer = NULL, *done = NULL, *root = NULL;
-        _cleanup_close_ int fd = -1;
-        unsigned max_follow = CHASE_SYMLINKS_MAX; /* how many symlinks to follow before giving up and returning ELOOP */
-        bool exists = true, append_trail_slash = false;
-        struct stat previous_stat;
-        const char *todo;
-        int r;
-
-        assert(path);
-
-        /* Either the file may be missing, or we return an fd to the final object, but both make no sense */
-        if ((flags & CHASE_NONEXISTENT) && ret_fd)
-                return -EINVAL;
-
-        if ((flags & CHASE_STEP) && ret_fd)
-                return -EINVAL;
-
-        if (isempty(path))
-                return -EINVAL;
-
-        /* This is a lot like canonicalize_file_name(), but takes an additional "root" parameter, that allows following
-         * symlinks relative to a root directory, instead of the root of the host.
-         *
-         * Note that "root" primarily matters if we encounter an absolute symlink. It is also used when following
-         * relative symlinks to ensure they cannot be used to "escape" the root directory. The path parameter passed is
-         * assumed to be already prefixed by it, except if the CHASE_PREFIX_ROOT flag is set, in which case it is first
-         * prefixed accordingly.
-         *
-         * Algorithmically this operates on two path buffers: "done" are the components of the path we already
-         * processed and resolved symlinks, "." and ".." of. "todo" are the components of the path we still need to
-         * process. On each iteration, we move one component from "todo" to "done", processing it's special meaning
-         * each time. The "todo" path always starts with at least one slash, the "done" path always ends in no
-         * slash. We always keep an O_PATH fd to the component we are currently processing, thus keeping lookup races
-         * to a minimum.
-         *
-         * Suggested usage: whenever you want to canonicalize a path, use this function. Pass the absolute path you got
-         * as-is: fully qualified and relative to your host's root. Optionally, specify the root parameter to tell this
-         * function what to do when encountering a symlink with an absolute path as directory: prefix it by the
-         * specified path.
-         *
-         * There are five ways to invoke this function:
-         *
-         * 1. Without CHASE_STEP or ret_fd: in this case the path is resolved and the normalized path is
-         *    returned in `ret_path`. The return value is < 0 on error. If CHASE_NONEXISTENT is also set, 0
-         *    is returned if the file doesn't exist, > 0 otherwise. If CHASE_NONEXISTENT is not set, >= 0 is
-         *    returned if the destination was found, -ENOENT if it wasn't.
-         *
-         * 2. With ret_fd: in this case the destination is opened after chasing it as O_PATH and this file
-         *    descriptor is returned as return value. This is useful to open files relative to some root
-         *    directory. Note that the returned O_PATH file descriptors must be converted into a regular one (using
-         *    fd_reopen() or such) before it can be used for reading/writing. ret_fd may not be combined with
-         *    CHASE_NONEXISTENT.
-         *
-         * 3. With CHASE_STEP: in this case only a single step of the normalization is executed, i.e. only the first
-         *    symlink or ".." component of the path is resolved, and the resulting path is returned. This is useful if
-         *    a caller wants to trace the path through the file system verbosely. Returns < 0 on error, > 0 if the
-         *    path is fully normalized, and == 0 for each normalization step. This may be combined with
-         *    CHASE_NONEXISTENT, in which case 1 is returned when a component is not found.
-         *
-         * 4. With CHASE_SAFE: in this case the path must not contain unsafe transitions, i.e. transitions from
-         *    unprivileged to privileged files or directories. In such cases the return value is -ENOLINK. If
-         *    CHASE_WARN is also set, a warning describing the unsafe transition is emitted.
-         *
-         * 5. With CHASE_NO_AUTOFS: in this case if an autofs mount point is encountered, path normalization
-         *    is aborted and -EREMOTE is returned. If CHASE_WARN is also set, a warning showing the path of
-         *    the mount point is emitted.
-         */
-
-        /* A root directory of "/" or "" is identical to none */
-        if (empty_or_root(original_root))
-                original_root = NULL;
-
-        if (!original_root && !ret_path && !(flags & (CHASE_NONEXISTENT|CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_STEP)) && ret_fd) {
-                /* Shortcut the ret_fd case if the caller isn't interested in the actual path and has no root set
-                 * and doesn't care about any of the other special features we provide either. */
-                r = open(path, O_PATH|O_CLOEXEC|((flags & CHASE_NOFOLLOW) ? O_NOFOLLOW : 0));
-                if (r < 0)
-                        return -errno;
-
-                *ret_fd = r;
-                return 0;
-        }
-
-        if (original_root) {
-                r = path_make_absolute_cwd(original_root, &root);
-                if (r < 0)
-                        return r;
-
-                /* Simplify the root directory, so that it has no duplicate slashes and nothing at the
-                 * end. While we won't resolve the root path we still simplify it. Note that dropping the
-                 * trailing slash should not change behaviour, since when opening it we specify O_DIRECTORY
-                 * anyway. Moreover at the end of this function after processing everything we'll always turn
-                 * the empty string back to "/". */
-                delete_trailing_chars(root, "/");
-                path_simplify(root);
-
-                if (flags & CHASE_PREFIX_ROOT) {
-                        /* We don't support relative paths in combination with a root directory */
-                        if (!path_is_absolute(path))
-                                return -EINVAL;
-
-                        path = prefix_roota(root, path);
-                }
-        }
-
-        r = path_make_absolute_cwd(path, &buffer);
-        if (r < 0)
-                return r;
-
-        fd = open(root ?: "/", O_CLOEXEC|O_DIRECTORY|O_PATH);
-        if (fd < 0)
-                return -errno;
-
-        if (flags & CHASE_SAFE)
-                if (fstat(fd, &previous_stat) < 0)
-                        return -errno;
-
-        if (flags & CHASE_TRAIL_SLASH)
-                append_trail_slash = endswith(buffer, "/") || endswith(buffer, "/.");
-
-        if (root) {
-                /* If we are operating on a root directory, let's take the root directory as it is. */
-
-                todo = path_startswith(buffer, root);
-                if (!todo)
-                        return log_full_errno(flags & CHASE_WARN ? LOG_WARNING : LOG_DEBUG,
-                                              SYNTHETIC_ERRNO(ECHRNG),
-                                              "Specified path '%s' is outside of specified root directory '%s', refusing to resolve.",
-                                              path, root);
-
-                done = strdup(root);
-        } else {
-                todo = buffer;
-                done = strdup("/");
-        }
-
-        for (;;) {
-                _cleanup_free_ char *first = NULL;
-                _cleanup_close_ int child = -1;
-                struct stat st;
-                const char *e;
-
-                r = path_find_first_component(&todo, true, &e);
-                if (r < 0)
-                        return r;
-                if (r == 0) { /* We reached the end. */
-                        if (append_trail_slash)
-                                if (!strextend(&done, "/"))
-                                        return -ENOMEM;
-                        break;
-                }
-
-                first = strndup(e, r);
-                if (!first)
-                        return -ENOMEM;
-
-                /* Two dots? Then chop off the last bit of what we already found out. */
-                if (path_equal(first, "..")) {
-                        _cleanup_free_ char *parent = NULL;
-                        _cleanup_close_ int fd_parent = -1;
-
-                        /* If we already are at the top, then going up will not change anything. This is in-line with
-                         * how the kernel handles this. */
-                        if (empty_or_root(done))
-                                continue;
-
-                        parent = dirname_malloc(done);
-                        if (!parent)
-                                return -ENOMEM;
-
-                        /* Don't allow this to leave the root dir.  */
-                        if (root &&
-                            path_startswith(done, root) &&
-                            !path_startswith(parent, root))
-                                continue;
-
-                        free_and_replace(done, parent);
-
-                        if (flags & CHASE_STEP)
-                                goto chased_one;
-
-                        fd_parent = openat(fd, "..", O_CLOEXEC|O_NOFOLLOW|O_PATH);
-                        if (fd_parent < 0)
-                                return -errno;
-
-                        if (flags & CHASE_SAFE) {
-                                if (fstat(fd_parent, &st) < 0)
-                                        return -errno;
-
-                                if (unsafe_transition(&previous_stat, &st))
-                                        return log_unsafe_transition(fd, fd_parent, path, flags);
-
-                                previous_stat = st;
-                        }
-
-                        safe_close(fd);
-                        fd = TAKE_FD(fd_parent);
-
-                        continue;
-                }
-
-                /* Otherwise let's see what this is. */
-                child = openat(fd, first, O_CLOEXEC|O_NOFOLLOW|O_PATH);
-                if (child < 0) {
-                        if (errno == ENOENT &&
-                            (flags & CHASE_NONEXISTENT) &&
-                            (isempty(todo) || path_is_safe(todo))) {
-                                /* If CHASE_NONEXISTENT is set, and the path does not exist, then
-                                 * that's OK, return what we got so far. But don't allow this if the
-                                 * remaining path contains "../" or something else weird. */
-
-                                if (!path_extend(&done, first, todo))
-                                        return -ENOMEM;
-
-                                exists = false;
-                                break;
-                        }
-
-                        return -errno;
-                }
-
-                if (fstat(child, &st) < 0)
-                        return -errno;
-                if ((flags & CHASE_SAFE) &&
-                    unsafe_transition(&previous_stat, &st))
-                        return log_unsafe_transition(fd, child, path, flags);
-
-                previous_stat = st;
-
-                if ((flags & CHASE_NO_AUTOFS) &&
-                    fd_is_fs_type(child, AUTOFS_SUPER_MAGIC) > 0)
-                        return log_autofs_mount_point(child, path, flags);
-
-                if (S_ISLNK(st.st_mode) && !((flags & CHASE_NOFOLLOW) && isempty(todo))) {
-                        _cleanup_free_ char *destination = NULL;
-
-                        /* This is a symlink, in this case read the destination. But let's make sure we
-                         * don't follow symlinks without bounds. */
-                        if (--max_follow <= 0)
-                                return -ELOOP;
-
-                        r = readlinkat_malloc(fd, first, &destination);
-                        if (r < 0)
-                                return r;
-                        if (isempty(destination))
-                                return -EINVAL;
-
-                        if (path_is_absolute(destination)) {
-
-                                /* An absolute destination. Start the loop from the beginning, but use the root
-                                 * directory as base. */
-
-                                safe_close(fd);
-                                fd = open(root ?: "/", O_CLOEXEC|O_DIRECTORY|O_PATH);
-                                if (fd < 0)
-                                        return -errno;
-
-                                if (flags & CHASE_SAFE) {
-                                        if (fstat(fd, &st) < 0)
-                                                return -errno;
-
-                                        if (unsafe_transition(&previous_stat, &st))
-                                                return log_unsafe_transition(child, fd, path, flags);
-
-                                        previous_stat = st;
-                                }
-
-                                /* Note that we do not revalidate the root, we take it as is. */
-                                r = free_and_strdup(&done, empty_to_root(root));
-                                if (r < 0)
-                                        return r;
-                        }
-
-                        /* Prefix what's left to do with what we just read, and start the loop again, but
-                         * remain in the current directory. */
-                        if (!path_extend(&destination, todo))
-                                return -ENOMEM;
-
-                        free_and_replace(buffer, destination);
-                        todo = buffer;
-
-                        if (flags & CHASE_STEP)
-                                goto chased_one;
-
-                        continue;
-                }
-
-                /* If this is not a symlink, then let's just add the name we read to what we already verified. */
-                if (!path_extend(&done, first))
-                        return -ENOMEM;
-
-                /* And iterate again, but go one directory further down. */
-                safe_close(fd);
-                fd = TAKE_FD(child);
-        }
-
-        if (ret_path)
-                *ret_path = TAKE_PTR(done);
-
-        if (ret_fd) {
-                /* Return the O_PATH fd we currently are looking to the caller. It can translate it to a
-                 * proper fd by opening /proc/self/fd/xyz. */
-
-                assert(fd >= 0);
-                *ret_fd = TAKE_FD(fd);
-        }
-
-        if (flags & CHASE_STEP)
-                return 1;
-
-        return exists;
-
-chased_one:
-        if (ret_path) {
-                const char *e;
-
-                /* todo may contain slashes at the beginning. */
-                r = path_find_first_component(&todo, true, &e);
-                if (r < 0)
-                        return r;
-                if (r == 0)
-                        *ret_path = TAKE_PTR(done);
-                else {
-                        char *c;
-
-                        c = path_join(done, e);
-                        if (!c)
-                                return -ENOMEM;
-
-                        *ret_path = c;
-                }
-        }
-
-        return 0;
-}
-
-int chase_symlinks_and_open(
-                const char *path,
-                const char *root,
-                unsigned chase_flags,
-                int open_flags,
-                char **ret_path) {
-
-        _cleanup_close_ int path_fd = -1;
-        _cleanup_free_ char *p = NULL;
-        int r;
-
-        if (chase_flags & CHASE_NONEXISTENT)
-                return -EINVAL;
-
-        if (empty_or_root(root) && !ret_path && (chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE)) == 0) {
-                /* Shortcut this call if none of the special features of this call are requested */
-                r = open(path, open_flags);
-                if (r < 0)
-                        return -errno;
-
-                return r;
-        }
-
-        r = chase_symlinks(path, root, chase_flags, ret_path ? &p : NULL, &path_fd);
-        if (r < 0)
-                return r;
-        assert(path_fd >= 0);
-
-        r = fd_reopen(path_fd, open_flags);
-        if (r < 0)
-                return r;
-
-        if (ret_path)
-                *ret_path = TAKE_PTR(p);
-
-        return r;
-}
-
-int chase_symlinks_and_opendir(
-                const char *path,
-                const char *root,
-                unsigned chase_flags,
-                char **ret_path,
-                DIR **ret_dir) {
-
-        _cleanup_close_ int path_fd = -1;
-        _cleanup_free_ char *p = NULL;
-        DIR *d;
-        int r;
-
-        if (!ret_dir)
-                return -EINVAL;
-        if (chase_flags & CHASE_NONEXISTENT)
-                return -EINVAL;
-
-        if (empty_or_root(root) && !ret_path && (chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE)) == 0) {
-                /* Shortcut this call if none of the special features of this call are requested */
-                d = opendir(path);
-                if (!d)
-                        return -errno;
-
-                *ret_dir = d;
-                return 0;
-        }
-
-        r = chase_symlinks(path, root, chase_flags, ret_path ? &p : NULL, &path_fd);
-        if (r < 0)
-                return r;
-        assert(path_fd >= 0);
-
-        d = opendir(FORMAT_PROC_FD_PATH(path_fd));
-        if (!d)
-                return -errno;
-
-        if (ret_path)
-                *ret_path = TAKE_PTR(p);
-
-        *ret_dir = d;
-        return 0;
-}
-
-int chase_symlinks_and_stat(
-                const char *path,
-                const char *root,
-                unsigned chase_flags,
-                char **ret_path,
-                struct stat *ret_stat,
-                int *ret_fd) {
-
-        _cleanup_close_ int path_fd = -1;
-        _cleanup_free_ char *p = NULL;
-        int r;
-
-        assert(path);
-        assert(ret_stat);
-
-        if (chase_flags & CHASE_NONEXISTENT)
-                return -EINVAL;
-
-        if (empty_or_root(root) && !ret_path && (chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE)) == 0) {
-                /* Shortcut this call if none of the special features of this call are requested */
-                if (stat(path, ret_stat) < 0)
-                        return -errno;
-
-                return 1;
-        }
-
-        r = chase_symlinks(path, root, chase_flags, ret_path ? &p : NULL, &path_fd);
-        if (r < 0)
-                return r;
-        assert(path_fd >= 0);
-
-        if (fstat(path_fd, ret_stat) < 0)
-                return -errno;
-
-        if (ret_path)
-                *ret_path = TAKE_PTR(p);
-        if (ret_fd)
-                *ret_fd = TAKE_FD(path_fd);
-
-        return 1;
-}
-
 int access_fd(int fd, int mode) {
         /* Like access() but operates on an already open fd */
 
index 61a6a81bf3c0c419de7635ae88c9b6f5366848dc..f8a7657a0748c2daa6dc2d30da49947b50052862 100644 (file)
@@ -66,29 +66,6 @@ int var_tmp_dir(const char **ret);
 
 int unlink_or_warn(const char *filename);
 
-enum {
-        CHASE_PREFIX_ROOT = 1 << 0, /* The specified path will be prefixed by the specified root before beginning the iteration */
-        CHASE_NONEXISTENT = 1 << 1, /* It's OK if the path doesn't actually exist. */
-        CHASE_NO_AUTOFS   = 1 << 2, /* Return -EREMOTE if autofs mount point found */
-        CHASE_SAFE        = 1 << 3, /* Return -EPERM if we ever traverse from unprivileged to privileged files or directories */
-        CHASE_TRAIL_SLASH = 1 << 4, /* Any trailing slash will be preserved */
-        CHASE_STEP        = 1 << 5, /* Just execute a single step of the normalization */
-        CHASE_NOFOLLOW    = 1 << 6, /* Do not follow the path's right-most component. With ret_fd, when the path's
-                                     * right-most component refers to symlink, return O_PATH fd of the symlink. */
-        CHASE_WARN        = 1 << 7, /* Emit an appropriate warning when an error is encountered */
-};
-
-bool unsafe_transition(const struct stat *a, const struct stat *b);
-
-/* How many iterations to execute before returning -ELOOP */
-#define CHASE_SYMLINKS_MAX 32
-
-int chase_symlinks(const char *path_with_prefix, const char *root, unsigned flags, char **ret_path, int *ret_fd);
-
-int chase_symlinks_and_open(const char *path, const char *root, unsigned chase_flags, int open_flags, char **ret_path);
-int chase_symlinks_and_opendir(const char *path, const char *root, unsigned chase_flags, char **ret_path, DIR **ret_dir);
-int chase_symlinks_and_stat(const char *path, const char *root, unsigned chase_flags, char **ret_path, struct stat *ret_stat, int *ret_fd);
-
 /* Useful for usage with _cleanup_(), removes a directory and frees the pointer */
 static inline char *rmdir_and_free(char *p) {
         PROTECT_ERRNO;
index 0d8100a391333b76113f2bb6359176cb285de5c9..ade45bdfc2da1b03477f4a17a074ce32030d9f20 100644 (file)
@@ -25,6 +25,8 @@ basic_sources = files('''
         capability-util.h
         cgroup-util.c
         cgroup-util.h
+        chase-symlinks.c
+        chase-symlinks.h
         chattr-util.c
         chattr-util.h
         conf-files.c
index 78f540809f825a2801d569a1238d1d862e36b6b5..60d08a9493bdfbbc0d6de0fdd48fceb001582e5d 100644 (file)
@@ -5,6 +5,7 @@
 #include <string.h>
 
 #include "alloc-util.h"
+#include "chase-symlinks.h"
 #include "fd-util.h"
 #include "format-util.h"
 #include "fs-util.h"
index e7a5a995514ad4ae505213a87b6e2957e63e5bc6..f07534267fe74aa82c42ffffe2137d2dbe37c853 100644 (file)
@@ -5,6 +5,7 @@
 #include <sys/mount.h>
 
 #include "alloc-util.h"
+#include "chase-symlinks.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "fs-util.h"
index 1d69ecc58622c0616c3dceb083ae3adbce6e3a87..d161f8d33c4b358101a3629a7b9495c42db57628 100644 (file)
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include "alloc-util.h"
+#include "chase-symlinks.h"
 #include "dirent-util.h"
 #include "env-file.h"
 #include "env-util.h"
index eee07b6ea568d77ad0f4e9b570aff94fe0f1f829..4c952d863caca37b8a337077b20270038a16a3f4 100644 (file)
@@ -13,6 +13,7 @@
 #undef basename
 
 #include "alloc-util.h"
+#include "chase-symlinks.h"
 #include "extract-word.h"
 #include "fd-util.h"
 #include "fs-util.h"
index 72a7e4a48bfb9c52cb26d46bf53035b0ec313e73..45864e9e62de8f0e2244de15f9f96b7d09a4af43 100644 (file)
@@ -8,10 +8,11 @@
 #include <unistd.h>
 
 #include "alloc-util.h"
+#include "chase-symlinks.h"
 #include "dirent-util.h"
+#include "errno-util.h"
 #include "fd-util.h"
 #include "fileio.h"
-#include "fs-util.h"
 #include "macro.h"
 #include "missing_fs.h"
 #include "missing_magic.h"
index d1e997ec9f295c052633fc9c300ea6b25e022345..00be0601dc24318b6534cbf90097a0c990f47d70 100644 (file)
@@ -2,6 +2,7 @@
 
 #include "sd-id128.h"
 
+#include "chase-symlinks.h"
 #include "dirent-util.h"
 #include "fd-util.h"
 #include "fs-util.h"
index 99b75598b5ac4e456726df9660be492f6f80ba15..5a294f07b30556ed81a3d0d24195d7688bff7dc9 100644 (file)
@@ -11,6 +11,7 @@
 #include "bus-common-errors.h"
 #include "bus-get-properties.h"
 #include "bus-log-control-api.h"
+#include "chase-symlinks.h"
 #include "data-fd-util.h"
 #include "dbus-cgroup.h"
 #include "dbus-execute.h"
@@ -24,7 +25,6 @@
 #include "fd-util.h"
 #include "fileio.h"
 #include "format-util.h"
-#include "fs-util.h"
 #include "install.h"
 #include "log.h"
 #include "manager-dump.h"
index e7034ce696040a0d252c02a5207ccdcd40421d02..d68e31eb7dd19802316ec11e8a6d7b77b8fe9ea6 100644 (file)
@@ -44,6 +44,7 @@
 #include "cap-list.h"
 #include "capability-util.h"
 #include "cgroup-setup.h"
+#include "chase-symlinks.h"
 #include "chown-recursive.h"
 #include "cpu-set-util.h"
 #include "creds-util.h"
@@ -58,7 +59,6 @@
 #include "fd-util.h"
 #include "fileio.h"
 #include "format-util.h"
-#include "fs-util.h"
 #include "glob-util.h"
 #include "hexdecoct.h"
 #include "io-util.h"
index 038da6c554bb67a7adbad335939028b92521e8ae..48f11f99066fa2996fda9d6d846da1ba720669ee 100644 (file)
 
 #include "alloc-util.h"
 #include "base-filesystem.h"
+#include "chase-symlinks.h"
 #include "dev-setup.h"
 #include "env-util.h"
 #include "escape.h"
 #include "extension-release.h"
 #include "fd-util.h"
 #include "format-util.h"
-#include "fs-util.h"
 #include "label.h"
 #include "list.h"
 #include "loop-util.h"
index 9299813d45eca120ff0bc056d13d8828c982ae85..f331c45de036e34eb54458e9f1a855e878599bf5 100644 (file)
@@ -12,6 +12,7 @@
 #include "bus-error.h"
 #include "bus-kernel.h"
 #include "bus-util.h"
+#include "chase-symlinks.h"
 #include "dbus-service.h"
 #include "dbus-unit.h"
 #include "def.h"
@@ -21,7 +22,6 @@
 #include "fd-util.h"
 #include "fileio.h"
 #include "format-util.h"
-#include "fs-util.h"
 #include "load-dropin.h"
 #include "load-fragment.h"
 #include "log.h"
index 177068eed49f0104de556d4bc29a532382ab19f6..81178e3de267e9d8f608247af89b772a3943ef15 100644 (file)
@@ -14,6 +14,7 @@
 #include "bpf-firewall.h"
 #include "bus-error.h"
 #include "bus-util.h"
+#include "chase-symlinks.h"
 #include "copy.h"
 #include "dbus-socket.h"
 #include "dbus-unit.h"
@@ -22,7 +23,6 @@
 #include "exit-status.h"
 #include "fd-util.h"
 #include "format-util.h"
-#include "fs-util.h"
 #include "in-addr-util.h"
 #include "io-util.h"
 #include "ip-protocol-list.h"
index 304f67dbf111d7eac977265d91c948c69d228f39..05341a64f569636b510f0b2d598cea6c598e2c6f 100644 (file)
@@ -17,6 +17,7 @@
 #include "bus-util.h"
 #include "cgroup-setup.h"
 #include "cgroup-util.h"
+#include "chase-symlinks.h"
 #include "core-varlink.h"
 #include "dbus-unit.h"
 #include "dbus.h"
index 51fe4b4beda5d1b6ee155c15d62423af989a7a7e..ad6b9a195a89849899b7ace395724ec2469564c2 100644 (file)
@@ -6,6 +6,7 @@
 #include <unistd.h>
 
 #include "alloc-util.h"
+#include "chase-symlinks.h"
 #include "dirent-util.h"
 #include "fd-util.h"
 #include "fs-util.h"
index c145c2761145ff8189513b7553ee941db6ca3708..03c1e89cc56bf82995d743d457843acfa85a9e00 100644 (file)
@@ -8,6 +8,7 @@
 #include <sys/mount.h>
 
 #include "architecture.h"
+#include "chase-symlinks.h"
 #include "copy.h"
 #include "dissect-image.h"
 #include "fd-util.h"
index 1727649ae1f164e1c19f9bdd1e5f4298ccedb079..d28a416e5d48ad6d0a9fe594e2779ed09261d12f 100644 (file)
@@ -9,6 +9,7 @@
 
 #include "alloc-util.h"
 #include "ask-password-api.h"
+#include "chase-symlinks.h"
 #include "copy.h"
 #include "creds-util.h"
 #include "dissect-image.h"
index 8a4340c5ba9290d0e5571f34855ee72a77efe3f4..1e6ad432dc2d7935cd914e801beb36cc22fcf678 100644 (file)
@@ -5,9 +5,9 @@
 #include <unistd.h>
 
 #include "alloc-util.h"
+#include "chase-symlinks.h"
 #include "fd-util.h"
 #include "fileio.h"
-#include "fs-util.h"
 #include "fstab-util.h"
 #include "generator.h"
 #include "log.h"
index 73e4fafdffdfcce3cffbe4698bb0160df13b97bd..0eb27b88b295f22cfece988ef51c54527926f7e6 100644 (file)
@@ -27,6 +27,7 @@
 #include "bus-error.h"
 #include "bus-util.h"
 #include "catalog.h"
+#include "chase-symlinks.h"
 #include "chattr-util.h"
 #include "def.h"
 #include "dissect-image.h"
index 7e11ea2d39ea68f0ce82ca1fcb19a4f42b9786d9..1c0dce7b077389ed2abadb48a570938f90e18306 100644 (file)
@@ -8,6 +8,7 @@
 #include "sd-device.h"
 
 #include "alloc-util.h"
+#include "chase-symlinks.h"
 #include "device-internal.h"
 #include "device-private.h"
 #include "device-util.h"
index 8b1cb247e94eab29e436996717692bfc6003bc67..d8034202dc0e0b11b9522e0375168167e0024c0f 100644 (file)
@@ -9,6 +9,7 @@
 #include "bus-locator.h"
 #include "bus-unit-util.h"
 #include "bus-wait-for-jobs.h"
+#include "chase-symlinks.h"
 #include "device-util.h"
 #include "dirent-util.h"
 #include "escape.h"
index 3250cd9768fb698e75cecb2d55ef795067f17deb..0220d71c2b93c69b736f9b242399d007988555db 100644 (file)
@@ -1,9 +1,9 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
+#include "chase-symlinks.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "format-util.h"
-#include "fs-util.h"
 #include "nspawn-bind-user.h"
 #include "nspawn.h"
 #include "path-util.h"
index c59151685c97545ecf3db7bee71f4e677dec5ef0..035fe287eecb16f72511cb55a7a6e7ed16a08bbb 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/magic.h>
 
 #include "alloc-util.h"
+#include "chase-symlinks.h"
 #include "escape.h"
 #include "fd-util.h"
 #include "format-util.h"
index 3694841ba8467fe40a8e2d5f695baf2a95e594fb..7b767fb2963696e02c4fd75f0e592c4e028e9061 100644 (file)
@@ -33,6 +33,7 @@
 #include "cap-list.h"
 #include "capability-util.h"
 #include "cgroup-util.h"
+#include "chase-symlinks.h"
 #include "copy.h"
 #include "cpu-set-util.h"
 #include "creds-util.h"
index 5422d5e1e5260cdd8a09cd6f701e5429be0fef47..e4ea0f04b20778ba88261c55b2bcf97e87f031cd 100644 (file)
@@ -22,6 +22,7 @@
 #include "blkid-util.h"
 #include "blockdev-util.h"
 #include "btrfs-util.h"
+#include "chase-symlinks.h"
 #include "conf-files.h"
 #include "conf-parser.h"
 #include "cryptsetup-util.h"
index 4daafea3d391bd38cd051762a1b53305cd2c2878..48d99c0ca2be0872e2fa3b2ebc45aac906ed4b93 100644 (file)
@@ -4,6 +4,7 @@
 
 #include "bus-common-errors.h"
 #include "bus-error.h"
+#include "chase-symlinks.h"
 #include "conf-files.h"
 #include "copy.h"
 #include "data-fd-util.h"
index c2d79ec3a23d90040060b8ce7368046c69b51cbd..ec625161a4594b750bd80001475aa59c3c640a6a 100644 (file)
@@ -10,6 +10,7 @@
 #include "bus-locator.h"
 #include "bus-unit-util.h"
 #include "bus-wait-for-jobs.h"
+#include "chase-symlinks.h"
 #include "def.h"
 #include "dirent-util.h"
 #include "env-file.h"
@@ -24,8 +25,8 @@
 #include "parse-argument.h"
 #include "parse-util.h"
 #include "path-util.h"
-#include "pretty-print.h"
 #include "portable.h"
+#include "pretty-print.h"
 #include "spawn-polkit-agent.h"
 #include "string-util.h"
 #include "strv.h"
index b96a082aa358ac1f6cb60ba5f7460228917e4d57..129db21eb0e05afc390c409b884c89096c041b5d 100644 (file)
@@ -14,6 +14,7 @@
 
 #include "alloc-util.h"
 #include "btrfs-util.h"
+#include "chase-symlinks.h"
 #include "chattr-util.h"
 #include "copy.h"
 #include "dirent-util.h"
index de75340c9d657bf9d9f5b2a44620b1ade46a58cb..ccbe1aced4141fa29502bc082997e3c908fc8cfe 100644 (file)
@@ -24,6 +24,7 @@
 #include "ask-password-api.h"
 #include "blkid-util.h"
 #include "blockdev-util.h"
+#include "chase-symlinks.h"
 #include "conf-files.h"
 #include "copy.h"
 #include "cryptsetup-util.h"
index 89f4b8ad897dc943a0e8c8f389ec89c2213859fc..eb016eb114604ba8d9190a69d1d1bc9ea3a50421 100644 (file)
@@ -6,13 +6,13 @@
 #include <stdlib.h>
 
 #include "alloc-util.h"
+#include "chase-symlinks.h"
 #include "conf-files.h"
 #include "dirent-util.h"
 #include "dropin.h"
 #include "escape.h"
 #include "fd-util.h"
 #include "fileio-label.h"
-#include "fs-util.h"
 #include "hashmap.h"
 #include "log.h"
 #include "macro.h"
index a348f0c5728c1c4c2a5f7d3a8f363d9919ecc354..268cbd960264c85bba631d76df549b196d9b13c4 100644 (file)
@@ -10,6 +10,7 @@
 #include <unistd.h>
 
 #include "alloc-util.h"
+#include "chase-symlinks.h"
 #include "conf-files.h"
 #include "conf-parser.h"
 #include "def.h"
index 9a3f33915e1c0e8b8a010708740e9242bd359332..e6b6a7e89a1d2e82edf4f9f41af7b537fb80ea0d 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/fs.h>
 
 #include "alloc-util.h"
+#include "chase-symlinks.h"
 #include "dissect-image.h"
 #include "exec-util.h"
 #include "extract-word.h"
index cb4d6daf6a9f9306dbe795e24d3b0a72bcb0e7ea..1fd76b1d15f18295c7b5d1a169ae6dce113d73c5 100644 (file)
@@ -10,6 +10,7 @@
 
 #include "alloc-util.h"
 #include "architecture.h"
+#include "chase-symlinks.h"
 #include "fd-util.h"
 #include "format-util.h"
 #include "fs-util.h"
index e0dd17a2f855dc857dced74312c4003fe67a9498..7edb9d7ff273e32f0b1374206ea34e22b9c0296d 100644 (file)
@@ -9,8 +9,8 @@
 #include <unistd.h>
 
 #include "base-filesystem.h"
+#include "chase-symlinks.h"
 #include "fd-util.h"
-#include "fs-util.h"
 #include "log.h"
 #include "missing_syscall.h"
 #include "mkdir.h"
index 4c54303d131a265c0a49f0f92c592607c6e60e28..f34a48b6567ccb0d14dabcd3c10cf57157fae102 100644 (file)
@@ -3,6 +3,7 @@
 #include <sys/mount.h>
 
 #include "cgroup-util.h"
+#include "chase-symlinks.h"
 #include "dns-domain.h"
 #include "env-util.h"
 #include "fd-util.h"
index 67112c4e14d52c587c05be21f904e42398b03283..509cb9bf319c687e76755c6db1a580e6cc2c5454 100644 (file)
@@ -6,6 +6,7 @@
 #include <unistd.h>
 
 #include "capability-util.h"
+#include "chase-symlinks.h"
 #include "discover-image.h"
 #include "dissect-image.h"
 #include "env-util.h"
index 9f3174d106d21bac0bc67a0d761c24fc6547ec10..d0c514e46763abf74372bbc2406caad9a89287a5 100644 (file)
@@ -10,6 +10,7 @@
 #include "bus-locator.h"
 #include "bus-map-properties.h"
 #include "bus-unit-util.h"
+#include "chase-symlinks.h"
 #include "dropin.h"
 #include "env-util.h"
 #include "exit-status.h"
index 635c44675b2217721e03c490585057c62006f0fb..5f53eba101a15019b1d4cc696ec7a16b8b19d9dd 100644 (file)
@@ -1,8 +1,8 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 #include <getopt.h>
 
+#include "chase-symlinks.h"
 #include "fd-util.h"
-#include "fs-util.h"
 #include "log.h"
 #include "main-func.h"
 
index 7b8f8fa1b2babe4c9817ebcf2deefbe34721d062..362f210e6a65771d5ef8209f97e407cedbbf3034 100644 (file)
@@ -4,6 +4,7 @@
 #include <unistd.h>
 
 #include "alloc-util.h"
+#include "chase-symlinks.h"
 #include "copy.h"
 #include "fd-util.h"
 #include "fileio.h"
index f0cac447c3cfa9eac2499a2af8879e62e930a021..cd024ef7f18a43d678cf0df8425cc52c5dcceea9 100644 (file)
@@ -3,6 +3,7 @@
 #include <unistd.h>
 
 #include "alloc-util.h"
+#include "chase-symlinks.h"
 #include "copy.h"
 #include "fd-util.h"
 #include "fileio.h"
index b607aacf576c71ab186877ea0f6f57ffc0b315cd..8ba3fea9843ba24df0c4aa5f1d33d817f493f35c 100644 (file)
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
+#include "chase-symlinks.h"
 #include "fd-util.h"
-#include "fs-util.h"
 #include "offline-passwd.h"
 #include "path-util.h"
 #include "user-util.h"
index 8a02e6c9dd5d4a37d99299b26ae1f4cd75bb95bd..6b2f75e2486b8dbafba68c6a6e7f3f5903bb7a2f 100644 (file)
@@ -21,6 +21,7 @@
 #include "alloc-util.h"
 #include "btrfs-util.h"
 #include "capability-util.h"
+#include "chase-symlinks.h"
 #include "chattr-util.h"
 #include "conf-files.h"
 #include "copy.h"
index 5a7c94207b66cc4fc76233b8fcbf4df056c53c62..db155421b2c6f33b147dcecd000a4413f6096424 100644 (file)
 #include <linux/pci_regs.h>
 
 #include "alloc-util.h"
+#include "chase-symlinks.h"
 #include "device-util.h"
 #include "dirent-util.h"
 #include "fd-util.h"
 #include "fileio.h"
-#include "fs-util.h"
 #include "netif-naming-scheme.h"
 #include "parse-util.h"
 #include "proc-cmdline.h"
index 1a6593f9c468cad5527fb03b93d496077b5f7b6b..90065b410b075ae403247f7e6aed7a44948eeff9 100644 (file)
@@ -4,8 +4,8 @@
 
 #include "alloc-util.h"
 #include "blockdev-util.h"
+#include "chase-symlinks.h"
 #include "escape.h"
-#include "fs-util.h"
 #include "main-func.h"
 #include "mkdir.h"
 #include "mount-util.h"