fs-util: add flags parameter to chase_symlinks()

Let's remove chase_symlinks_prefix() and instead introduce a flags parameter to
chase_symlinks(), with a flag CHASE_PREFIX_ROOT that exposes the behaviour of
chase_symlinks_prefix().
This commit is contained in:
Lennart Poettering 2016-11-29 16:49:30 +01:00
parent a4eaf3cf82
commit c4f4fce79e
11 changed files with 45 additions and 48 deletions

View File

@ -235,7 +235,7 @@ int readlink_and_canonicalize(const char *p, const char *root, char **ret) {
if (r < 0) if (r < 0)
return r; return r;
r = chase_symlinks(t, root, &s); r = chase_symlinks(t, root, 0, &s);
if (r < 0) if (r < 0)
/* If we can't follow up, then let's return the original string, slightly cleaned up. */ /* If we can't follow up, then let's return the original string, slightly cleaned up. */
*ret = path_kill_slashes(t); *ret = path_kill_slashes(t);
@ -598,7 +598,7 @@ int inotify_add_watch_fd(int fd, int what, uint32_t mask) {
return r; return r;
} }
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_free_ char *buffer = NULL, *done = NULL, *root = NULL;
_cleanup_close_ int fd = -1; _cleanup_close_ int fd = -1;
unsigned max_follow = 32; /* how many symlinks to follow before giving up and returning ELOOP */ unsigned max_follow = 32; /* how many symlinks to follow before giving up and returning ELOOP */
@ -611,8 +611,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. * 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 * 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 * relative symlinks to ensure they cannot be used to "escape" the root directory. The path parameter passed is
* shall *not* be prefixed by it. * 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 * 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 * processed and resolved symlinks, "." and ".." of. "todo" are the components of the path we still need to
@ -629,16 +630,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 * Note: there's also chase_symlinks_prefix() (see below), which as first step prefixes the passed path by the
* passed root. */ * passed 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); r = path_make_absolute_cwd(path, &buffer);
if (r < 0) if (r < 0)
return r; return r;
if (_root) {
r = path_make_absolute_cwd(_root, &root);
if (r < 0)
return r;
}
fd = open("/", O_CLOEXEC|O_NOFOLLOW|O_PATH); fd = open("/", O_CLOEXEC|O_NOFOLLOW|O_PATH);
if (fd < 0) if (fd < 0)
return -errno; return -errno;
@ -791,13 +795,3 @@ int chase_symlinks(const char *path, const char *_root, char **ret) {
return 0; return 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);
return chase_symlinks(t, root, ret);
}

View File

@ -78,5 +78,8 @@ union inotify_event_buffer {
int inotify_add_watch_fd(int fd, int what, uint32_t mask); int inotify_add_watch_fd(int fd, int what, uint32_t mask);
int chase_symlinks(const char *path_with_prefix, const char *root, char **ret); enum {
int chase_symlinks_prefix(const char *path_without_prefix, const char *root, char **ret); CHASE_PREFIX_ROOT = 1, /* If set, the specified path will be prefixed by the specified root before beginning the iteration */
};
int chase_symlinks(const char *path_with_prefix, const char *root, unsigned flags, char **ret);

View File

@ -221,7 +221,7 @@ int path_is_mount_point(const char *t, const char *root, int flags) {
* /bin -> /usr/bin/ and /usr is a mount point, then the parent that we * /bin -> /usr/bin/ and /usr is a mount point, then the parent that we
* look at needs to be /usr, not /. */ * look at needs to be /usr, not /. */
if (flags & AT_SYMLINK_FOLLOW) { if (flags & AT_SYMLINK_FOLLOW) {
r = chase_symlinks(t, root, &canonical); r = chase_symlinks(t, root, 0, &canonical);
if (r < 0) if (r < 0)
return r; return r;

View File

@ -252,7 +252,7 @@ char **path_strv_resolve(char **l, const char *root) {
} else } else
t = *s; t = *s;
r = chase_symlinks(t, root, &u); r = chase_symlinks(t, root, 0, &u);
if (r == -ENOENT) { if (r == -ENOENT) {
if (root) { if (root) {
u = orig; u = orig;

View File

@ -665,7 +665,7 @@ static int chase_all_symlinks(const char *root_directory, BindMount *m, unsigned
_cleanup_free_ char *chased = NULL; _cleanup_free_ char *chased = NULL;
int k; int k;
k = chase_symlinks(bind_mount_path(f), root_directory, &chased); k = chase_symlinks(bind_mount_path(f), root_directory, 0, &chased);
if (k < 0) { if (k < 0) {
/* Get only real errors */ /* Get only real errors */
if (r >= 0 && (k != -ENOENT || !f->ignore)) if (r >= 0 && (k != -ENOENT || !f->ignore))

View File

@ -89,11 +89,11 @@ static int equivalent(const char *a, const char *b) {
_cleanup_free_ char *x = NULL, *y = NULL; _cleanup_free_ char *x = NULL, *y = NULL;
int r; int r;
r = chase_symlinks(a, NULL, &x); r = chase_symlinks(a, NULL, 0, &x);
if (r < 0) if (r < 0)
return r; return r;
r = chase_symlinks(b, NULL, &y); r = chase_symlinks(b, NULL, 0, &y);
if (r < 0) if (r < 0)
return r; return r;
@ -361,7 +361,7 @@ static int should_skip_prefix(const char* p) {
int r; int r;
_cleanup_free_ char *target = NULL; _cleanup_free_ char *target = NULL;
r = chase_symlinks(p, NULL, &target); r = chase_symlinks(p, NULL, 0, &target);
if (r < 0) if (r < 0)
return r; return r;

View File

@ -941,7 +941,7 @@ static int add_matches(sd_journal *j, char **args) {
_cleanup_free_ char *p = NULL, *t = NULL, *t2 = NULL, *interpreter = NULL; _cleanup_free_ char *p = NULL, *t = NULL, *t2 = NULL, *interpreter = NULL;
struct stat st; struct stat st;
r = chase_symlinks(*i, NULL, &p); r = chase_symlinks(*i, NULL, 0, &p);
if (r < 0) if (r < 0)
return log_error_errno(r, "Couldn't canonicalize path: %m"); return log_error_errno(r, "Couldn't canonicalize path: %m");

View File

@ -512,7 +512,7 @@ static int mount_bind(const char *dest, CustomMount *m) {
if (stat(m->source, &source_st) < 0) if (stat(m->source, &source_st) < 0)
return log_error_errno(errno, "Failed to stat %s: %m", m->source); return log_error_errno(errno, "Failed to stat %s: %m", m->source);
r = chase_symlinks_prefix(m->destination, dest, &where); r = chase_symlinks(m->destination, dest, CHASE_PREFIX_ROOT, &where);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to resolve %s: %m", m->destination); return log_error_errno(r, "Failed to resolve %s: %m", m->destination);
@ -572,7 +572,7 @@ static int mount_tmpfs(
assert(dest); assert(dest);
assert(m); assert(m);
r = chase_symlinks_prefix(m->destination, dest, &where); r = chase_symlinks(m->destination, dest, CHASE_PREFIX_ROOT, &where);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to resolve %s: %m", m->destination); return log_error_errno(r, "Failed to resolve %s: %m", m->destination);
@ -612,7 +612,7 @@ static int mount_overlay(const char *dest, CustomMount *m) {
assert(dest); assert(dest);
assert(m); assert(m);
r = chase_symlinks_prefix(m->destination, dest, &where); r = chase_symlinks(m->destination, dest, CHASE_PREFIX_ROOT, &where);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to resolve %s: %m", m->destination); return log_error_errno(r, "Failed to resolve %s: %m", m->destination);

View File

@ -2675,7 +2675,7 @@ static int chase_symlinks_and_update(char **p) {
if (!*p) if (!*p)
return 0; return 0;
r = chase_symlinks(*p, NULL, &chased); r = chase_symlinks(*p, NULL, 0, &chased);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to resolve path %s: %m", *p); return log_error_errno(r, "Failed to resolve path %s: %m", *p);

View File

@ -2487,7 +2487,7 @@ static int unit_file_find_path(LookupPaths *lp, const char *unit_name, char **un
if (!path) if (!path)
return log_oom(); return log_oom();
r = chase_symlinks(path, arg_root, &lpath); r = chase_symlinks(path, arg_root, 0, &lpath);
if (r == -ENOENT) if (r == -ENOENT)
continue; continue;
if (r == -ENOMEM) if (r == -ENOMEM)

View File

@ -62,18 +62,18 @@ static void test_chase_symlinks(void) {
/* Paths that use symlinks underneath the "root" */ /* Paths that use symlinks underneath the "root" */
r = chase_symlinks(p, NULL, &result); r = chase_symlinks(p, NULL, 0, &result);
assert_se(r >= 0); assert_se(r >= 0);
assert_se(path_equal(result, "/usr")); assert_se(path_equal(result, "/usr"));
result = mfree(result); result = mfree(result);
r = chase_symlinks(p, temp, &result); r = chase_symlinks(p, temp, 0, &result);
assert_se(r == -ENOENT); assert_se(r == -ENOENT);
q = strjoina(temp, "/usr"); q = strjoina(temp, "/usr");
assert_se(mkdir(q, 0700) >= 0); assert_se(mkdir(q, 0700) >= 0);
r = chase_symlinks(p, temp, &result); r = chase_symlinks(p, temp, 0, &result);
assert_se(r >= 0); assert_se(r >= 0);
assert_se(path_equal(result, q)); assert_se(path_equal(result, q));
@ -81,12 +81,12 @@ static void test_chase_symlinks(void) {
assert_se(symlink("/", p) >= 0); assert_se(symlink("/", p) >= 0);
result = mfree(result); result = mfree(result);
r = chase_symlinks(p, NULL, &result); r = chase_symlinks(p, NULL, 0, &result);
assert_se(r >= 0); assert_se(r >= 0);
assert_se(path_equal(result, "/")); assert_se(path_equal(result, "/"));
result = mfree(result); result = mfree(result);
r = chase_symlinks(p, temp, &result); r = chase_symlinks(p, temp, 0, &result);
assert_se(r >= 0); assert_se(r >= 0);
assert_se(path_equal(result, temp)); assert_se(path_equal(result, temp));
@ -96,21 +96,21 @@ static void test_chase_symlinks(void) {
assert_se(symlink("../../..", p) >= 0); assert_se(symlink("../../..", p) >= 0);
result = mfree(result); result = mfree(result);
r = chase_symlinks(p, temp, &result); r = chase_symlinks(p, temp, 0, &result);
assert_se(r == 0 && path_equal(result, temp)); assert_se(r == 0 && path_equal(result, temp));
p = strjoina(temp, "/6dotsusr"); p = strjoina(temp, "/6dotsusr");
assert_se(symlink("../../../usr", p) >= 0); assert_se(symlink("../../../usr", p) >= 0);
result = mfree(result); result = mfree(result);
r = chase_symlinks(p, temp, &result); r = chase_symlinks(p, temp, 0, &result);
assert_se(r == 0 && path_equal(result, q)); assert_se(r == 0 && path_equal(result, q));
p = strjoina(temp, "/top/8dotsusr"); p = strjoina(temp, "/top/8dotsusr");
assert_se(symlink("../../../../usr", p) >= 0); assert_se(symlink("../../../../usr", p) >= 0);
result = mfree(result); result = mfree(result);
r = chase_symlinks(p, temp, &result); r = chase_symlinks(p, temp, 0, &result);
assert_se(r == 0 && path_equal(result, q)); assert_se(r == 0 && path_equal(result, q));
/* Paths that contain repeated slashes */ /* Paths that contain repeated slashes */
@ -119,28 +119,28 @@ static void test_chase_symlinks(void) {
assert_se(symlink("///usr///", p) >= 0); assert_se(symlink("///usr///", p) >= 0);
result = mfree(result); result = mfree(result);
r = chase_symlinks(p, NULL, &result); r = chase_symlinks(p, NULL, 0, &result);
assert_se(r >= 0); assert_se(r >= 0);
assert_se(path_equal(result, "/usr")); assert_se(path_equal(result, "/usr"));
result = mfree(result); result = mfree(result);
r = chase_symlinks(p, temp, &result); r = chase_symlinks(p, temp, 0, &result);
assert_se(r >= 0); assert_se(r >= 0);
assert_se(path_equal(result, q)); assert_se(path_equal(result, q));
/* Paths using . */ /* Paths using . */
result = mfree(result); result = mfree(result);
r = chase_symlinks("/etc/./.././", NULL, &result); r = chase_symlinks("/etc/./.././", NULL, 0, &result);
assert_se(r >= 0); assert_se(r >= 0);
assert_se(path_equal(result, "/")); assert_se(path_equal(result, "/"));
result = mfree(result); result = mfree(result);
r = chase_symlinks("/etc/./.././", "/etc", &result); r = chase_symlinks("/etc/./.././", "/etc", 0, &result);
assert_se(r == 0 && path_equal(result, "/etc")); assert_se(r == 0 && path_equal(result, "/etc"));
result = mfree(result); result = mfree(result);
r = chase_symlinks("/etc/machine-id/foo", NULL, &result); r = chase_symlinks("/etc/machine-id/foo", NULL, 0, &result);
assert_se(r == -ENOTDIR); assert_se(r == -ENOTDIR);
/* Path that loops back to self */ /* Path that loops back to self */
@ -148,7 +148,7 @@ static void test_chase_symlinks(void) {
result = mfree(result); result = mfree(result);
p = strjoina(temp, "/recursive-symlink"); p = strjoina(temp, "/recursive-symlink");
assert_se(symlink("recursive-symlink", p) >= 0); assert_se(symlink("recursive-symlink", p) >= 0);
r = chase_symlinks(p, NULL, &result); r = chase_symlinks(p, NULL, 0, &result);
assert_se(r == -ELOOP); assert_se(r == -ELOOP);
assert_se(rm_rf(temp, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0); assert_se(rm_rf(temp, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);