diff options
author | skerner@chromium.org <skerner@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-05-12 15:13:57 +0000 |
---|---|---|
committer | skerner@chromium.org <skerner@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-05-12 15:13:57 +0000 |
commit | 01e2a1fabe5a6d0065f535a9de4bdd98f0640906 (patch) | |
tree | 2050dd5669e2907324d13002cb261ffa15c8d1f9 | |
parent | 4979b09a75936283a62772b7078de381d60061fc (diff) | |
download | chromium_src-01e2a1fabe5a6d0065f535a9de4bdd98f0640906.zip chromium_src-01e2a1fabe5a6d0065f535a9de4bdd98f0640906.tar.gz chromium_src-01e2a1fabe5a6d0065f535a9de4bdd98f0640906.tar.bz2 |
Use realpath() to find the path to the extension unpack dir on posix systems.
Extensions are unpacked by a sandboxed utility process. The sandbox forbids file access outside the directory the extension will be unpacked in. If the path to that directory contains a symbolic link, then unpacking will fail because following the link will cause file system access outside the sandbox path. Use realpath() to get a symlink free path to the directory where the extension will be unpacked.
A similar issue exists on windows, with junctions instead of symlinks. This will be fixed in another change.
BUG=13044,35198
TEST=FileUtilTest.RealPath
Review URL: http://codereview.chromium.org/2001013
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@47032 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | base/file_util.h | 7 | ||||
-rw-r--r-- | base/file_util_posix.cc | 10 | ||||
-rw-r--r-- | base/file_util_unittest.cc | 51 | ||||
-rw-r--r-- | chrome/browser/utility_process_host.cc | 25 |
4 files changed, 92 insertions, 1 deletions
diff --git a/base/file_util.h b/base/file_util.h index a129876..64a91ee 100644 --- a/base/file_util.h +++ b/base/file_util.h @@ -279,6 +279,13 @@ bool IsDot(const FilePath& path); // Returns true if the given path's base name is "..". bool IsDotDot(const FilePath& path); +#if defined(OS_POSIX) +// Set |real_path| to |path| with symbolic links expanded. +// Windows support (expanding junctions) comming soon: +// http://crbug.com/13044 +bool RealPath(const FilePath& path, FilePath* real_path); +#endif + // Used to hold information about a given file path. See GetFileInfo below. struct FileInfo { // The size of the file in bytes. Undefined when is_directory is true. diff --git a/base/file_util_posix.cc b/base/file_util_posix.cc index d9cbe09..9db41fe 100644 --- a/base/file_util_posix.cc +++ b/base/file_util_posix.cc @@ -14,6 +14,7 @@ #include <string.h> #include <sys/errno.h> #include <sys/mman.h> +#include <sys/param.h> #include <sys/stat.h> #include <sys/time.h> #include <sys/types.h> @@ -735,6 +736,15 @@ bool HasFileBeenModifiedSince(const FileEnumerator::FindInfo& find_info, return find_info.stat.st_mtime >= cutoff_time.ToTimeT(); } +bool RealPath(const FilePath& path, FilePath* real_path) { + FilePath::CharType buf[PATH_MAX]; + if (!realpath(path.value().c_str(), buf)) + return false; + + *real_path = FilePath(buf); + return true; +} + #if !defined(OS_MACOSX) bool GetTempDir(FilePath* path) { const char* tmp = getenv("TMPDIR"); diff --git a/base/file_util_unittest.cc b/base/file_util_unittest.cc index c496290..efe79c9 100644 --- a/base/file_util_unittest.cc +++ b/base/file_util_unittest.cc @@ -387,6 +387,57 @@ TEST_F(FileUtilTest, FileAndDirectorySize) { EXPECT_EQ(size_f1 + size_f2 + 3, computed_size); } +#if defined(OS_POSIX) +TEST_F(FileUtilTest, RealPath) { + // Get the real test directory, in case some future change to the + // test setup makes the path to test_dir_ include a symlink. + FilePath real_test_dir; + ASSERT_TRUE(file_util::RealPath(test_dir_, &real_test_dir)); + + FilePath real_path; + ASSERT_TRUE(file_util::RealPath(real_test_dir, &real_path)); + ASSERT_TRUE(real_test_dir == real_path); + + // Link one file to another. + FilePath link_from = real_test_dir.Append(FPL("from_file")); + FilePath link_to = real_test_dir.Append(FPL("to_file")); + CreateTextFile(link_to, bogus_content); + + ASSERT_EQ(0, symlink(link_to.value().c_str(), link_from.value().c_str())) + << "Failed to create file symlink."; + + // Check that RealPath sees the link. + ASSERT_TRUE(file_util::RealPath(link_from, &real_path)); + ASSERT_TRUE(link_to != link_from); + ASSERT_TRUE(link_to == real_path); + + + // Link to a directory. + link_from = real_test_dir.Append(FPL("from_dir")); + link_to = real_test_dir.Append(FPL("to_dir")); + file_util::CreateDirectory(link_to); + + ASSERT_EQ(0, symlink(link_to.value().c_str(), link_from.value().c_str())) + << "Failed to create directory symlink."; + + ASSERT_TRUE(file_util::RealPath(link_from, &real_path)); + ASSERT_TRUE(link_to != link_from); + ASSERT_TRUE(link_to == real_path); + + + // Test that a loop in the links causes RealPath() to return false. + link_from = real_test_dir.Append(FPL("link_a")); + link_to = real_test_dir.Append(FPL("link_b")); + ASSERT_EQ(0, symlink(link_to.value().c_str(), link_from.value().c_str())) + << "Failed to create loop symlink a."; + ASSERT_EQ(0, symlink(link_from.value().c_str(), link_to.value().c_str())) + << "Failed to create loop symlink b."; + + // Infinite loop! + ASSERT_FALSE(file_util::RealPath(link_from, &real_path)); +} +#endif // defined(OS_POSIX) + TEST_F(FileUtilTest, DeleteNonExistent) { FilePath non_existent = test_dir_.AppendASCII("bogus_file_dne.foobar"); ASSERT_FALSE(file_util::PathExists(non_existent)); diff --git a/chrome/browser/utility_process_host.cc b/chrome/browser/utility_process_host.cc index 2f7ce5d..118234d7e 100644 --- a/chrome/browser/utility_process_host.cc +++ b/chrome/browser/utility_process_host.cc @@ -26,9 +26,32 @@ UtilityProcessHost::~UtilityProcessHost() { } bool UtilityProcessHost::StartExtensionUnpacker(const FilePath& extension) { + FilePath initial_path = extension.DirName(); + FilePath real_path; + + // The utility process will have access to the directory passed to + // StartProcess(). That directory should not be a symlink or NTFS + // junctions, because when the path is used, following the link will + // cause file system access outside the sandbox path. + +#if defined(OS_POSIX) + // Resolve symlinks to get a symlink free path. + if (!file_util::RealPath(initial_path, &real_path)) { + real_path = initial_path; + } +#else + // TODO(skerner): For windows, we need to expand NTFS junctions. + // http://crbug.com/13044 + real_path = initial_path; +#endif + + // TODO(skerner): Remove this logging once we understand crbug.com/35198 + LOG(INFO) << "initial_path: " << initial_path.value(); + LOG(INFO) << "real_path: " << real_path.value(); + // Grant the subprocess access to the entire subdir the extension file is // in, so that it can unpack to that dir. - if (!StartProcess(extension.DirName())) + if (!StartProcess(real_path)) return false; Send(new UtilityMsg_UnpackExtension(extension)); |