diff options
author | Lennart Poettering <lennart@poettering.net> | 2021-10-05 15:12:27 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2021-10-05 16:14:37 +0200 |
commit | f435195925ccdf96cf8413898f9b9590f8b5f760 (patch) | |
tree | 3f137e5e8630c5830238cfee4637f553b081e668 /src | |
parent | basic: split out inotify-related calls from fs-util.h → inotify-util.h (diff) | |
download | systemd-f435195925ccdf96cf8413898f9b9590f8b5f760.tar.xz systemd-f435195925ccdf96cf8413898f9b9590f8b5f760.zip |
basic: spit out chase_symlinks() from fs-util.[ch] → chase-symlinks.[ch]
Diffstat (limited to 'src')
48 files changed, 594 insertions, 543 deletions
diff --git a/src/basic/chase-symlinks.c b/src/basic/chase-symlinks.c new file mode 100644 index 0000000000..dd3a217203 --- /dev/null +++ b/src/basic/chase-symlinks.c @@ -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 index 0000000000..7191a45768 --- /dev/null +++ b/src/basic/chase-symlinks.h @@ -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); diff --git a/src/basic/fileio.c b/src/basic/fileio.c index a268a41add..4911ac7c6d 100644 --- a/src/basic/fileio.c +++ b/src/basic/fileio.c @@ -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" diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c index a83f35a4c9..847ebd1841 100644 --- a/src/basic/fs-util.c +++ b/src/basic/fs-util.c @@ -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 */ diff --git a/src/basic/fs-util.h b/src/basic/fs-util.h index 61a6a81bf3..f8a7657a07 100644 --- a/src/basic/fs-util.h +++ b/src/basic/fs-util.h @@ -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; diff --git a/src/basic/meson.build b/src/basic/meson.build index 0d8100a391..ade45bdfc2 100644 --- a/src/basic/meson.build +++ b/src/basic/meson.build @@ -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 diff --git a/src/basic/mkdir.c b/src/basic/mkdir.c index 78f540809f..60d08a9493 100644 --- a/src/basic/mkdir.c +++ b/src/basic/mkdir.c @@ -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" diff --git a/src/basic/mountpoint-util.c b/src/basic/mountpoint-util.c index e7a5a99551..f07534267f 100644 --- a/src/basic/mountpoint-util.c +++ b/src/basic/mountpoint-util.c @@ -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" diff --git a/src/basic/os-util.c b/src/basic/os-util.c index 1d69ecc586..d161f8d33c 100644 --- a/src/basic/os-util.c +++ b/src/basic/os-util.c @@ -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" diff --git a/src/basic/path-util.c b/src/basic/path-util.c index eee07b6ea5..4c952d863c 100644 --- a/src/basic/path-util.c +++ b/src/basic/path-util.c @@ -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" diff --git a/src/basic/stat-util.c b/src/basic/stat-util.c index 72a7e4a48b..45864e9e62 100644 --- a/src/basic/stat-util.c +++ b/src/basic/stat-util.c @@ -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" diff --git a/src/basic/unit-file.c b/src/basic/unit-file.c index d1e997ec9f..00be0601dc 100644 --- a/src/basic/unit-file.c +++ b/src/basic/unit-file.c @@ -2,6 +2,7 @@ #include "sd-id128.h" +#include "chase-symlinks.h" #include "dirent-util.h" #include "fd-util.h" #include "fs-util.h" diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index 99b75598b5..5a294f07b3 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -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" diff --git a/src/core/execute.c b/src/core/execute.c index e7034ce696..d68e31eb7d 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -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" diff --git a/src/core/namespace.c b/src/core/namespace.c index 038da6c554..48f11f9906 100644 --- a/src/core/namespace.c +++ b/src/core/namespace.c @@ -10,13 +10,13 @@ #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" diff --git a/src/core/service.c b/src/core/service.c index 9299813d45..f331c45de0 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -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" diff --git a/src/core/socket.c b/src/core/socket.c index 177068eed4..81178e3de2 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -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" diff --git a/src/core/unit.c b/src/core/unit.c index 304f67dbf1..05341a64f5 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -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" diff --git a/src/delta/delta.c b/src/delta/delta.c index 51fe4b4bed..ad6b9a195a 100644 --- a/src/delta/delta.c +++ b/src/delta/delta.c @@ -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" diff --git a/src/dissect/dissect.c b/src/dissect/dissect.c index c145c27611..03c1e89cc5 100644 --- a/src/dissect/dissect.c +++ b/src/dissect/dissect.c @@ -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" diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c index 1727649ae1..d28a416e5d 100644 --- a/src/firstboot/firstboot.c +++ b/src/firstboot/firstboot.c @@ -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" diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c index 8a4340c5ba..1e6ad432dc 100644 --- a/src/fstab-generator/fstab-generator.c +++ b/src/fstab-generator/fstab-generator.c @@ -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" diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index 73e4fafdff..0eb27b88b2 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -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" diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c index 7e11ea2d39..1c0dce7b07 100644 --- a/src/libsystemd/sd-device/sd-device.c +++ b/src/libsystemd/sd-device/sd-device.c @@ -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" diff --git a/src/mount/mount-tool.c b/src/mount/mount-tool.c index 8b1cb247e9..d8034202dc 100644 --- a/src/mount/mount-tool.c +++ b/src/mount/mount-tool.c @@ -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" diff --git a/src/nspawn/nspawn-bind-user.c b/src/nspawn/nspawn-bind-user.c index 3250cd9768..0220d71c2b 100644 --- a/src/nspawn/nspawn-bind-user.c +++ b/src/nspawn/nspawn-bind-user.c @@ -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" diff --git a/src/nspawn/nspawn-mount.c b/src/nspawn/nspawn-mount.c index c59151685c..035fe287ee 100644 --- a/src/nspawn/nspawn-mount.c +++ b/src/nspawn/nspawn-mount.c @@ -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" diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 3694841ba8..7b767fb296 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -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" diff --git a/src/partition/repart.c b/src/partition/repart.c index 5422d5e1e5..e4ea0f04b2 100644 --- a/src/partition/repart.c +++ b/src/partition/repart.c @@ -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" diff --git a/src/portable/portable.c b/src/portable/portable.c index 4daafea3d3..48d99c0ca2 100644 --- a/src/portable/portable.c +++ b/src/portable/portable.c @@ -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" diff --git a/src/portable/portablectl.c b/src/portable/portablectl.c index c2d79ec3a2..ec625161a4 100644 --- a/src/portable/portablectl.c +++ b/src/portable/portablectl.c @@ -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" diff --git a/src/shared/discover-image.c b/src/shared/discover-image.c index b96a082aa3..129db21eb0 100644 --- a/src/shared/discover-image.c +++ b/src/shared/discover-image.c @@ -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" diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c index de75340c9d..ccbe1aced4 100644 --- a/src/shared/dissect-image.c +++ b/src/shared/dissect-image.c @@ -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" diff --git a/src/shared/dropin.c b/src/shared/dropin.c index 89f4b8ad89..eb016eb114 100644 --- a/src/shared/dropin.c +++ b/src/shared/dropin.c @@ -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" diff --git a/src/shared/install.c b/src/shared/install.c index a348f0c572..268cbd9602 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -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" diff --git a/src/shared/mount-util.c b/src/shared/mount-util.c index 9a3f33915e..e6b6a7e89a 100644 --- a/src/shared/mount-util.c +++ b/src/shared/mount-util.c @@ -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" diff --git a/src/shared/specifier.c b/src/shared/specifier.c index cb4d6daf6a..1fd76b1d15 100644 --- a/src/shared/specifier.c +++ b/src/shared/specifier.c @@ -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" diff --git a/src/shared/switch-root.c b/src/shared/switch-root.c index e0dd17a2f8..7edb9d7ff2 100644 --- a/src/shared/switch-root.c +++ b/src/shared/switch-root.c @@ -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" diff --git a/src/shared/user-record.c b/src/shared/user-record.c index 4c54303d13..f34a48b656 100644 --- a/src/shared/user-record.c +++ b/src/shared/user-record.c @@ -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" diff --git a/src/sysext/sysext.c b/src/sysext/sysext.c index 67112c4e14..509cb9bf31 100644 --- a/src/sysext/sysext.c +++ b/src/sysext/sysext.c @@ -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" diff --git a/src/systemctl/systemctl-util.c b/src/systemctl/systemctl-util.c index 9f3174d106..d0c514e467 100644 --- a/src/systemctl/systemctl-util.c +++ b/src/systemctl/systemctl-util.c @@ -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" diff --git a/src/test/test-chase-symlinks.c b/src/test/test-chase-symlinks.c index 635c44675b..5f53eba101 100644 --- a/src/test/test-chase-symlinks.c +++ b/src/test/test-chase-symlinks.c @@ -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" diff --git a/src/test/test-copy.c b/src/test/test-copy.c index 7b8f8fa1b2..362f210e6a 100644 --- a/src/test/test-copy.c +++ b/src/test/test-copy.c @@ -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" diff --git a/src/test/test-fs-util.c b/src/test/test-fs-util.c index f0cac447c3..cd024ef7f1 100644 --- a/src/test/test-fs-util.c +++ b/src/test/test-fs-util.c @@ -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" diff --git a/src/tmpfiles/offline-passwd.c b/src/tmpfiles/offline-passwd.c index b607aacf57..8ba3fea984 100644 --- a/src/tmpfiles/offline-passwd.c +++ b/src/tmpfiles/offline-passwd.c @@ -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" diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index 8a02e6c9dd..6b2f75e248 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -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" diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c index 5a7c94207b..db155421b2 100644 --- a/src/udev/udev-builtin-net_id.c +++ b/src/udev/udev-builtin-net_id.c @@ -23,11 +23,11 @@ #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" diff --git a/src/volatile-root/volatile-root.c b/src/volatile-root/volatile-root.c index 1a6593f9c4..90065b410b 100644 --- a/src/volatile-root/volatile-root.c +++ b/src/volatile-root/volatile-root.c @@ -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" |