From: Jonathan Wakely Date: Wed, 23 Sep 2015 11:26:50 +0000 (+0100) Subject: Limit number of symlinks that canonical() will resolve X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=07dc170b6f2dd893e6b4befe6706dfc0e48771d9;p=gcc.git 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 --- diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 578c5510b01..17d82e3de71 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,8 @@ +2015-09-23 Jonathan Wakely + + * src/filesystem/ops.cc (canonical): Simplify error handling and + limit number of symlinks that can be resolved. + 2015-09-23 Jonathan Wakely * acinclude.m4 (GLIBCXX_CHECK_FILESYSTEM_DEPS): Remove _GLIBCXX_ 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; }