blob: bdb64c1a23637eeefcd897421563c46da41cbf6e [file] [log] [blame]
Sergei Datsenko1d2cbf82020-12-08 21:54:42 +11001// Copyright 2020 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/archive_mounter.h"
6
7#include <utility>
8
9#include <base/files/file_util.h>
10#include <base/files/scoped_temp_dir.h>
11#include <base/strings/string_util.h>
12#include <base/strings/string_split.h>
13#include <brillo/process/process_reaper.h>
14#include <gmock/gmock.h>
15#include <gtest/gtest.h>
16
17#include "cros-disks/mount_point.h"
18#include "cros-disks/platform.h"
19
20namespace cros_disks {
21
22namespace {
23
24using testing::_;
25using testing::ElementsAre;
26using testing::Return;
27using testing::UnorderedElementsAre;
28
29const char kArchiveType[] = "archive";
30const char kSomeSource[] = "/home/user/something.archive";
31const char kMountDir[] = "/mnt";
32const int kPasswordNeededCode = 42;
33
34// Mock Platform implementation for testing.
35class MockFUSEPlatform : public Platform {
36 public:
37 MOCK_METHOD(bool, PathExists, (const std::string&), (const, override));
38};
39
40class FakeSandboxedProcessFactory : public SandboxedProcessFactory {
41 public:
42 std::unique_ptr<SandboxedProcess> CreateSandboxedProcess() const override {
43 return std::make_unique<FakeSandboxedProcess>();
44 }
45};
46
47} // namespace
48
49class ArchiveMounterTest : public ::testing::Test {
50 public:
51 ArchiveMounterTest() {
52 ON_CALL(platform_, PathExists).WillByDefault(Return(true));
53 }
54
55 protected:
56 std::unique_ptr<ArchiveMounter> CreateMounter(
57 std::vector<int> password_needed_codes) {
58 return std::make_unique<ArchiveMounter>(
59 &platform_, &process_reaper_, kArchiveType, &metrics_, "ArchiveMetrics",
60 std::move(password_needed_codes),
61 std::make_unique<FakeSandboxedProcessFactory>());
62 }
63
64 MountErrorType InterpretReturnCode(const ArchiveMounter& mounter,
65 int exit_code) const {
66 return mounter.InterpretReturnCode(exit_code);
67 }
68
69 std::unique_ptr<FakeSandboxedProcess> PrepareSandbox(
70 const ArchiveMounter& mounter,
71 const std::string& source,
72 std::vector<std::string> params,
73 MountErrorType* error) const {
74 auto sandbox = mounter.PrepareSandbox(source, base::FilePath(kMountDir),
75 std::move(params), error);
76 return std::unique_ptr<FakeSandboxedProcess>(
77 static_cast<FakeSandboxedProcess*>(sandbox.release()));
78 }
79
80 MockFUSEPlatform platform_;
81 brillo::ProcessReaper process_reaper_;
82 Metrics metrics_;
83};
84
85TEST_F(ArchiveMounterTest, CanMount) {
86 auto mounter = CreateMounter({});
87 base::FilePath name;
88 EXPECT_TRUE(mounter->CanMount("/foo/bar/baz.archive", {}, &name));
89 EXPECT_EQ("baz.archive", name.value());
90 EXPECT_FALSE(mounter->CanMount("/foo/bar/baz.something", {}, &name));
Sergei Datsenkoc9904bb2020-12-11 12:46:02 +110091 EXPECT_FALSE(mounter->CanMount("baz.archive", {}, &name));
92 EXPECT_FALSE(mounter->CanMount(".archive", {}, &name));
93 EXPECT_FALSE(mounter->CanMount("", {}, &name));
Sergei Datsenko1d2cbf82020-12-08 21:54:42 +110094}
95
96TEST_F(ArchiveMounterTest, InvalidPathsRejected) {
97 auto mounter = CreateMounter({});
98 MountErrorType error = MOUNT_ERROR_UNKNOWN;
99 auto sandbox = PrepareSandbox(*mounter, "foo.archive", {}, &error);
100 EXPECT_NE(MOUNT_ERROR_NONE, error);
101 EXPECT_FALSE(sandbox);
102 sandbox = PrepareSandbox(*mounter, "/foo/../etc/foo.archive", {}, &error);
103 EXPECT_NE(MOUNT_ERROR_NONE, error);
104 EXPECT_FALSE(sandbox);
105}
106
107TEST_F(ArchiveMounterTest, AppArgs) {
108 auto mounter = CreateMounter({});
109 MountErrorType error = MOUNT_ERROR_UNKNOWN;
110 auto sandbox = PrepareSandbox(*mounter, kSomeSource, {}, &error);
111 EXPECT_EQ(MOUNT_ERROR_NONE, error);
112 ASSERT_TRUE(sandbox);
113 EXPECT_THAT(sandbox->arguments(), ElementsAre("-o", _, kSomeSource));
114 std::vector<std::string> opts =
115 base::SplitString(sandbox->arguments()[1], ",", base::KEEP_WHITESPACE,
116 base::SPLIT_WANT_ALL);
117 EXPECT_THAT(opts,
118 UnorderedElementsAre("umask=0222", "uid=1000", "gid=1001", "ro"));
119}
120
121TEST_F(ArchiveMounterTest, FileNotFound) {
122 EXPECT_CALL(platform_, PathExists(kSomeSource)).WillRepeatedly(Return(false));
123 auto mounter = CreateMounter({});
124 MountErrorType error = MOUNT_ERROR_UNKNOWN;
125 auto sandbox = PrepareSandbox(*mounter, kSomeSource, {}, &error);
126 EXPECT_NE(MOUNT_ERROR_NONE, error);
127 EXPECT_FALSE(sandbox);
128}
129
130TEST_F(ArchiveMounterTest, AppNeedsPassword) {
131 auto mounter = CreateMounter({kPasswordNeededCode});
132 EXPECT_EQ(MOUNT_ERROR_NEED_PASSWORD,
133 InterpretReturnCode(*mounter, kPasswordNeededCode));
134}
135
136TEST_F(ArchiveMounterTest, WithPassword) {
137 const std::string password = "My Password";
138
139 auto mounter = CreateMounter({kPasswordNeededCode});
140 MountErrorType error = MOUNT_ERROR_UNKNOWN;
141 auto sandbox =
142 PrepareSandbox(*mounter, kSomeSource, {"password=" + password}, &error);
143 EXPECT_EQ(MOUNT_ERROR_NONE, error);
144 ASSERT_TRUE(sandbox);
145 EXPECT_EQ(password, sandbox->input());
146 // Make sure password is not in args.
147 std::vector<std::string> opts =
148 base::SplitString(sandbox->arguments()[1], ",", base::KEEP_WHITESPACE,
149 base::SPLIT_WANT_ALL);
150 EXPECT_THAT(opts,
151 UnorderedElementsAre("umask=0222", "uid=1000", "gid=1001", "ro"));
152}
153
154TEST_F(ArchiveMounterTest, NoPassword) {
155 auto mounter = CreateMounter({kPasswordNeededCode});
156 MountErrorType error = MOUNT_ERROR_UNKNOWN;
157 auto sandbox = PrepareSandbox(*mounter, kSomeSource,
158 {
159 "Password=1", // Options are case sensitive
160 "password =2", // Space is significant
161 " password=3", // Space is significant
162 "password", // Not a valid option
163 },
164 &error);
165 ASSERT_TRUE(sandbox);
166 EXPECT_EQ("", sandbox->input());
167}
168
169TEST_F(ArchiveMounterTest, CopiesPassword) {
170 for (const std::string password : {
171 "",
172 " ",
173 "=",
174 "simple",
175 R"( !@#$%^&*()_-+={[}]|\:;"'<,>.?/ )",
176 }) {
177 auto mounter = CreateMounter({kPasswordNeededCode});
178 MountErrorType error = MOUNT_ERROR_UNKNOWN;
179 auto sandbox =
180 PrepareSandbox(*mounter, kSomeSource, {"password=" + password}, &error);
181 ASSERT_TRUE(sandbox);
182 EXPECT_EQ(password, sandbox->input());
183 }
184}
185
186TEST_F(ArchiveMounterTest, IgnoredIfNotNeeded) {
187 auto mounter = CreateMounter({});
188 MountErrorType error = MOUNT_ERROR_UNKNOWN;
189 auto sandbox =
190 PrepareSandbox(*mounter, kSomeSource, {"password=foo"}, &error);
191 EXPECT_EQ(MOUNT_ERROR_NONE, error);
192 ASSERT_TRUE(sandbox);
193 EXPECT_EQ("", sandbox->input());
194}
195
196} // namespace cros_disks