Limit number of symlinks that canonical() will resolve

* src/filesystem/ops.cc (canonical): Simplify error handling and
	limit number of symlinks that can be resolved.

From-SVN: r228043
This commit is contained in:
Jonathan Wakely 2015-09-23 12:26:50 +01:00 committed by Jonathan Wakely
parent 429ee11aa3
commit 07dc170b6f
2 changed files with 32 additions and 33 deletions

View File

@ -1,3 +1,8 @@
2015-09-23 Jonathan Wakely <jwakely@redhat.com>
* src/filesystem/ops.cc (canonical): Simplify error handling and
limit number of symlinks that can be resolved.
2015-09-23 Jonathan Wakely <jwakely@redhat.com>
* acinclude.m4 (GLIBCXX_CHECK_FILESYSTEM_DEPS): Remove _GLIBCXX_

View File

@ -116,6 +116,7 @@ fs::canonical(const path& p, const path& base, error_code& ec)
{
const path pa = absolute(p, base);
path result;
#ifdef _GLIBCXX_USE_REALPATH
char_ptr buf{ nullptr };
# if _XOPEN_VERSION < 700
@ -137,18 +138,9 @@ fs::canonical(const path& p, const path& base, error_code& ec)
}
#endif
auto fail = [&ec, &result](int e) mutable {
if (!ec.value())
ec.assign(e, std::generic_category());
result.clear();
};
if (!exists(pa, ec))
{
fail(ENOENT);
return result;
}
// else we can assume no unresolvable symlink loops
return result;
// else: we know there are (currently) no unresolvable symlink loops
result = pa.root_path();
@ -156,20 +148,19 @@ fs::canonical(const path& p, const path& base, error_code& ec)
for (auto& f : pa.relative_path())
cmpts.push_back(f);
while (!cmpts.empty())
int max_allowed_symlinks = 40;
while (!cmpts.empty() && !ec)
{
path f = std::move(cmpts.front());
cmpts.pop_front();
if (f.compare(".") == 0)
if (is_dot(f))
{
if (!is_directory(result, ec))
{
fail(ENOTDIR);
break;
}
if (!is_directory(result, ec) && !ec)
ec.assign(ENOTDIR, std::generic_category());
}
else if (f.compare("..") == 0)
else if (is_dotdot(f))
{
auto parent = result.parent_path();
if (parent.empty())
@ -184,27 +175,30 @@ fs::canonical(const path& p, const path& base, error_code& ec)
if (is_symlink(result, ec))
{
path link = read_symlink(result, ec);
if (!ec.value())
if (!ec)
{
if (link.is_absolute())
{
result = link.root_path();
link = link.relative_path();
}
if (--max_allowed_symlinks == 0)
ec.assign(ELOOP, std::generic_category());
else
result.remove_filename();
{
if (link.is_absolute())
{
result = link.root_path();
link = link.relative_path();
}
else
result.remove_filename();
cmpts.insert(cmpts.begin(), link.begin(), link.end());
cmpts.insert(cmpts.begin(), link.begin(), link.end());
}
}
}
if (ec.value() || !exists(result, ec))
{
fail(ENOENT);
break;
}
}
}
if (ec || !exists(result, ec))
result.clear();
return result;
}