Commit 07dc170b by Jonathan Wakely Committed by Jonathan Wakely

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
parent 429ee11a
2015-09-23 Jonathan Wakely <jwakely@redhat.com> 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_ * acinclude.m4 (GLIBCXX_CHECK_FILESYSTEM_DEPS): Remove _GLIBCXX_
prefix from HAVE_STRUCT_DIRENT_D_TYPE. prefix from HAVE_STRUCT_DIRENT_D_TYPE.
* config.h.in: Regenerate. * config.h.in: Regenerate.
......
...@@ -116,6 +116,7 @@ fs::canonical(const path& p, const path& base, error_code& ec) ...@@ -116,6 +116,7 @@ fs::canonical(const path& p, const path& base, error_code& ec)
{ {
const path pa = absolute(p, base); const path pa = absolute(p, base);
path result; path result;
#ifdef _GLIBCXX_USE_REALPATH #ifdef _GLIBCXX_USE_REALPATH
char_ptr buf{ nullptr }; char_ptr buf{ nullptr };
# if _XOPEN_VERSION < 700 # if _XOPEN_VERSION < 700
...@@ -137,18 +138,9 @@ fs::canonical(const path& p, const path& base, error_code& ec) ...@@ -137,18 +138,9 @@ fs::canonical(const path& p, const path& base, error_code& ec)
} }
#endif #endif
auto fail = [&ec, &result](int e) mutable {
if (!ec.value())
ec.assign(e, std::generic_category());
result.clear();
};
if (!exists(pa, ec)) if (!exists(pa, ec))
{ return result;
fail(ENOENT); // else: we know there are (currently) no unresolvable symlink loops
return result;
}
// else we can assume no unresolvable symlink loops
result = pa.root_path(); result = pa.root_path();
...@@ -156,20 +148,19 @@ fs::canonical(const path& p, const path& base, error_code& ec) ...@@ -156,20 +148,19 @@ fs::canonical(const path& p, const path& base, error_code& ec)
for (auto& f : pa.relative_path()) for (auto& f : pa.relative_path())
cmpts.push_back(f); cmpts.push_back(f);
while (!cmpts.empty()) int max_allowed_symlinks = 40;
while (!cmpts.empty() && !ec)
{ {
path f = std::move(cmpts.front()); path f = std::move(cmpts.front());
cmpts.pop_front(); cmpts.pop_front();
if (f.compare(".") == 0) if (is_dot(f))
{ {
if (!is_directory(result, ec)) if (!is_directory(result, ec) && !ec)
{ ec.assign(ENOTDIR, std::generic_category());
fail(ENOTDIR);
break;
}
} }
else if (f.compare("..") == 0) else if (is_dotdot(f))
{ {
auto parent = result.parent_path(); auto parent = result.parent_path();
if (parent.empty()) if (parent.empty())
...@@ -184,27 +175,30 @@ fs::canonical(const path& p, const path& base, error_code& ec) ...@@ -184,27 +175,30 @@ fs::canonical(const path& p, const path& base, error_code& ec)
if (is_symlink(result, ec)) if (is_symlink(result, ec))
{ {
path link = read_symlink(result, ec); path link = read_symlink(result, ec);
if (!ec.value()) if (!ec)
{ {
if (link.is_absolute()) if (--max_allowed_symlinks == 0)
ec.assign(ELOOP, std::generic_category());
else
{ {
result = link.root_path(); if (link.is_absolute())
link = link.relative_path(); {
result = link.root_path();
link = link.relative_path();
}
else
result.remove_filename();
cmpts.insert(cmpts.begin(), link.begin(), link.end());
} }
else
result.remove_filename();
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; return result;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment