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());