summaryrefslogtreecommitdiff
path: root/libstdc++-v3
diff options
context:
space:
mode:
authorredi <redi@138bc75d-0d04-0410-961f-82ee72b054a4>2015-09-23 11:26:50 +0000
committerredi <redi@138bc75d-0d04-0410-961f-82ee72b054a4>2015-09-23 11:26:50 +0000
commit22d6391584cbaca2ddad937a3a2e4fbe7fdb91b5 (patch)
tree49b6053f8e3db3ee5082b14731c5bf3a759db7bf /libstdc++-v3
parent8dabee1bf1ca4c6f438a1872428bd1c0e8aa53eb (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: svn+ssh://gcc.gnu.org/svn/gcc/trunk@228043 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libstdc++-v3')
-rw-r--r--libstdc++-v3/ChangeLog5
-rw-r--r--libstdc++-v3/src/filesystem/ops.cc60
2 files changed, 32 insertions, 33 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index 578c5510b01c..17d82e3de71a 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -1,5 +1,10 @@
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_
prefix from HAVE_STRUCT_DIRENT_D_TYPE.
* config.h.in: Regenerate.
diff --git a/libstdc++-v3/src/filesystem/ops.cc b/libstdc++-v3/src/filesystem/ops.cc
index 5ff8120f6076..7b261fb93aae 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;
}