Refactor code related to non-privileged mounts.
This CL modifies the code to obtain the user and group ID of the user
for non-privileged mounts when the daemon starts and keep that
information in the Platform object such that other objects can simply
obtain the information when needed.
BUG=none
TEST=Ran unit tests and tested mounting/unmounting on Cr48.
Change-Id: Ib299191ff45da260d1a6de617e052131aa9e906a
Reviewed-on: http://gerrit.chromium.org/gerrit/5229
Reviewed-by: Darin Petkov <petkov@chromium.org>
Tested-by: Ben Chan <benchan@chromium.org>
diff --git a/archive-manager.cc b/archive-manager.cc
index 59afe78..77a30e2 100644
--- a/archive-manager.cc
+++ b/archive-manager.cc
@@ -30,7 +30,6 @@
// in the path: '/', 'media', '<sub type>', '<mount dir>'
static size_t kNumComponentsInMountDirectoryPath = 4;
static const char kAVFSMountProgram[] = "/usr/bin/avfsd";
-static const char kAVFSMountUser[] = "chronos";
static const char kAVFSRootDirectory[] = "/var/run/avfsroot";
static const char kAVFSMediaDirectory[] = "/var/run/avfsroot/media";
static const char kAVFSUserFileDirectory[] = "/var/run/avfsroot/user";
@@ -52,10 +51,8 @@
}
bool ArchiveManager::StartSession(const string& user) {
- uid_t user_id;
- gid_t group_id;
- if (!platform_->GetUserAndGroupId(kAVFSMountUser, &user_id, &group_id))
- return false;
+ uid_t user_id = platform_->mount_user_id();
+ gid_t group_id = platform_->mount_group_id();
if (!platform_->CreateDirectory(kAVFSRootDirectory) ||
!platform_->SetOwnership(kAVFSRootDirectory, user_id, group_id) ||
@@ -191,12 +188,13 @@
}
chromeos::ProcessImpl mount_process;
- mount_process.AddArg("/bin/su");
- mount_process.AddArg(kAVFSMountUser);
- mount_process.AddArg("-c");
- mount_process.AddArg(string(kAVFSMountProgram) +
- " -o ro,nodev,noexec,nosuid,modules=subdir,subdir=" +
- base_path + " " + avfs_path);
+ mount_process.AddArg(kAVFSMountProgram);
+ mount_process.AddArg("-o");
+ mount_process.AddArg("ro,nodev,noexec,nosuid,modules=subdir,subdir=" +
+ base_path);
+ mount_process.AddArg(avfs_path);
+ mount_process.SetUid(platform_->mount_user_id());
+ mount_process.SetGid(platform_->mount_group_id());
if (mount_process.Run() != 0 ||
!mount_info.RetrieveFromCurrentProcess() ||
!mount_info.HasMountPath(avfs_path)) {
diff --git a/disk-manager.cc b/disk-manager.cc
index 9635d5c..6a1f36c 100644
--- a/disk-manager.cc
+++ b/disk-manager.cc
@@ -27,9 +27,6 @@
namespace cros_disks {
-// TODO(benchan): Infer the current user/group from session manager
-// instead of hardcoding as chronos
-static const char kMountDefaultUser[] = "chronos";
static const char kBlockSubsystem[] = "block";
static const char kScsiSubsystem[] = "scsi";
static const char kScsiDevice[] = "scsi_device";
@@ -337,12 +334,8 @@
string default_user_id, default_group_id;
bool set_user_and_group_id = filesystem.accepts_user_and_group_id();
if (set_user_and_group_id) {
- uid_t uid;
- gid_t gid;
- if (platform_->GetUserAndGroupId(kMountDefaultUser, &uid, &gid)) {
- default_user_id = base::StringPrintf("%d", uid);
- default_group_id = base::StringPrintf("%d", gid);
- }
+ default_user_id = base::StringPrintf("%d", platform_->mount_user_id());
+ default_group_id = base::StringPrintf("%d", platform_->mount_group_id());
}
MountOptions mount_options;
diff --git a/disk-manager.h b/disk-manager.h
index fe7a08f..a846d53 100644
--- a/disk-manager.h
+++ b/disk-manager.h
@@ -7,7 +7,6 @@
#include <blkid/blkid.h>
#include <libudev.h>
-#include <sys/types.h>
#include <map>
#include <set>
diff --git a/disk-manager_unittest.cc b/disk-manager_unittest.cc
index 1fa0d4f..e140f97 100644
--- a/disk-manager_unittest.cc
+++ b/disk-manager_unittest.cc
@@ -5,7 +5,6 @@
#include "cros-disks/disk-manager.h"
#include <sys/mount.h>
-#include <sys/types.h>
#include <base/memory/scoped_temp_dir.h>
#include <gtest/gtest.h>
diff --git a/main.cc b/main.cc
index 60f4315..b8335c6 100644
--- a/main.cc
+++ b/main.cc
@@ -44,6 +44,7 @@
static const char kUsageMessage[] = "Chromium OS Disk Daemon";
static const char kArchiveMountRootDirectory[] = "/media/archive";
static const char kDiskMountRootDirectory[] = "/media/removable";
+static const char kNonPrivilegedMountUser[] = "chronos";
// Always logs to the syslog and logs to stderr if
// we are running in the foreground.
@@ -97,10 +98,12 @@
server_conn.request_name("org.chromium.CrosDisks");
Platform platform;
+ CHECK(platform.SetMountUser(kNonPrivilegedMountUser))
+ << "'" << kNonPrivilegedMountUser
+ << "' is not available for non-privileged mount operations.";
LOG(INFO) << "Creating the archive manager";
- ArchiveManager archive_manager(kArchiveMountRootDirectory,
- &platform);
+ ArchiveManager archive_manager(kArchiveMountRootDirectory, &platform);
CHECK(archive_manager.Initialize())
<< "Failed to initialize the archive manager";
diff --git a/mount-manager.cc b/mount-manager.cc
index 79dd5c9..978d7da 100644
--- a/mount-manager.cc
+++ b/mount-manager.cc
@@ -102,9 +102,8 @@
return kMountErrorDirectoryCreationFailed;
}
- gid_t group_id;
- if (!platform_->GetGroupId(kMountDirectoryGroup, &group_id) ||
- !platform_->SetOwnership(actual_mount_path, getuid(), group_id) ||
+ if (!platform_->SetOwnership(actual_mount_path, getuid(),
+ platform_->mount_group_id()) ||
!platform_->SetPermissions(actual_mount_path,
kMountDirectoryPermissions)) {
LOG(ERROR) << "Failed to set ownership and permissions of directory '"
diff --git a/mount-manager_unittest.cc b/mount-manager_unittest.cc
index 6381fcc..b8cd502 100644
--- a/mount-manager_unittest.cc
+++ b/mount-manager_unittest.cc
@@ -35,8 +35,6 @@
MOCK_CONST_METHOD1(CreateOrReuseEmptyDirectory, bool(const string& path));
MOCK_CONST_METHOD2(CreateOrReuseEmptyDirectoryWithFallback,
bool(string* path, unsigned max_suffix_to_retry));
- MOCK_CONST_METHOD2(GetGroupId,
- bool(const string& group_name, gid_t* group_id));
MOCK_CONST_METHOD1(RemoveEmptyDirectory, bool(const string& path));
MOCK_CONST_METHOD3(SetOwnership, bool(const string& path,
uid_t user_id, gid_t group_id));
@@ -201,7 +199,6 @@
.WillOnce(Return(true));
EXPECT_CALL(platform_, CreateOrReuseEmptyDirectoryWithFallback(_, _))
.Times(0);
- EXPECT_CALL(platform_, GetGroupId(_, _)).WillOnce(Return(true));
EXPECT_CALL(platform_, SetOwnership(mount_path_, _, _))
.WillOnce(Return(false));
EXPECT_CALL(platform_, SetPermissions(_, _)).Times(0);
@@ -226,7 +223,6 @@
.WillOnce(Return(true));
EXPECT_CALL(platform_, CreateOrReuseEmptyDirectoryWithFallback(_, _))
.Times(0);
- EXPECT_CALL(platform_, GetGroupId(_, _)).WillOnce(Return(true));
EXPECT_CALL(platform_, SetOwnership(mount_path_, _, _))
.WillOnce(Return(true));
EXPECT_CALL(platform_, SetPermissions(mount_path_, _))
@@ -252,7 +248,6 @@
.WillOnce(Return(true));
EXPECT_CALL(platform_, CreateOrReuseEmptyDirectoryWithFallback(_, _))
.Times(0);
- EXPECT_CALL(platform_, GetGroupId(_, _)).WillOnce(Return(true));
EXPECT_CALL(platform_, SetOwnership(mount_path_, _, _))
.WillOnce(Return(true));
EXPECT_CALL(platform_, SetPermissions(mount_path_, _))
@@ -281,7 +276,6 @@
EXPECT_CALL(platform_, CreateOrReuseEmptyDirectory(_)).Times(0);
EXPECT_CALL(platform_, CreateOrReuseEmptyDirectoryWithFallback(_, _))
.WillOnce(Return(true));
- EXPECT_CALL(platform_, GetGroupId(_, _)).WillOnce(Return(true));
EXPECT_CALL(platform_, SetOwnership(suggested_mount_path, _, _))
.WillOnce(Return(true));
EXPECT_CALL(platform_, SetPermissions(suggested_mount_path, _))
@@ -311,7 +305,6 @@
EXPECT_CALL(platform_, CreateOrReuseEmptyDirectory(_)).Times(0);
EXPECT_CALL(platform_, CreateOrReuseEmptyDirectoryWithFallback(_, _))
.WillOnce(Return(true));
- EXPECT_CALL(platform_, GetGroupId(_, _)).WillOnce(Return(true));
EXPECT_CALL(platform_, SetOwnership(suggested_mount_path, _, _))
.WillOnce(Return(true));
EXPECT_CALL(platform_, SetPermissions(suggested_mount_path, _))
@@ -395,7 +388,6 @@
.WillOnce(Return(true));
EXPECT_CALL(platform_, CreateOrReuseEmptyDirectoryWithFallback(_, _))
.Times(0);
- EXPECT_CALL(platform_, GetGroupId(_, _)).WillOnce(Return(true));
EXPECT_CALL(platform_, SetOwnership(mount_path_, _, _))
.WillOnce(Return(true));
EXPECT_CALL(platform_, SetPermissions(mount_path_, _))
@@ -431,7 +423,6 @@
.WillOnce(Return(true));
EXPECT_CALL(platform_, CreateOrReuseEmptyDirectoryWithFallback(_, _))
.Times(0);
- EXPECT_CALL(platform_, GetGroupId(_, _)).WillOnce(Return(true));
EXPECT_CALL(platform_, SetOwnership(mount_path_, _, _))
.WillOnce(Return(true));
EXPECT_CALL(platform_, SetPermissions(mount_path_, _))
diff --git a/platform.cc b/platform.cc
index b4fd9c7..924d227 100644
--- a/platform.cc
+++ b/platform.cc
@@ -23,7 +23,9 @@
static const unsigned kFallbackPasswordBufferSize = 16384;
Platform::Platform()
- : experimental_features_enabled_(false) {
+ : experimental_features_enabled_(false),
+ mount_group_id_(0),
+ mount_user_id_(0) {
}
Platform::~Platform() {
@@ -114,6 +116,10 @@
return true;
}
+bool Platform::SetMountUser(const std::string& user_name) {
+ return GetUserAndGroupId(user_name, &mount_user_id_, &mount_group_id_);
+}
+
bool Platform::RemoveEmptyDirectory(const string& path) const {
if (rmdir(path.c_str()) != 0) {
PLOG(WARNING) << "Failed to remove directory '" << path << "'";
diff --git a/platform.h b/platform.h
index ea193d6..3ac212f 100644
--- a/platform.h
+++ b/platform.h
@@ -6,6 +6,7 @@
#define CROS_DISKS_PLATFORM_H_
#include <sys/stat.h>
+#include <sys/types.h>
#include <string>
@@ -50,6 +51,13 @@
// Returns true on success.
virtual bool RemoveEmptyDirectory(const std::string& path) const;
+ // Makes |user_name| to perform mount operations, which changes the value of
+ // mount_group_id_ and mount_user_id_. When |user_name| is a non-root user, a
+ // mount operation repsecting the value of mount_group_id_ and mount_user_id_
+ // becomes non-privileged. Returns false if it fails to obtain the user and
+ // group ID of |user_name|.
+ bool SetMountUser(const std::string& user_name);
+
// Sets the user ID and group ID of |path| to |user_id| and |group_id|,
// respectively. Returns true on success.
virtual bool SetOwnership(const std::string& path,
@@ -68,10 +76,20 @@
experimental_features_enabled_ = experimental_features_enabled;
}
+ gid_t mount_group_id() const { return mount_group_id_; }
+
+ uid_t mount_user_id() const { return mount_user_id_; }
+
private:
// This variable is set to true if the experimental features are enabled.
bool experimental_features_enabled_;
+ // Group ID to perform mount operations.
+ gid_t mount_group_id_;
+
+ // User ID to perform mount operations.
+ uid_t mount_user_id_;
+
DISALLOW_COPY_AND_ASSIGN(Platform);
};
diff --git a/platform_unittest.cc b/platform_unittest.cc
index 9825a55..5006b19 100644
--- a/platform_unittest.cc
+++ b/platform_unittest.cc
@@ -154,6 +154,20 @@
EXPECT_FALSE(platform_.RemoveEmptyDirectory(path));
}
+TEST_F(PlatformTest, SetMountUserToRoot) {
+ EXPECT_TRUE(platform_.SetMountUser("root"));
+ EXPECT_EQ(0, platform_.mount_user_id());
+ EXPECT_EQ(0, platform_.mount_group_id());
+}
+
+TEST_F(PlatformTest, SetMountUserToNonexistentUser) {
+ uid_t user_id = platform_.mount_user_id();
+ gid_t group_id = platform_.mount_group_id();
+ EXPECT_FALSE(platform_.SetMountUser("nonexistent-user"));
+ EXPECT_EQ(user_id, platform_.mount_user_id());
+ EXPECT_EQ(group_id, platform_.mount_group_id());
+}
+
TEST_F(PlatformTest, SetOwnershipOfNonExistentPath) {
EXPECT_FALSE(platform_.SetOwnership("/nonexistent-path", getuid(), getgid()));
}