diff options
author | Bruno Cardoso Lopes <bruno.cardoso@gmail.com> | 2016-02-22 18:41:01 +0000 |
---|---|---|
committer | Bruno Cardoso Lopes <bruno.cardoso@gmail.com> | 2016-02-22 18:41:01 +0000 |
commit | 956e6a0dc6146d9625fe58a20bdf16515b036505 (patch) | |
tree | 0c8852b3d5388ff763654624dadb13427083420b /clang/lib/Basic/VirtualFileSystem.cpp | |
parent | b8a91bbf0476e1b2c44520f56d131dfbdccb8237 (diff) | |
download | llvm-956e6a0dc6146d9625fe58a20bdf16515b036505.zip llvm-956e6a0dc6146d9625fe58a20bdf16515b036505.tar.gz llvm-956e6a0dc6146d9625fe58a20bdf16515b036505.tar.bz2 |
[VFS] Add support for handling path traversals
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: 261551
Diffstat (limited to 'clang/lib/Basic/VirtualFileSystem.cpp')
-rw-r--r-- | clang/lib/Basic/VirtualFileSystem.cpp | 54 |
1 files changed, 39 insertions, 15 deletions
diff --git a/clang/lib/Basic/VirtualFileSystem.cpp b/clang/lib/Basic/VirtualFileSystem.cpp index 6977f40..68ad428 100644 --- a/clang/lib/Basic/VirtualFileSystem.cpp +++ b/clang/lib/Basic/VirtualFileSystem.cpp @@ -111,6 +111,20 @@ bool FileSystem::exists(const Twine &Path) { return Status && Status->exists(); } +#ifndef NDEBUG +static bool isTraversalComponent(StringRef Component) { + return Component.equals("..") || Component.equals("."); +} + +static bool pathHasTraversal(StringRef Path) { + using namespace llvm::sys; + for (StringRef Comp : llvm::make_range(path::begin(Path), path::end(Path))) + if (isTraversalComponent(Comp)) + return true; + return false; +} +#endif + //===-----------------------------------------------------------------------===/ // RealFileSystem implementation //===-----------------------------------------------------------------------===/ @@ -807,6 +821,9 @@ public: /// /// and inherit their attributes from the external contents. /// +/// Virtual file paths and external files are expected to be canonicalized +/// without "..", "." and "./" in their paths. +/// /// In both cases, the 'name' field may contain multiple path components (e.g. /// /path/to/file). However, any directory that contains more than one child /// must be uniquely represented by a directory entry. @@ -1004,7 +1021,13 @@ class RedirectingFileSystemParser { if (Key == "name") { if (!parseScalarString(I->getValue(), Value, Buffer)) return nullptr; - Name = Value; + + SmallString<256> Path(Value); + // Guarantee that old YAML files containing paths with ".." and "." are + // properly canonicalized before read into the VFS. + Path = sys::path::remove_leading_dotslash(Path); + sys::path::remove_dots(Path, /*remove_dot_dot=*/true); + Name = Path.str(); } else if (Key == "type") { if (!parseScalarString(I->getValue(), Value, Buffer)) return nullptr; @@ -1048,7 +1071,12 @@ class RedirectingFileSystemParser { HasContents = true; if (!parseScalarString(I->getValue(), Value, Buffer)) return nullptr; - ExternalContentsPath = Value; + SmallString<256> Path(Value); + // Guarantee that old YAML files containing paths with ".." and "." are + // properly canonicalized before read into the VFS. + Path = sys::path::remove_leading_dotslash(Path); + sys::path::remove_dots(Path, /*remove_dot_dot=*/true); + ExternalContentsPath = Path.str(); } else if (Key == "use-external-name") { bool Val; if (!parseScalarBool(I->getValue(), Val)) @@ -1238,6 +1266,12 @@ ErrorOr<Entry *> RedirectingFileSystem::lookupPath(const Twine &Path_) { if (std::error_code EC = makeAbsolute(Path)) return EC; + // Canonicalize path by removing ".", "..", "./", etc components. This is + // a VFS request, do bot bother about symlinks in the path components + // but canonicalize in order to perform the correct entry search. + Path = sys::path::remove_leading_dotslash(Path); + sys::path::remove_dots(Path, /*remove_dot_dot=*/true); + if (Path.empty()) return make_error_code(llvm::errc::invalid_argument); @@ -1254,10 +1288,10 @@ ErrorOr<Entry *> RedirectingFileSystem::lookupPath(const Twine &Path_) { ErrorOr<Entry *> RedirectingFileSystem::lookupPath(sys::path::const_iterator Start, sys::path::const_iterator End, Entry *From) { - if (Start->equals(".")) - ++Start; + assert(!isTraversalComponent(*Start) && + !isTraversalComponent(From->getName()) && + "Paths should not contain traversal components"); - // FIXME: handle .. if (CaseSensitive ? !Start->equals(From->getName()) : !Start->equals_lower(From->getName())) // failure to match @@ -1376,16 +1410,6 @@ UniqueID vfs::getNextVirtualUniqueID() { return UniqueID(std::numeric_limits<uint64_t>::max(), ID); } -#ifndef NDEBUG -static bool pathHasTraversal(StringRef Path) { - using namespace llvm::sys; - for (StringRef Comp : llvm::make_range(path::begin(Path), path::end(Path))) - if (Comp == "." || Comp == "..") - return true; - return false; -} -#endif - void YAMLVFSWriter::addFileMapping(StringRef VirtualPath, StringRef RealPath) { assert(sys::path::is_absolute(VirtualPath) && "virtual path not absolute"); assert(sys::path::is_absolute(RealPath) && "real path not absolute"); |