aboutsummaryrefslogtreecommitdiff
path: root/libstdc++-v3/src
diff options
context:
space:
mode:
authorJonathan Wakely <jwakely@redhat.com>2015-09-23 11:26:50 +0000
committerJonathan Wakely <jwakely@redhat.com>2015-09-23 11:26:50 +0000
commit0f6a51cf4137edb34c8ece25b46709d94d53eb7e (patch)
tree49b6053f8e3db3ee5082b14731c5bf3a759db7bf /libstdc++-v3/src
parent7d6e8a64476619b2e85dac1fe40891c02e41f8e1 (diff)
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. git-svn-id: https://gcc.gnu.org/svn/gcc/trunk@228043 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libstdc++-v3/src')
-rw-r--r--libstdc++-v3/src/filesystem/ops.cc60
1 files changed, 27 insertions, 33 deletions
diff --git a/libstdc++-v3/src/filesystem/ops.cc b/libstdc++-v3/src/filesystem/ops.cc
index 5ff8120f607..7b261fb93aa 100644
--- a/libstdc++-v3/src/filesystem/ops.cc
+++ b/libstdc++-v3/src/filesystem/ops.cc
@@ -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())
+ if (--max_allowed_symlinks == 0)
+ ec.assign(ELOOP, std::generic_category());
+ else
{
- result = link.root_path();
- link = link.relative_path();
+ if (link.is_absolute())
+ {
+ 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;
}