summaryrefslogtreecommitdiff
path: root/src/basic
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2016-11-29 15:54:42 +0100
committerSven Eden <yamakuzure@gmx.net>2017-07-17 17:58:35 +0200
commit7b987da65ad4eacb30034519653a61457b688352 (patch)
treef7479cac5978a07354bb971607c335f05d6f58d5 /src/basic
parent5de3db0016e2a97b779abe27be5e7326ec1b78aa (diff)
fs-util: change chase_symlinks() behaviour in regards to escaping the root dir
Previously, we'd generate an EINVAL error if it is attempted to escape a root directory with relative ".." symlinks. With this commit this is changed so that ".." from the root directory is a NOP, following the kernel's own behaviour where /.. is equivalent to /. As suggested by @keszybz.
Diffstat (limited to 'src/basic')
-rw-r--r--src/basic/fs-util.c12
1 files changed, 7 insertions, 5 deletions
diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c
index 39f840581..b97edb552 100644
--- a/src/basic/fs-util.c
+++ b/src/basic/fs-util.c
@@ -616,8 +616,8 @@ 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. (For cases where this is
- * attempted -EINVAL is returned.). 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
+ * shall *not* be prefixed by it.
*
* 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
@@ -679,18 +679,20 @@ int chase_symlinks(const char *path, const char *_root, char **ret) {
_cleanup_free_ char *parent = NULL;
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 (isempty(done) || path_equal(done, "/"))
- return -EINVAL;
+ continue;
parent = dirname_malloc(done);
if (!parent)
return -ENOMEM;
- /* Don't allow this to leave the root dir */
+ /* Don't allow this to leave the root dir. */
if (root &&
path_startswith(done, root) &&
!path_startswith(parent, root))
- return -EINVAL;
+ continue;
free_and_replace(done, parent);