blob: 43c164237f521c5f24f7fd169d724c2a1ccec440 [file] [log] [blame]
Sam McNallyc56ae312018-05-22 13:14:27 +10001// Copyright 2018 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "cros-disks/drivefs_helper.h"
6
7#include <sys/mount.h>
8
Qijiang Fan713061e2021-03-08 15:45:12 +09009#include <base/check_op.h>
Sam McNallyf6b4ef82019-06-12 14:22:08 +100010#include <base/files/file_util.h>
11#include <base/files/scoped_temp_dir.h>
Qijiang Fan886c4692021-02-19 11:54:10 +090012#include <base/notreached.h>
Sergei Datsenkof5553d12020-11-25 07:51:59 +110013#include <base/strings/string_split.h>
Sam McNallyc56ae312018-05-22 13:14:27 +100014#include <base/strings/string_util.h>
Simon Glass2b1da092020-05-21 12:24:16 -060015#include <brillo/process/process_reaper.h>
Sam McNallyc56ae312018-05-22 13:14:27 +100016#include <gmock/gmock.h>
17#include <gtest/gtest.h>
18
19#include "cros-disks/fuse_mounter.h"
20#include "cros-disks/mount_options.h"
21#include "cros-disks/platform.h"
22#include "cros-disks/uri.h"
Sergei Datsenkof5553d12020-11-25 07:51:59 +110023#include "cros-disks/user.h"
Sam McNallyc56ae312018-05-22 13:14:27 +100024
25namespace cros_disks {
26namespace {
27
28using testing::_;
29using testing::DoAll;
Sergei Datsenko562d4f02018-06-28 15:42:09 +100030using testing::EndsWith;
Sam McNallyc56ae312018-05-22 13:14:27 +100031using testing::HasSubstr;
32using testing::Invoke;
Sergei Datsenkof5553d12020-11-25 07:51:59 +110033using testing::IsSupersetOf;
Sam McNallyc56ae312018-05-22 13:14:27 +100034using testing::Return;
Sergei Datsenkof5553d12020-11-25 07:51:59 +110035using testing::SaveArg;
Sam McNallyc56ae312018-05-22 13:14:27 +100036using testing::SetArgPointee;
Sergei Datsenkof5553d12020-11-25 07:51:59 +110037using testing::StrEq;
38using testing::UnorderedElementsAre;
Sam McNallyc56ae312018-05-22 13:14:27 +100039
Sergei Datsenkof5553d12020-11-25 07:51:59 +110040constexpr char kSource[] = "drivefs://id";
41constexpr char kDataDir[] = "/home/chronos/user/GCache/foo";
42constexpr char kMountPath[] = "/media/fuse/drivefs/id";
Sam McNallyc56ae312018-05-22 13:14:27 +100043
Sergei Datsenkof5553d12020-11-25 07:51:59 +110044constexpr char kPrefixParam[] = "prefix=/media/fuse/drivefs/id";
45constexpr char kDataDirParam[] = "datadir=/home/chronos/user/GCache/foo";
46constexpr char kMyFilesParam[] = "myfiles=/home/chronos/user/MyFiles";
47
48std::vector<std::string> ParseOptions(const SandboxedProcess& sandbox) {
49 CHECK_EQ(2, sandbox.arguments().size());
50 CHECK_EQ("-o", sandbox.arguments()[0]);
51 return base::SplitString(sandbox.arguments()[1], ",",
52 base::WhitespaceHandling::KEEP_WHITESPACE,
53 base::SplitResult::SPLIT_WANT_ALL);
54}
Sam McNallydd0ff982019-06-12 18:18:36 +100055
Sam McNallyc56ae312018-05-22 13:14:27 +100056// Mock Platform implementation for testing.
57class MockPlatform : public Platform {
58 public:
59 MockPlatform() {
Sam McNallyc56ae312018-05-22 13:14:27 +100060 ON_CALL(*this, GetRealPath(_, _))
61 .WillByDefault(Invoke(this, &MockPlatform::GetRealPathImpl));
Sam McNally0b2361b2018-05-25 10:17:19 +100062 ON_CALL(*this, DirectoryExists(_)).WillByDefault(Return(true));
Sergei Datsenkof5553d12020-11-25 07:51:59 +110063 ON_CALL(*this, GetOwnership(_, _, _))
64 .WillByDefault(DoAll(SetArgPointee<1>(kChronosUID), Return(true)));
Sam McNallyc56ae312018-05-22 13:14:27 +100065 }
66
Ben Chanef8e6032019-09-27 08:24:56 -070067 MOCK_METHOD(bool,
68 GetRealPath,
69 (const std::string&, std::string*),
70 (const, override));
Ben Chanef8e6032019-09-27 08:24:56 -070071 MOCK_METHOD(bool, PathExists, (const std::string&), (const, override));
72 MOCK_METHOD(bool, DirectoryExists, (const std::string&), (const, override));
Ben Chanef8e6032019-09-27 08:24:56 -070073 MOCK_METHOD(bool, CreateDirectory, (const std::string&), (const, override));
74 MOCK_METHOD(bool,
75 RemoveEmptyDirectory,
76 (const std::string&),
77 (const, override));
78 MOCK_METHOD(bool,
Ben Chanef8e6032019-09-27 08:24:56 -070079 GetOwnership,
80 (const std::string&, uid_t*, gid_t*),
81 (const, override));
82 MOCK_METHOD(bool,
83 SetPermissions,
84 (const std::string&, mode_t),
85 (const, override));
Sam McNallyc56ae312018-05-22 13:14:27 +100086
Sam McNallyc56ae312018-05-22 13:14:27 +100087 bool GetRealPathImpl(const std::string& path, std::string* real_path) const {
Sergei Datsenkof5553d12020-11-25 07:51:59 +110088 std::vector<std::string> components;
89 base::FilePath(path).GetComponents(&components);
90 base::FilePath result(components[0]);
91 components.erase(components.begin());
92 for (const auto& part : components) {
93 if (part != ".")
94 result = result.Append(part);
Sam McNallydd0ff982019-06-12 18:18:36 +100095 }
Sergei Datsenkof5553d12020-11-25 07:51:59 +110096 *real_path = result.value();
Sam McNallyc56ae312018-05-22 13:14:27 +100097 return true;
98 }
99
Sergei Datsenkof5553d12020-11-25 07:51:59 +1100100 bool GetUserAndGroupId(const std::string& user,
101 uid_t* user_id,
102 gid_t* group_id) const override {
103 NOTREACHED();
Sam McNallyc56ae312018-05-22 13:14:27 +1000104 return false;
105 }
106
Sergei Datsenkof5553d12020-11-25 07:51:59 +1100107 bool GetGroupId(const std::string& group, gid_t* group_id) const override {
108 NOTREACHED();
Sam McNallyc56ae312018-05-22 13:14:27 +1000109 return false;
110 }
Sam McNallyf6b4ef82019-06-12 14:22:08 +1000111
Sergei Datsenkof5553d12020-11-25 07:51:59 +1100112 bool SetOwnership(const std::string&, uid_t, gid_t) const override {
113 NOTREACHED();
114 return false;
115 }
Sam McNallyc56ae312018-05-22 13:14:27 +1000116};
117
118class TestDrivefsHelper : public DrivefsHelper {
119 public:
Sergei Datsenkoa910bba2019-06-18 13:31:59 +1000120 TestDrivefsHelper(const Platform* platform,
121 brillo::ProcessReaper* process_reaper)
122 : DrivefsHelper(platform, process_reaper) {
Sam McNallyc56ae312018-05-22 13:14:27 +1000123 }
Sergei Datsenkof5553d12020-11-25 07:51:59 +1100124 using DrivefsHelper::ConfigureSandbox;
Sam McNallyc56ae312018-05-22 13:14:27 +1000125};
126
127class DrivefsHelperTest : public ::testing::Test {
128 public:
Sergei Datsenkoa910bba2019-06-18 13:31:59 +1000129 DrivefsHelperTest() : helper_(&platform_, &process_reaper_) {}
Sam McNallyc56ae312018-05-22 13:14:27 +1000130
131 protected:
Sam McNallyc56ae312018-05-22 13:14:27 +1000132 MockPlatform platform_;
Sergei Datsenkoa910bba2019-06-18 13:31:59 +1000133 brillo::ProcessReaper process_reaper_;
Sam McNallyc56ae312018-05-22 13:14:27 +1000134 TestDrivefsHelper helper_;
135};
136
Sergei Datsenkof5553d12020-11-25 07:51:59 +1100137TEST_F(DrivefsHelperTest, ConfigureSandbox) {
138 FakeSandboxedProcess sandbox;
139 auto error = helper_.ConfigureSandbox(
140 kSource, base::FilePath(kMountPath),
141 {"datadir=/home/chronos//user/GCache//foo/./"}, &sandbox);
Sam McNallyc56ae312018-05-22 13:14:27 +1000142
Sergei Datsenkof5553d12020-11-25 07:51:59 +1100143 EXPECT_EQ(MOUNT_ERROR_NONE, error);
144 auto options = ParseOptions(sandbox);
145 EXPECT_THAT(options,
146 UnorderedElementsAre(kDataDirParam, "identity=id", "uid=1000",
147 "gid=1001", kPrefixParam));
Sam McNallyc56ae312018-05-22 13:14:27 +1000148}
149
Sergei Datsenkof5553d12020-11-25 07:51:59 +1100150TEST_F(DrivefsHelperTest, ConfigureSandboxWithMyFiles) {
151 FakeSandboxedProcess sandbox;
152 auto error = helper_.ConfigureSandbox(
153 kSource, base::FilePath(kMountPath),
154 {kDataDirParam, "myfiles=/home/chronos//user/.//MyFiles"}, &sandbox);
Sam McNallydd0ff982019-06-12 18:18:36 +1000155
Sergei Datsenkof5553d12020-11-25 07:51:59 +1100156 EXPECT_EQ(MOUNT_ERROR_NONE, error);
157 auto options = ParseOptions(sandbox);
158 EXPECT_THAT(options, IsSupersetOf({StrEq(kMyFilesParam)}));
Sam McNallydd0ff982019-06-12 18:18:36 +1000159}
160
Sergei Datsenkof5553d12020-11-25 07:51:59 +1100161TEST_F(DrivefsHelperTest, ConfigureSandboxFailsIfInvalidSource) {
162 FakeSandboxedProcess sandbox;
163 auto error = helper_.ConfigureSandbox(
164 "drive://id", base::FilePath(kMountPath), {kDataDirParam}, &sandbox);
165 EXPECT_NE(MOUNT_ERROR_NONE, error);
Sam McNally0b2361b2018-05-25 10:17:19 +1000166
Sergei Datsenkof5553d12020-11-25 07:51:59 +1100167 error = helper_.ConfigureSandbox("/dev/block", base::FilePath(kMountPath),
168 {kDataDirParam}, &sandbox);
169 EXPECT_NE(MOUNT_ERROR_NONE, error);
Sam McNally0b2361b2018-05-25 10:17:19 +1000170
Sergei Datsenkof5553d12020-11-25 07:51:59 +1100171 error = helper_.ConfigureSandbox("drivefs:/foo", base::FilePath(kMountPath),
172 {kDataDirParam}, &sandbox);
173 EXPECT_NE(MOUNT_ERROR_NONE, error);
Sam McNally0b2361b2018-05-25 10:17:19 +1000174}
175
Sergei Datsenkof5553d12020-11-25 07:51:59 +1100176TEST_F(DrivefsHelperTest, ConfigureSandboxFailsIfDataDirInvalid) {
177 FakeSandboxedProcess sandbox;
178 auto error = helper_.ConfigureSandbox(kSource, base::FilePath(kMountPath), {},
179 &sandbox);
180 EXPECT_NE(MOUNT_ERROR_NONE, error);
Sam McNallyc56ae312018-05-22 13:14:27 +1000181
Sergei Datsenkof5553d12020-11-25 07:51:59 +1100182 error = helper_.ConfigureSandbox(kSource, base::FilePath(kMountPath),
183 {"datadir=dodgy/path"}, &sandbox);
184 EXPECT_NE(MOUNT_ERROR_NONE, error);
185
186 error = helper_.ConfigureSandbox(kSource, base::FilePath(kMountPath),
187 {"datadir=/nonhome/dir"}, &sandbox);
188 EXPECT_NE(MOUNT_ERROR_NONE, error);
189
190 error = helper_.ConfigureSandbox(kSource, base::FilePath(kMountPath),
191 {"datadir=/home/chronos/../../etc/passwd"},
192 &sandbox);
193 EXPECT_NE(MOUNT_ERROR_NONE, error);
Sam McNallyc56ae312018-05-22 13:14:27 +1000194}
195
Sergei Datsenkof5553d12020-11-25 07:51:59 +1100196TEST_F(DrivefsHelperTest, ConfigureSandboxFailsIfDataDirDoesntExist) {
197 EXPECT_CALL(platform_, DirectoryExists(kDataDir)).WillOnce(Return(false));
198 FakeSandboxedProcess sandbox;
199 auto error = helper_.ConfigureSandbox(kSource, base::FilePath(kMountPath),
200 {kDataDirParam}, &sandbox);
201 EXPECT_NE(MOUNT_ERROR_NONE, error);
Sam McNallyc56ae312018-05-22 13:14:27 +1000202}
203
Sergei Datsenkof5553d12020-11-25 07:51:59 +1100204TEST_F(DrivefsHelperTest, ConfigureSandboxFailsWhenCantStat) {
205 EXPECT_CALL(platform_, GetOwnership(kDataDir, _, _)).WillOnce(Return(false));
206 FakeSandboxedProcess sandbox;
207 auto error = helper_.ConfigureSandbox(kSource, base::FilePath(kMountPath),
208 {kDataDirParam}, &sandbox);
209 EXPECT_NE(MOUNT_ERROR_NONE, error);
Sam McNally0b2361b2018-05-25 10:17:19 +1000210}
211
Sergei Datsenkof5553d12020-11-25 07:51:59 +1100212TEST_F(DrivefsHelperTest, ConfigureSandboxFailsWhenWrongOwner) {
213 EXPECT_CALL(platform_, GetOwnership(kDataDir, _, _))
214 .WillOnce(DoAll(SetArgPointee<1>(kChronosUID + 100), Return(false)));
215 FakeSandboxedProcess sandbox;
216 auto error = helper_.ConfigureSandbox(kSource, base::FilePath(kMountPath),
217 {kDataDirParam}, &sandbox);
218 EXPECT_NE(MOUNT_ERROR_NONE, error);
Sam McNallydd0ff982019-06-12 18:18:36 +1000219}
220
Sam McNallyc56ae312018-05-22 13:14:27 +1000221} // namespace
222} // namespace cros_disks