Commit 8b399a02 authored by Ramon Nou's avatar Ramon Nou
Browse files

bound internal symlink traversal

parent 6796d246
Loading
Loading
Loading
Loading
+21 −2
Original line number Diff line number Diff line
@@ -202,8 +202,13 @@ test_lock_file(const std::string& path) {
 * @param flags
 * @return 0 on success, -1 on failure
 */
namespace {

constexpr unsigned int max_symlink_depth = 40;

int
gkfs_open(const std::string& path, mode_t mode, int flags) {
gkfs_open_impl(const std::string& path, mode_t mode, int flags,
               unsigned int symlink_depth) {

    LOG(DEBUG, "{}() called with path: \"{}\", mode: {}, flags: {}", __func__,
        path, mode, flags);
@@ -292,7 +297,14 @@ gkfs_open(const std::string& path, mode_t mode, int flags) {
            errno = ELOOP;
            return -1;
        }
        return gkfs_open(md.target_path(), mode, flags);
        if(symlink_depth >= max_symlink_depth) {
            LOG(WARNING,
                "{}() symbolic link traversal exceeded {} links for '{}'",
                __func__, max_symlink_depth, path);
            errno = ELOOP;
            return -1;
        }
        return gkfs_open_impl(md.target_path(), mode, flags, symlink_depth + 1);
    }
    if(gkfs::config::metadata::rename_support) {
        if(md.blocks() == -1) {
@@ -376,6 +388,13 @@ gkfs_open(const std::string& path, mode_t mode, int flags) {
    return fd;
}

} // namespace

int
gkfs_open(const std::string& path, mode_t mode, int flags) {
    return gkfs_open_impl(path, mode, flags, 0);
}

/**
 * Wrapper function for file/directory creation
 * errno may be set
+17 −0
Original line number Diff line number Diff line
import stat
import os
import errno

import pytest

@@ -44,3 +45,19 @@ def test_symlink_type(client_fixture, request, gkfs_daemon):

    assert found_link, "Symlink entry not found in readdir"
    assert found_target, "Target entry not found in readdir"


@pytest.mark.parametrize("client_fixture", ["gkfs_client", "gkfs_clientLibc"])
def test_symlink_cycle_returns_eloop(client_fixture, request, gkfs_daemon):
    """Opening a cyclic symlink must fail with ELOOP, not recurse indefinitely."""
    gkfs_client = request.getfixturevalue(client_fixture)
    mountdir = gkfs_daemon.mountdir
    link_a = mountdir / "cycle_a"
    link_b = mountdir / "cycle_b"

    assert gkfs_client.symlink(str(link_b), str(link_a)).retval == 0
    assert gkfs_client.symlink(str(link_a), str(link_b)).retval == 0

    ret = gkfs_client.open(link_a, os.O_RDONLY)
    assert ret.retval == -1
    assert ret.errno == errno.ELOOP