X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fbasic%2Ffs-util.c;h=eefdbb52d84243c9f6c3d4a091d4a88df2e621c2;hp=b97edb552c067c7b10b0c805e3aa7ccd8e2efad1;hb=a485a218fb4fc1baa0b279314b737ea0e36aa397;hpb=7b987da65ad4eacb30034519653a61457b688352 diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c index b97edb552..eefdbb52d 100644 --- a/src/basic/fs-util.c +++ b/src/basic/fs-util.c @@ -17,7 +17,6 @@ along with systemd; If not, see . ***/ -#include #include #include #include @@ -38,6 +37,7 @@ #include "mkdir.h" #include "parse-util.h" #include "path-util.h" +#include "stat-util.h" #include "string-util.h" #include "strv.h" //#include "time-util.h" @@ -236,7 +236,7 @@ int readlink_and_canonicalize(const char *p, const char *root, char **ret) { if (r < 0) return r; - r = chase_symlinks(t, root, &s); + r = chase_symlinks(t, root, 0, &s); if (r < 0) /* If we can't follow up, then let's return the original string, slightly cleaned up. */ *ret = path_kill_slashes(t); @@ -450,6 +450,7 @@ int mkfifo_atomic(const char *path, mode_t mode) { int get_files_in_directory(const char *path, char ***list) { _cleanup_closedir_ DIR *d = NULL; + struct dirent *de; size_t bufsize = 0, n = 0; _cleanup_strv_free_ char **l = NULL; @@ -463,16 +464,7 @@ int get_files_in_directory(const char *path, char ***list) { if (!d) return -errno; - for (;;) { - struct dirent *de; - - errno = 0; - de = readdir(d); - if (!de && errno > 0) - return -errno; - if (!de) - break; - + FOREACH_DIRENT_ALL(de, d, return -errno) { dirent_ensure_type(d, de); if (!dirent_is_file(de)) @@ -500,7 +492,6 @@ int get_files_in_directory(const char *path, char ***list) { return n; } -#if 0 /// UNNEEDED by elogind static int getenv_tmp_dir(const char **ret_path) { const char *n; int r, ret = 0; @@ -571,6 +562,7 @@ static int tmp_dir_internal(const char *def, const char **ret) { return 0; } +#if 0 /// UNNEEDED by elogind int var_tmp_dir(const char **ret) { /* Returns the location for "larger" temporary files, that is backed by physical storage if available, and thus @@ -580,6 +572,7 @@ int var_tmp_dir(const char **ret) { return tmp_dir_internal("/var/tmp", ret); } +#endif // 0 int tmp_dir(const char **ret) { @@ -589,6 +582,7 @@ int tmp_dir(const char **ret) { return tmp_dir_internal("/tmp", ret); } +#if 0 /// UNNEEDED by elogind int inotify_add_watch_fd(int fd, int what, uint32_t mask) { char path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1]; int r; @@ -602,11 +596,13 @@ int inotify_add_watch_fd(int fd, int what, uint32_t mask) { return r; } +#endif // 0 -int chase_symlinks(const char *path, const char *_root, char **ret) { +int chase_symlinks(const char *path, const char *original_root, unsigned flags, char **ret) { _cleanup_free_ char *buffer = NULL, *done = NULL, *root = NULL; _cleanup_close_ int fd = -1; unsigned max_follow = 32; /* how many symlinks to follow before giving up and returning ELOOP */ + bool exists = true; char *todo; int r; @@ -616,8 +612,9 @@ int chase_symlinks(const char *path, const char *_root, char **ret) { * 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 - * shall *not* be prefixed by it. + * 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 @@ -634,16 +631,19 @@ int chase_symlinks(const char *path, const char *_root, char **ret) { * Note: there's also chase_symlinks_prefix() (see below), which as first step prefixes the passed path by the * passed root. */ - r = path_make_absolute_cwd(path, &buffer); - if (r < 0) - return r; - - if (_root) { - r = path_make_absolute_cwd(_root, &root); + if (original_root) { + r = path_make_absolute_cwd(original_root, &root); if (r < 0) return r; + + if (flags & CHASE_PREFIX_ROOT) + path = prefix_roota(root, path); } + r = path_make_absolute_cwd(path, &buffer); + if (r < 0) + return r; + fd = open("/", O_CLOEXEC|O_NOFOLLOW|O_PATH); if (fd < 0) return -errno; @@ -708,13 +708,32 @@ int chase_symlinks(const char *path, const char *_root, char **ret) { /* Otherwise let's see what this is. */ child = openat(fd, first + n, O_CLOEXEC|O_NOFOLLOW|O_PATH); - if (child < 0) + 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 "./" + * or something else weird. */ + + if (!strextend(&done, first, todo, NULL)) + return -ENOMEM; + + exists = false; + break; + } + return -errno; + } if (fstat(child, &st) < 0) return -errno; if (S_ISLNK(st.st_mode)) { + char *joined; + _cleanup_free_ char *destination = NULL; /* This is a symlink, in this case read the destination. But let's make sure we don't follow @@ -738,9 +757,6 @@ int chase_symlinks(const char *path, const char *_root, char **ret) { if (fd < 0) return -errno; - free_and_replace(buffer, destination); - - todo = buffer; free(done); /* Note that we do not revalidate the root, we take it as is. */ @@ -752,19 +768,17 @@ int chase_symlinks(const char *path, const char *_root, char **ret) { return -ENOMEM; } - } else { - char *joined; + } - /* A relative destination. If so, this is what we'll prefix what's left to do with what - * we just read, and start the loop again, but remain in the current directory. */ + /* Prefix what's left to do with what we just read, and start the loop again, + * but remain in the current directory. */ - joined = strjoin("/", destination, todo); - if (!joined) - return -ENOMEM; + joined = strjoin("/", destination, todo); + if (!joined) + return -ENOMEM; - free(buffer); - todo = buffer = joined; - } + free(buffer); + todo = buffer = joined; continue; } @@ -791,19 +805,10 @@ int chase_symlinks(const char *path, const char *_root, char **ret) { return -ENOMEM; } - *ret = done; - done = NULL; - - return 0; -} -#endif // 0 - -int chase_symlinks_prefix(const char *path, const char *root, char **ret) { - const char *t; - - /* Same as chase_symlinks(), but prefixes 'path' by 'root' first. */ - - t = prefix_roota(root, path); + if (ret) { + *ret = done; + done = NULL; + } - return chase_symlinks(t, root, ret); + return exists; }