Validate source and mount path.

This CL add validations of the source and mount path to ensure:
1. The source path is fully canonicalized before being checked by the
   CanMount() method of a mount manager.
2. The mount path must be an immediate child of the mount root
   directory of a mount manager.

BUG=chromium:351811
TEST=Tested the following:
1. Build and run unit tests.
2. Run the following tests:
   - platform_CrosDisksDBus
   - platform_CrosDisksFilesystem
   - platform_CrosDisksArchive
3. Verify that Files.app can mount an external USB drive.
4. Verify that Files.app can open a ZIP file from:
   - user's Downloads directory
   - an external USB drive
   - within another ZIP file
   - Drive

Change-Id: I7a880818a565820c6549a9b127292cad178b010b
Reviewed-on: https://chromium-review.googlesource.com/189715
Reviewed-by: Ben Chan <benchan@chromium.org>
Commit-Queue: Ben Chan <benchan@chromium.org>
Tested-by: Ben Chan <benchan@chromium.org>
Reviewed-by: Kees Cook <keescook@chromium.org>
Reviewed-by: Jorge Lucangeli Obes <jorgelo@chromium.org>
diff --git a/cros_disks_server.cc b/cros_disks_server.cc
index d13a191..690e683 100644
--- a/cros_disks_server.cc
+++ b/cros_disks_server.cc
@@ -84,15 +84,19 @@
                             DBus::Error& error) {  // NOLINT
   MountErrorType error_type = MOUNT_ERROR_INVALID_PATH;
   MountSourceType source_type = MOUNT_SOURCE_INVALID;
+  string source_path;
   string mount_path;
 
-  for (vector<MountManager*>::iterator manager_iter = mount_managers_.begin();
-       manager_iter != mount_managers_.end(); ++manager_iter) {
-    MountManager* manager = *manager_iter;
-    if (manager->CanMount(path)) {
-      source_type = manager->GetMountSourceType();
-      error_type = manager->Mount(path, filesystem_type, options, &mount_path);
-      break;
+  if (platform_->GetRealPath(path, &source_path)) {
+    for (vector<MountManager*>::iterator manager_iter = mount_managers_.begin();
+         manager_iter != mount_managers_.end(); ++manager_iter) {
+      MountManager* manager = *manager_iter;
+      if (manager->CanMount(source_path)) {
+        source_type = manager->GetMountSourceType();
+        error_type =
+            manager->Mount(source_path, filesystem_type, options, &mount_path);
+        break;
+      }
     }
   }
 
diff --git a/mount_manager.cc b/mount_manager.cc
index f7ac2f7..ee79ef1 100644
--- a/mount_manager.cc
+++ b/mount_manager.cc
@@ -118,7 +118,6 @@
   // the source path. If an error occurs, ShouldReserveMountPathOnError()
   // is not called to reserve the mount path as a reserved mount path still
   // requires a proper mount directory.
-  bool mount_path_created;
   if (mount_path->empty()) {
     actual_mount_path = SuggestMountPath(source_path);
     if (!mount_label.empty()) {
@@ -126,10 +125,20 @@
       actual_mount_path =
           FilePath(actual_mount_path).DirName().Append(mount_label).value();
     }
+  } else {
+    actual_mount_path = *mount_path;
+  }
+
+  if (!IsValidMountPath(actual_mount_path)) {
+    LOG(ERROR) << "Mount path '" << actual_mount_path << "' is invalid";
+    return MOUNT_ERROR_INVALID_PATH;
+  }
+
+  bool mount_path_created;
+  if (mount_path->empty()) {
     mount_path_created = platform_->CreateOrReuseEmptyDirectoryWithFallback(
         &actual_mount_path, kMaxNumMountTrials, GetReservedMountPaths());
   } else {
-    actual_mount_path = *mount_path;
     mount_path_created = !IsMountPathReserved(actual_mount_path) &&
         platform_->CreateOrReuseEmptyDirectory(actual_mount_path);
   }
@@ -369,4 +378,8 @@
                     path_components.begin());
 }
 
+bool MountManager::IsValidMountPath(const std::string& mount_path) const{
+  return IsPathImmediateChildOfParent(mount_path, mount_root_);
+}
+
 }  // namespace cros_disks
diff --git a/mount_manager.h b/mount_manager.h
index cebac09..5a8abd7 100644
--- a/mount_manager.h
+++ b/mount_manager.h
@@ -195,6 +195,14 @@
   bool IsPathImmediateChildOfParent(const std::string& path,
                                     const std::string& parent) const;
 
+  // Returns true if |mount_path| is a valid mount path, which should be an
+  // immediate child of the mount root specified by |mount_root_|. The check
+  // performed by this method takes the simplest approach and does not first try
+  // to canonicalize |mount_path|, resolve symlinks or determine the absolute
+  // path of |mount_path|, so a legitimate mount path may be deemed as invalid.
+  // But we don't consider these cases as part of the use cases of cros-disks.
+  bool IsValidMountPath(const std::string& mount_path) const;
+
   // Returns the root directory under which mount directories are created.
   const std::string& mount_root() const { return mount_root_; }
 
@@ -228,6 +236,7 @@
   FRIEND_TEST(MountManagerTest, ExtractSupportedUnmountOptions);
   FRIEND_TEST(MountManagerTest, ExtractUnsupportedUnmountOptions);
   FRIEND_TEST(MountManagerTest, IsPathImmediateChildOfParent);
+  FRIEND_TEST(MountManagerTest, IsValidMountPath);
 
   DISALLOW_COPY_AND_ASSIGN(MountManager);
 };
diff --git a/mount_manager_unittest.cc b/mount_manager_unittest.cc
index bd72718..a62c627 100644
--- a/mount_manager_unittest.cc
+++ b/mount_manager_unittest.cc
@@ -14,7 +14,6 @@
 #include <string>
 #include <vector>
 
-#include <base/files/scoped_temp_dir.h>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
@@ -30,7 +29,10 @@
 
 namespace {
 
-const char kMountRootDirectory[] = "/test";
+const char kMountRootDirectory[] = "/media/removable";
+const char kTestSourcePath[] = "source";
+const char kTestMountPath[] = "/media/removable/test";
+const char kInvalidMountPath[] = "/media/removable/../test/doc";
 
 }  // namespace
 
@@ -161,7 +163,7 @@
 // Verifies that MountManager::Mount() returns an error when it is invoked
 // with a NULL mount path.
 TEST_F(MountManagerTest, MountFailedWithNullMountPath) {
-  source_path_ = "source";
+  source_path_ = kTestSourcePath;
 
   EXPECT_CALL(platform_, CreateOrReuseEmptyDirectory(_)).Times(0);
   EXPECT_CALL(platform_, CreateOrReuseEmptyDirectoryWithFallback(_, _, _))
@@ -175,11 +177,76 @@
             manager_.Mount(source_path_, filesystem_type_, options_, NULL));
 }
 
+// Verifies that MountManager::Mount() returns an error when it is invoked
+// with an invalid mount path.
+TEST_F(MountManagerTest, MountFailedWithInvalidMountPath) {
+  source_path_ = kTestSourcePath;
+  mount_path_ = kInvalidMountPath;
+
+  EXPECT_CALL(platform_, CreateOrReuseEmptyDirectory(_)).Times(0);
+  EXPECT_CALL(platform_, CreateOrReuseEmptyDirectoryWithFallback(_, _, _))
+      .Times(0);
+  EXPECT_CALL(platform_, RemoveEmptyDirectory(_)).Times(0);
+  EXPECT_CALL(manager_, DoMount(_, _, _, _)).Times(0);
+  EXPECT_CALL(manager_, DoUnmount(_, _)).Times(0);
+  EXPECT_CALL(manager_, SuggestMountPath(_)).Times(0);
+
+  EXPECT_EQ(MOUNT_ERROR_INVALID_PATH,
+            manager_.Mount(source_path_, filesystem_type_, options_,
+                           &mount_path_));
+}
+
+// Verifies that MountManager::Mount() returns an error when it is invoked
+// without a given mount path and the suggested mount path is invalid.
+TEST_F(MountManagerTest, MountFailedWithInvalidSuggestedMountPath) {
+  source_path_ = kTestSourcePath;
+  string suggested_mount_path = kInvalidMountPath;
+
+  EXPECT_CALL(platform_, CreateOrReuseEmptyDirectory(_)).Times(0);
+  EXPECT_CALL(platform_, CreateOrReuseEmptyDirectoryWithFallback(_, _, _))
+      .Times(0);
+  EXPECT_CALL(platform_, RemoveEmptyDirectory(_)).Times(0);
+  EXPECT_CALL(manager_, DoMount(_, _, _, _)).Times(0);
+  EXPECT_CALL(manager_, DoUnmount(_, _)).Times(0);
+  EXPECT_CALL(manager_, SuggestMountPath(_))
+      .WillRepeatedly(Return(suggested_mount_path));
+
+  EXPECT_EQ(MOUNT_ERROR_INVALID_PATH,
+            manager_.Mount(source_path_, filesystem_type_, options_,
+                           &mount_path_));
+
+  options_.push_back("mountlabel=custom_label");
+  EXPECT_EQ(MOUNT_ERROR_INVALID_PATH,
+            manager_.Mount(source_path_, filesystem_type_, options_,
+                           &mount_path_));
+}
+
+// Verifies that MountManager::Mount() returns an error when it is invoked
+// with an mount label that yields an invalid mount path.
+TEST_F(MountManagerTest, MountFailedWithInvalidMountLabel) {
+  source_path_ = kTestSourcePath;
+  string suggested_mount_path = kTestSourcePath;
+  options_.push_back("mountlabel=../custom_label");
+
+  EXPECT_CALL(platform_, CreateOrReuseEmptyDirectory(_)).Times(0);
+  EXPECT_CALL(platform_, CreateOrReuseEmptyDirectoryWithFallback(_, _, _))
+      .Times(0);
+  EXPECT_CALL(platform_, RemoveEmptyDirectory(_)).Times(0);
+  EXPECT_CALL(manager_, DoMount(_, _, _, _)).Times(0);
+  EXPECT_CALL(manager_, DoUnmount(_, _)).Times(0);
+  EXPECT_CALL(manager_, SuggestMountPath(_))
+      .WillOnce(Return(suggested_mount_path));
+
+  EXPECT_EQ(MOUNT_ERROR_INVALID_PATH,
+            manager_.Mount(source_path_, filesystem_type_, options_,
+                           &mount_path_));
+}
+
 // Verifies that MountManager::Mount() returns an error when it fails to
 // create the specified mount directory.
 TEST_F(MountManagerTest, MountFailedInCreateOrReuseEmptyDirectory) {
-  source_path_ = "source";
-  mount_path_ = "target";
+  source_path_ = kTestSourcePath;
+  mount_path_ = kTestMountPath;
 
   EXPECT_CALL(platform_, CreateOrReuseEmptyDirectory(mount_path_))
       .WillOnce(Return(false));
@@ -193,15 +260,15 @@
   EXPECT_EQ(MOUNT_ERROR_DIRECTORY_CREATION_FAILED,
             manager_.Mount(source_path_, filesystem_type_, options_,
                            &mount_path_));
-  EXPECT_EQ("target", mount_path_);
+  EXPECT_EQ(kTestMountPath, mount_path_);
   EXPECT_FALSE(manager_.IsMountPathInCache(mount_path_));
 }
 
 // Verifies that MountManager::Mount() returns an error when it fails to
 // create a specified but already reserved mount directory.
 TEST_F(MountManagerTest, MountFailedInCreateDirectoryDueToReservedMountPath) {
-  source_path_ = "source";
-  mount_path_ = "target";
+  source_path_ = kTestSourcePath;
+  mount_path_ = kTestMountPath;
 
   EXPECT_CALL(platform_, CreateOrReuseEmptyDirectory(mount_path_)).Times(0);
   EXPECT_CALL(platform_, CreateOrReuseEmptyDirectoryWithFallback(_, _, _))
@@ -218,7 +285,7 @@
   EXPECT_EQ(MOUNT_ERROR_DIRECTORY_CREATION_FAILED,
             manager_.Mount(source_path_, filesystem_type_, options_,
                            &mount_path_));
-  EXPECT_EQ("target", mount_path_);
+  EXPECT_EQ(kTestMountPath, mount_path_);
   EXPECT_FALSE(manager_.IsMountPathInCache(mount_path_));
   EXPECT_TRUE(manager_.IsMountPathReserved(mount_path_));
   EXPECT_EQ(MOUNT_ERROR_UNKNOWN_FILESYSTEM,
@@ -228,8 +295,8 @@
 // Verifies that MountManager::Mount() returns an error when it fails to
 // create a mount directory after a number of trials.
 TEST_F(MountManagerTest, MountFailedInCreateOrReuseEmptyDirectoryWithFallback) {
-  source_path_ = "source";
-  string suggested_mount_path = "target";
+  source_path_ = kTestSourcePath;
+  string suggested_mount_path = kTestMountPath;
 
   EXPECT_CALL(platform_, CreateOrReuseEmptyDirectory(_)).Times(0);
   EXPECT_CALL(platform_, CreateOrReuseEmptyDirectoryWithFallback(_, _, _))
@@ -250,8 +317,8 @@
 // Verifies that MountManager::Mount() returns an error when it fails to
 // set the ownership of the created mount directory.
 TEST_F(MountManagerTest, MountFailedInSetOwnership) {
-  source_path_ = "source";
-  mount_path_ = "target";
+  source_path_ = kTestSourcePath;
+  mount_path_ = kTestMountPath;
 
   EXPECT_CALL(platform_, CreateOrReuseEmptyDirectory(mount_path_))
       .WillOnce(Return(true));
@@ -269,15 +336,15 @@
   EXPECT_EQ(MOUNT_ERROR_DIRECTORY_CREATION_FAILED,
             manager_.Mount(source_path_, filesystem_type_, options_,
                            &mount_path_));
-  EXPECT_EQ("target", mount_path_);
+  EXPECT_EQ(kTestMountPath, mount_path_);
   EXPECT_FALSE(manager_.IsMountPathInCache(mount_path_));
 }
 
 // Verifies that MountManager::Mount() returns an error when it fails to
 // set the permissions of the created mount directory.
 TEST_F(MountManagerTest, MountFailedInSetPermissions) {
-  source_path_ = "source";
-  mount_path_ = "target";
+  source_path_ = kTestSourcePath;
+  mount_path_ = kTestMountPath;
 
   EXPECT_CALL(platform_, CreateOrReuseEmptyDirectory(mount_path_))
       .WillOnce(Return(true));
@@ -296,15 +363,15 @@
   EXPECT_EQ(MOUNT_ERROR_DIRECTORY_CREATION_FAILED,
             manager_.Mount(source_path_, filesystem_type_, options_,
                            &mount_path_));
-  EXPECT_EQ("target", mount_path_);
+  EXPECT_EQ(kTestMountPath, mount_path_);
   EXPECT_FALSE(manager_.IsMountPathInCache(mount_path_));
 }
 
 // Verifies that MountManager::Mount() returns no error when it successfully
 // mounts a source path to a specified mount path.
 TEST_F(MountManagerTest, MountSucceededWithGivenMountPath) {
-  source_path_ = "source";
-  mount_path_ = "target";
+  source_path_ = kTestSourcePath;
+  mount_path_ = kTestMountPath;
 
   EXPECT_CALL(platform_, CreateOrReuseEmptyDirectory(mount_path_))
       .WillOnce(Return(true));
@@ -326,7 +393,7 @@
   EXPECT_EQ(MOUNT_ERROR_NONE,
             manager_.Mount(source_path_, filesystem_type_, options_,
                            &mount_path_));
-  EXPECT_EQ("target", mount_path_);
+  EXPECT_EQ(kTestMountPath, mount_path_);
   EXPECT_TRUE(manager_.IsMountPathInCache(mount_path_));
   EXPECT_TRUE(manager_.UnmountAll());
   EXPECT_FALSE(manager_.IsMountPathReserved(mount_path_));
@@ -335,8 +402,8 @@
 // Verifies that MountManager::Mount() returns no error when it successfully
 // mounts a source path with no mount path specified.
 TEST_F(MountManagerTest, MountSucceededWithEmptyMountPath) {
-  source_path_ = "source";
-  string suggested_mount_path = "target";
+  source_path_ = kTestSourcePath;
+  string suggested_mount_path = kTestMountPath;
 
   EXPECT_CALL(platform_, CreateOrReuseEmptyDirectory(_)).Times(0);
   EXPECT_CALL(platform_, CreateOrReuseEmptyDirectoryWithFallback(_, _, _))
@@ -367,9 +434,9 @@
 // Verifies that MountManager::Mount() returns no error when it successfully
 // mounts a source path with a given mount label in options.
 TEST_F(MountManagerTest, MountSucceededWithGivenMountLabel) {
-  source_path_ = "source";
-  string suggested_mount_path = "parent_path/suggested";
-  string final_mount_path = "parent_path/custom_label";
+  source_path_ = kTestSourcePath;
+  string suggested_mount_path = kTestMountPath;
+  string final_mount_path = string(kMountRootDirectory) + "/custom_label";
   options_.push_back("mountlabel=custom_label");
   vector<string> updated_options;
 
@@ -402,8 +469,8 @@
 // Verifies that MountManager::Mount() handles the mounting of an already
 // mounted source path properly.
 TEST_F(MountManagerTest, MountWithAlreadyMountedSourcePath) {
-  source_path_ = "source";
-  string suggested_mount_path = "target";
+  source_path_ = kTestSourcePath;
+  string suggested_mount_path = kTestMountPath;
 
   EXPECT_CALL(platform_, CreateOrReuseEmptyDirectory(_)).Times(0);
   EXPECT_CALL(platform_, CreateOrReuseEmptyDirectoryWithFallback(_, _, _))
@@ -459,8 +526,8 @@
 // Verifies that MountManager::Mount() successfully reserves a path for a given
 // type of error. A specific mount path is given in this case.
 TEST_F(MountManagerTest, MountSucceededWithGivenMountPathInReservedCase) {
-  source_path_ = "source";
-  mount_path_ = "target";
+  source_path_ = kTestSourcePath;
+  mount_path_ = kTestMountPath;
 
   EXPECT_CALL(platform_, CreateOrReuseEmptyDirectory(mount_path_))
       .WillOnce(Return(true));
@@ -484,7 +551,7 @@
   EXPECT_EQ(MOUNT_ERROR_UNKNOWN_FILESYSTEM,
             manager_.Mount(source_path_, filesystem_type_, options_,
                            &mount_path_));
-  EXPECT_EQ("target", mount_path_);
+  EXPECT_EQ(kTestMountPath, mount_path_);
   EXPECT_TRUE(manager_.IsMountPathInCache(mount_path_));
   EXPECT_TRUE(manager_.IsMountPathReserved(mount_path_));
   EXPECT_TRUE(manager_.UnmountAll());
@@ -495,8 +562,8 @@
 // Verifies that MountManager::Mount() successfully reserves a path for a given
 // type of error. No specific mount path is given in this case.
 TEST_F(MountManagerTest, MountSucceededWithEmptyMountPathInReservedCase) {
-  source_path_ = "source";
-  string suggested_mount_path = "target";
+  source_path_ = kTestSourcePath;
+  string suggested_mount_path = kTestMountPath;
 
   EXPECT_CALL(platform_, CreateOrReuseEmptyDirectory(_)).Times(0);
   EXPECT_CALL(platform_, CreateOrReuseEmptyDirectoryWithFallback(_, _, _))
@@ -532,8 +599,8 @@
 // type of error and returns the same error when it tries to mount the same path
 // again.
 TEST_F(MountManagerTest, MountSucceededWithAlreadyReservedMountPath) {
-  source_path_ = "source";
-  string suggested_mount_path = "target";
+  source_path_ = kTestSourcePath;
+  string suggested_mount_path = kTestMountPath;
 
   EXPECT_CALL(platform_, CreateOrReuseEmptyDirectory(_)).Times(0);
   EXPECT_CALL(platform_, CreateOrReuseEmptyDirectoryWithFallback(_, _, _))
@@ -578,8 +645,8 @@
 // type of error and returns the same error when it tries to mount the same path
 // again.
 TEST_F(MountManagerTest, MountFailedWithGivenMountPathInReservedCase) {
-  source_path_ = "source";
-  mount_path_ = "target";
+  source_path_ = kTestSourcePath;
+  mount_path_ = kTestMountPath;
 
   EXPECT_CALL(platform_, CreateOrReuseEmptyDirectory(mount_path_))
       .WillOnce(Return(true));
@@ -603,7 +670,7 @@
   EXPECT_EQ(MOUNT_ERROR_UNKNOWN_FILESYSTEM,
             manager_.Mount(source_path_, filesystem_type_, options_,
                            &mount_path_));
-  EXPECT_EQ("target", mount_path_);
+  EXPECT_EQ(kTestMountPath, mount_path_);
   EXPECT_FALSE(manager_.IsMountPathInCache(mount_path_));
   EXPECT_FALSE(manager_.IsMountPathReserved(mount_path_));
 }
@@ -611,8 +678,8 @@
 // Verifies that MountManager::Mount() fails to mount or reserve a path for
 // a type of error that is not enabled for reservation.
 TEST_F(MountManagerTest, MountFailedWithEmptyMountPathInReservedCase) {
-  source_path_ = "source";
-  string suggested_mount_path = "target";
+  source_path_ = kTestSourcePath;
+  string suggested_mount_path = kTestMountPath;
 
   EXPECT_CALL(platform_, CreateOrReuseEmptyDirectory(_)).Times(0);
   EXPECT_CALL(platform_, CreateOrReuseEmptyDirectoryWithFallback(_, _, _))
@@ -676,8 +743,8 @@
 // Verifies that MountManager::Unmount() returns no error when it successfully
 // unmounts a source path.
 TEST_F(MountManagerTest, UnmountSucceededWithGivenSourcePath) {
-  source_path_ = "source";
-  mount_path_ = "target";
+  source_path_ = kTestSourcePath;
+  mount_path_ = kTestMountPath;
 
   EXPECT_CALL(platform_, CreateOrReuseEmptyDirectory(mount_path_))
       .WillOnce(Return(true));
@@ -699,7 +766,7 @@
   EXPECT_EQ(MOUNT_ERROR_NONE,
             manager_.Mount(source_path_, filesystem_type_, options_,
                            &mount_path_));
-  EXPECT_EQ("target", mount_path_);
+  EXPECT_EQ(kTestMountPath, mount_path_);
   EXPECT_TRUE(manager_.IsMountPathInCache(mount_path_));
 
   EXPECT_EQ(MOUNT_ERROR_NONE, manager_.Unmount(source_path_, options_));
@@ -709,12 +776,8 @@
 // Verifies that MountManager::Unmount() returns no error when it successfully
 // unmounts a mount path.
 TEST_F(MountManagerTest, UnmountSucceededWithGivenMountPath) {
-  base::ScopedTempDir temp_dir;
-  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
-  string actual_mount_path = temp_dir.path().value();
-
-  source_path_ = "source";
-  mount_path_ = actual_mount_path;
+  source_path_ = kTestSourcePath;
+  mount_path_ = kTestMountPath;
 
   EXPECT_CALL(platform_, CreateOrReuseEmptyDirectory(mount_path_))
       .WillOnce(Return(true));
@@ -736,7 +799,7 @@
   EXPECT_EQ(MOUNT_ERROR_NONE,
             manager_.Mount(source_path_, filesystem_type_, options_,
                            &mount_path_));
-  EXPECT_EQ(actual_mount_path, mount_path_);
+  EXPECT_EQ(kTestMountPath, mount_path_);
   EXPECT_TRUE(manager_.IsMountPathInCache(mount_path_));
 
   EXPECT_EQ(MOUNT_ERROR_NONE, manager_.Unmount(mount_path_, options_));
@@ -746,8 +809,8 @@
 // Verifies that MountManager::Unmount() returns no error when it is invoked
 // to unmount the source path of a reserved mount path.
 TEST_F(MountManagerTest, UnmountSucceededWithGivenSourcePathInReservedCase) {
-  source_path_ = "source";
-  mount_path_ = "target";
+  source_path_ = kTestSourcePath;
+  mount_path_ = kTestMountPath;
 
   EXPECT_CALL(platform_, CreateOrReuseEmptyDirectory(mount_path_))
       .WillOnce(Return(true));
@@ -771,7 +834,7 @@
   EXPECT_EQ(MOUNT_ERROR_UNKNOWN_FILESYSTEM,
             manager_.Mount(source_path_, filesystem_type_, options_,
                            &mount_path_));
-  EXPECT_EQ("target", mount_path_);
+  EXPECT_EQ(kTestMountPath, mount_path_);
   EXPECT_TRUE(manager_.IsMountPathInCache(mount_path_));
   EXPECT_TRUE(manager_.IsMountPathReserved(mount_path_));
 
@@ -783,12 +846,8 @@
 // Verifies that MountManager::Unmount() returns no error when it is invoked
 // to unmount a reserved mount path.
 TEST_F(MountManagerTest, UnmountSucceededWithGivenMountPathInReservedCase) {
-  base::ScopedTempDir temp_dir;
-  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
-  string actual_mount_path = temp_dir.path().value();
-
-  source_path_ = "source";
-  mount_path_ = actual_mount_path;
+  source_path_ = kTestSourcePath;
+  mount_path_ = kTestMountPath;
 
   EXPECT_CALL(platform_, CreateOrReuseEmptyDirectory(mount_path_))
       .WillOnce(Return(true));
@@ -812,7 +871,7 @@
   EXPECT_EQ(MOUNT_ERROR_UNKNOWN_FILESYSTEM,
             manager_.Mount(source_path_, filesystem_type_, options_,
                            &mount_path_));
-  EXPECT_EQ(actual_mount_path, mount_path_);
+  EXPECT_EQ(kTestMountPath, mount_path_);
   EXPECT_TRUE(manager_.IsMountPathInCache(mount_path_));
   EXPECT_TRUE(manager_.IsMountPathReserved(mount_path_));
 
@@ -824,8 +883,8 @@
 // Verifies that MountManager::AddMountPathToCache() works as expected.
 TEST_F(MountManagerTest, AddMountPathToCache) {
   string result;
-  source_path_ = "source";
-  mount_path_ = "target";
+  source_path_ = kTestSourcePath;
+  mount_path_ = kTestMountPath;
 
   EXPECT_TRUE(manager_.AddMountPathToCache(source_path_, mount_path_));
   EXPECT_TRUE(manager_.GetMountPathFromCache(source_path_, &result));
@@ -841,8 +900,8 @@
 // Verifies that MountManager::GetSourcePathFromCache() works as expected.
 TEST_F(MountManagerTest, GetSourcePathFromCache) {
   string result;
-  source_path_ = "source";
-  mount_path_ = "target";
+  source_path_ = kTestSourcePath;
+  mount_path_ = kTestMountPath;
 
   EXPECT_FALSE(manager_.GetSourcePathFromCache(mount_path_, &result));
   EXPECT_TRUE(manager_.AddMountPathToCache(source_path_, mount_path_));
@@ -855,8 +914,8 @@
 // Verifies that MountManager::GetMountPathFromCache() works as expected.
 TEST_F(MountManagerTest, GetMountPathFromCache) {
   string result;
-  source_path_ = "source";
-  mount_path_ = "target";
+  source_path_ = kTestSourcePath;
+  mount_path_ = kTestMountPath;
 
   EXPECT_FALSE(manager_.GetMountPathFromCache(source_path_, &result));
   EXPECT_TRUE(manager_.AddMountPathToCache(source_path_, mount_path_));
@@ -868,8 +927,8 @@
 
 // Verifies that MountManager::IsMountPathInCache() works as expected.
 TEST_F(MountManagerTest, IsMountPathInCache) {
-  source_path_ = "source";
-  mount_path_ = "target";
+  source_path_ = kTestSourcePath;
+  mount_path_ = kTestMountPath;
 
   EXPECT_FALSE(manager_.IsMountPathInCache(mount_path_));
   EXPECT_TRUE(manager_.AddMountPathToCache(source_path_, mount_path_));
@@ -880,8 +939,8 @@
 
 // Verifies that MountManager::RemoveMountPathFromCache() works as expected.
 TEST_F(MountManagerTest, RemoveMountPathFromCache) {
-  source_path_ = "source";
-  mount_path_ = "target";
+  source_path_ = kTestSourcePath;
+  mount_path_ = kTestMountPath;
 
   EXPECT_FALSE(manager_.RemoveMountPathFromCache(mount_path_));
   EXPECT_TRUE(manager_.AddMountPathToCache(source_path_, mount_path_));
@@ -923,7 +982,7 @@
 // Verifies that MountManager::ReserveMountPath() and
 // MountManager::UnreserveMountPath() work as expected.
 TEST_F(MountManagerTest, ReserveAndUnreserveMountPath) {
-  mount_path_ = "target";
+  mount_path_ = kTestMountPath;
 
   EXPECT_FALSE(manager_.IsMountPathReserved(mount_path_));
   EXPECT_EQ(MOUNT_ERROR_NONE,
@@ -1061,4 +1120,24 @@
       "/media", "/media/removable"));
 }
 
+// Verifies that MountManager::IsValidMountPath() correctly determines if a
+// mount path is an immediate child of the mount root.
+TEST_F(MountManagerTest, IsValidMountPath) {
+  manager_.mount_root_ = "/media/removable";
+  EXPECT_TRUE(manager_.IsValidMountPath("/media/removable/test"));
+  EXPECT_TRUE(manager_.IsValidMountPath("/media/removable/test/"));
+  EXPECT_TRUE(manager_.IsValidMountPath("/media/removable/test/"));
+  EXPECT_TRUE(manager_.IsValidMountPath("/media/removable//test"));
+  EXPECT_FALSE(manager_.IsValidMountPath("/media/archive/test"));
+  EXPECT_FALSE(manager_.IsValidMountPath("/media/removable/test/doc"));
+  EXPECT_FALSE(manager_.IsValidMountPath("/media/removable/../test"));
+  EXPECT_FALSE(manager_.IsValidMountPath("/media/removable/../test/"));
+  EXPECT_FALSE(manager_.IsValidMountPath("/media/removable/test/.."));
+  EXPECT_FALSE(manager_.IsValidMountPath("/media/removable/test/../"));
+
+  manager_.mount_root_ = "/media/archive";
+  EXPECT_TRUE(manager_.IsValidMountPath("/media/archive/test"));
+  EXPECT_FALSE(manager_.IsValidMountPath("/media/removable/test"));
+}
+
 }  // namespace cros_disks
diff --git a/platform.cc b/platform.cc
index c0c0643..183037a 100644
--- a/platform.cc
+++ b/platform.cc
@@ -39,6 +39,19 @@
 Platform::~Platform() {
 }
 
+bool Platform::GetRealPath(const string& path, string* real_path) const {
+  CHECK(real_path) << "Invalid real_path argument";
+
+  scoped_ptr<char, base::FreeDeleter> result(realpath(path.c_str(), NULL));
+  if (!result) {
+    PLOG(ERROR) << "Failed to get real path of '" << path << "'";
+    return false;
+  }
+
+  *real_path = result.get();
+  return true;
+}
+
 bool Platform::CreateDirectory(const string& path) const {
   if (!base::CreateDirectory(FilePath(path))) {
     LOG(ERROR) << "Failed to create directory '" << path << "'";
diff --git a/platform.h b/platform.h
index ed224a7..0bfe180 100644
--- a/platform.h
+++ b/platform.h
@@ -22,6 +22,11 @@
   Platform();
   virtual ~Platform();
 
+  // Gets the canonicalized absolute path of |path| using realpath() and returns
+  // that via |real_path|. Return true on success.
+  virtual bool GetRealPath(const std::string& path,
+                           std::string* real_path) const;
+
   // Creates a directory at |path| if it does not exist. Returns true on
   // success.
   virtual bool CreateDirectory(const std::string& path) const;
diff --git a/platform_unittest.cc b/platform_unittest.cc
index e880667..cd754ea 100644
--- a/platform_unittest.cc
+++ b/platform_unittest.cc
@@ -41,6 +41,52 @@
   Platform platform_;
 };
 
+TEST_F(PlatformTest, GetRealPath) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  FilePath subdir_path;
+  ASSERT_TRUE(
+      base::CreateTemporaryDirInDir(temp_dir.path(), "test", &subdir_path));
+  FilePath file_path;
+  ASSERT_TRUE(base::CreateTemporaryFileInDir(subdir_path, &file_path));
+  FilePath file_symlink = temp_dir.path().Append("file_symlink");
+  ASSERT_TRUE(base::CreateSymbolicLink(file_path, file_symlink));
+  FilePath subdir_symlink = temp_dir.path().Append("subdir_symlink");
+  ASSERT_TRUE(base::CreateSymbolicLink(subdir_path, subdir_symlink));
+
+  string real_path;
+  EXPECT_FALSE(platform_.GetRealPath("", &real_path));
+  EXPECT_FALSE(platform_.GetRealPath("/nonexistent", &real_path));
+
+  EXPECT_TRUE(platform_.GetRealPath(temp_dir.path().value(), &real_path));
+  EXPECT_EQ(temp_dir.path().value(), real_path);
+
+  EXPECT_TRUE(platform_.GetRealPath(file_path.value(), &real_path));
+  EXPECT_EQ(file_path.value(), real_path);
+
+  EXPECT_TRUE(platform_.GetRealPath(file_symlink.value(), &real_path));
+  EXPECT_EQ(file_path.value(), real_path);
+
+  EXPECT_TRUE(platform_.GetRealPath(subdir_symlink.value(), &real_path));
+  EXPECT_EQ(subdir_path.value(), real_path);
+
+  FilePath relative_path = subdir_path.Append("..");
+  EXPECT_TRUE(platform_.GetRealPath(relative_path.value(), &real_path));
+  EXPECT_EQ(temp_dir.path().value(), real_path);
+
+  relative_path = subdir_path.Append("..")
+                      .Append(subdir_path.BaseName())
+                      .Append(file_path.BaseName());
+  EXPECT_TRUE(platform_.GetRealPath(relative_path.value(), &real_path));
+  EXPECT_EQ(file_path.value(), real_path);
+
+  relative_path = subdir_path.Append("..")
+                      .Append(subdir_symlink.BaseName())
+                      .Append(file_path.BaseName());
+  EXPECT_TRUE(platform_.GetRealPath(relative_path.value(), &real_path));
+  EXPECT_EQ(file_path.value(), real_path);
+}
+
 TEST_F(PlatformTest, CreateDirectory) {
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());