summaryrefslogtreecommitdiff
path: root/src/basic
diff options
context:
space:
mode:
Diffstat (limited to 'src/basic')
-rw-r--r--src/basic/fs-util.c22
-rw-r--r--src/basic/fs-util.h1
2 files changed, 21 insertions, 2 deletions
diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c
index 0a3e983631..0ca4656fdd 100644
--- a/src/basic/fs-util.c
+++ b/src/basic/fs-util.c
@@ -602,6 +602,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
_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;
@@ -707,8 +708,25 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
/* 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_NON_EXISTING) &&
+ (isempty(todo) || path_is_safe(todo))) {
+
+ /* If CHASE_NON_EXISTING 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;
@@ -793,5 +811,5 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
*ret = done;
done = NULL;
- return 0;
+ return exists;
}
diff --git a/src/basic/fs-util.h b/src/basic/fs-util.h
index ee3d6bf7af..3931534a42 100644
--- a/src/basic/fs-util.h
+++ b/src/basic/fs-util.h
@@ -80,6 +80,7 @@ int inotify_add_watch_fd(int fd, int what, uint32_t mask);
enum {
CHASE_PREFIX_ROOT = 1, /* If set, the specified path will be prefixed by the specified root before beginning the iteration */
+ CHASE_NON_EXISTING = 2, /* If set, it's OK if the path doesn't actually exist. */
};
int chase_symlinks(const char *path_with_prefix, const char *root, unsigned flags, char **ret);