diff options
author | Bruno Cardoso Lopes <bruno.cardoso@gmail.com> | 2016-03-17 02:20:43 +0000 |
---|---|---|
committer | Bruno Cardoso Lopes <bruno.cardoso@gmail.com> | 2016-03-17 02:20:43 +0000 |
commit | b76c02771786ecb235ed6da6dda845e2a06330be (patch) | |
tree | 2cd1893cca1f11ea379f87d1c21c901cf20a9fa5 /clang/lib/Frontend/ModuleDependencyCollector.cpp | |
parent | 312038872df0e44d74b3009c4ac03a6ee15d2a86 (diff) | |
download | bcm5719-llvm-b76c02771786ecb235ed6da6dda845e2a06330be.tar.gz bcm5719-llvm-b76c02771786ecb235ed6da6dda845e2a06330be.zip |
Reapply [2]: [VFS] Add support for handling path traversals
This was applied twice r261551 and 263617 and later reverted because:
(1) Windows bot failing on unittests. Change the current behavior to do
not handle path traversals on windows.
(2) Windows bot failed to include llvm/Config/config.h in order to use
HAVE_REALPATH. Use LLVM_ON_UNIX instead, as done in lib/Basic/FileManager.cpp.
Handle ".", ".." and "./" with trailing slashes while collecting files
to be dumped into the vfs overlay directory.
Include the support for symlinks into components. Given the path:
/install-dir/bin/../lib/clang/3.8.0/include/altivec.h, if "bin"
component is a symlink, it's not safe to use `path::remove_dots` here,
and `realpath` is used to get the right answer. Since `realpath`
is expensive, we only do it at collecting time (which only happens
during the crash reproducer) and cache the base directory for fast lookups.
Overall, this makes the input to the VFS YAML file to be canonicalized
to never contain traversal components.
Differential Revision: http://reviews.llvm.org/D17104
rdar://problem/24499339
llvm-svn: 263686
Diffstat (limited to 'clang/lib/Frontend/ModuleDependencyCollector.cpp')
-rw-r--r-- | clang/lib/Frontend/ModuleDependencyCollector.cpp | 81 |
1 files changed, 73 insertions, 8 deletions
diff --git a/clang/lib/Frontend/ModuleDependencyCollector.cpp b/clang/lib/Frontend/ModuleDependencyCollector.cpp index 9768a164acb..c4e65d1291c 100644 --- a/clang/lib/Frontend/ModuleDependencyCollector.cpp +++ b/clang/lib/Frontend/ModuleDependencyCollector.cpp @@ -13,8 +13,9 @@ #include "clang/Frontend/Utils.h" #include "clang/Serialization/ASTReader.h" -#include "llvm/ADT/StringSet.h" +#include "llvm/ADT/StringMap.h" #include "llvm/ADT/iterator_range.h" +#include "llvm/Config/config.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" @@ -25,7 +26,9 @@ namespace { /// Private implementation for ModuleDependencyCollector class ModuleDependencyListener : public ASTReaderListener { ModuleDependencyCollector &Collector; + llvm::StringMap<std::string> SymLinkMap; + bool getRealPath(StringRef SrcPath, SmallVectorImpl<char> &Result); std::error_code copyToRoot(StringRef Src); public: ModuleDependencyListener(ModuleDependencyCollector &Collector) @@ -57,6 +60,48 @@ void ModuleDependencyCollector::writeFileMap() { VFSWriter.write(OS); } +// TODO: move this to Support/Path.h and check for HAVE_REALPATH? +static bool real_path(StringRef SrcPath, SmallVectorImpl<char> &RealPath) { +#ifdef LLVM_ON_UNIX + char CanonicalPath[PATH_MAX]; + + // TODO: emit a warning in case this fails...? + if (!realpath(SrcPath.str().c_str(), CanonicalPath)) + return false; + + SmallString<256> RPath(CanonicalPath); + RealPath.swap(RPath); + return true; +#else + // FIXME: Add support for systems without realpath. + return false; +#endif +} + +bool ModuleDependencyListener::getRealPath(StringRef SrcPath, + SmallVectorImpl<char> &Result) { + using namespace llvm::sys; + SmallString<256> RealPath; + StringRef FileName = path::filename(SrcPath); + std::string Dir = path::parent_path(SrcPath).str(); + auto DirWithSymLink = SymLinkMap.find(Dir); + + // Use real_path to fix any symbolic link component present in a path. + // Computing the real path is expensive, cache the search through the + // parent path directory. + if (DirWithSymLink == SymLinkMap.end()) { + if (!real_path(Dir, RealPath)) + return false; + SymLinkMap[Dir] = RealPath.str(); + } else { + RealPath = DirWithSymLink->second; + } + + path::append(RealPath, FileName); + Result.swap(RealPath); + return true; +} + std::error_code ModuleDependencyListener::copyToRoot(StringRef Src) { using namespace llvm::sys; @@ -65,22 +110,42 @@ std::error_code ModuleDependencyListener::copyToRoot(StringRef Src) { fs::make_absolute(AbsoluteSrc); // Canonicalize to a native path to avoid mixed separator styles. path::native(AbsoluteSrc); - // TODO: We probably need to handle .. as well as . in order to have valid - // input to the YAMLVFSWriter. - path::remove_dots(AbsoluteSrc); + // Remove redundant leading "./" pieces and consecutive separators. + AbsoluteSrc = path::remove_leading_dotslash(AbsoluteSrc); + + // Canonicalize path by removing "..", "." components. + SmallString<256> CanonicalPath = AbsoluteSrc; + path::remove_dots(CanonicalPath, /*remove_dot_dot=*/true); + + // If a ".." component is present after a symlink component, remove_dots may + // lead to the wrong real destination path. Let the source be canonicalized + // like that but make sure the destination uses the real path. + bool HasDotDotInPath = + std::count(path::begin(AbsoluteSrc), path::end(AbsoluteSrc), "..") > 0; + SmallString<256> RealPath; + bool HasRemovedSymlinkComponent = HasDotDotInPath && + getRealPath(AbsoluteSrc, RealPath) && + !StringRef(CanonicalPath).equals(RealPath); // Build the destination path. SmallString<256> Dest = Collector.getDest(); - path::append(Dest, path::relative_path(AbsoluteSrc)); + path::append(Dest, path::relative_path(HasRemovedSymlinkComponent ? RealPath + : CanonicalPath)); // Copy the file into place. if (std::error_code EC = fs::create_directories(path::parent_path(Dest), /*IgnoreExisting=*/true)) return EC; - if (std::error_code EC = fs::copy_file(AbsoluteSrc, Dest)) + if (std::error_code EC = fs::copy_file( + HasRemovedSymlinkComponent ? RealPath : CanonicalPath, Dest)) return EC; - // Use the absolute path under the root for the file mapping. - Collector.addFileMapping(AbsoluteSrc, Dest); + + // Use the canonical path under the root for the file mapping. Also create + // an additional entry for the real path. + Collector.addFileMapping(CanonicalPath, Dest); + if (HasRemovedSymlinkComponent) + Collector.addFileMapping(RealPath, Dest); + return std::error_code(); } |