diff options
author | Jonathan Wakely <jwakely@redhat.com> | 2015-09-23 12:26:50 +0100 |
---|---|---|
committer | Jonathan Wakely <redi@gcc.gnu.org> | 2015-09-23 12:26:50 +0100 |
commit | 07dc170b6f2dd893e6b4befe6706dfc0e48771d9 (patch) | |
tree | 49b6053f8e3db3ee5082b14731c5bf3a759db7bf /libstdc++-v3/src | |
parent | 429ee11aa39ba700510d789b446d74b65e202754 (diff) | |
download | gcc-07dc170b6f2dd893e6b4befe6706dfc0e48771d9.zip gcc-07dc170b6f2dd893e6b4befe6706dfc0e48771d9.tar.gz gcc-07dc170b6f2dd893e6b4befe6706dfc0e48771d9.tar.bz2 |
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
Diffstat (limited to 'libstdc++-v3/src')
-rw-r--r-- | libstdc++-v3/src/filesystem/ops.cc | 60 |
1 files changed, 27 insertions, 33 deletions
diff --git a/libstdc++-v3/src/filesystem/ops.cc b/libstdc++-v3/src/filesystem/ops.cc index 5ff8120..7b261fb 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; } |