blob: c9e1cfcbb02fb6a5995b420fb90c9a0eb4a16855 [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));
91}
92
93TEST_F(ArchiveMounterTest, InvalidPathsRejected) {
94 auto mounter = CreateMounter({});
95 MountErrorType error = MOUNT_ERROR_UNKNOWN;
96 auto sandbox = PrepareSandbox(*mounter, "foo.archive", {}, &error);
97 EXPECT_NE(MOUNT_ERROR_NONE, error);
98 EXPECT_FALSE(sandbox);
99 sandbox = PrepareSandbox(*mounter, "/foo/../etc/foo.archive", {}, &error);
100 EXPECT_NE(MOUNT_ERROR_NONE, error);
101 EXPECT_FALSE(sandbox);
102}
103
104TEST_F(ArchiveMounterTest, AppArgs) {
105 auto mounter = CreateMounter({});
106 MountErrorType error = MOUNT_ERROR_UNKNOWN;
107 auto sandbox = PrepareSandbox(*mounter, kSomeSource, {}, &error);
108 EXPECT_EQ(MOUNT_ERROR_NONE, error);
109 ASSERT_TRUE(sandbox);
110 EXPECT_THAT(sandbox->arguments(), ElementsAre("-o", _, kSomeSource));
111 std::vector<std::string> opts =
112 base::SplitString(sandbox->arguments()[1], ",", base::KEEP_WHITESPACE,
113 base::SPLIT_WANT_ALL);
114 EXPECT_THAT(opts,
115 UnorderedElementsAre("umask=0222", "uid=1000", "gid=1001", "ro"));
116}
117
118TEST_F(ArchiveMounterTest, FileNotFound) {
119 EXPECT_CALL(platform_, PathExists(kSomeSource)).WillRepeatedly(Return(false));
120 auto mounter = CreateMounter({});
121 MountErrorType error = MOUNT_ERROR_UNKNOWN;
122 auto sandbox = PrepareSandbox(*mounter, kSomeSource, {}, &error);
123 EXPECT_NE(MOUNT_ERROR_NONE, error);
124 EXPECT_FALSE(sandbox);
125}
126
127TEST_F(ArchiveMounterTest, AppNeedsPassword) {
128 auto mounter = CreateMounter({kPasswordNeededCode});
129 EXPECT_EQ(MOUNT_ERROR_NEED_PASSWORD,
130 InterpretReturnCode(*mounter, kPasswordNeededCode));
131}
132
133TEST_F(ArchiveMounterTest, WithPassword) {
134 const std::string password = "My Password";
135
136 auto mounter = CreateMounter({kPasswordNeededCode});
137 MountErrorType error = MOUNT_ERROR_UNKNOWN;
138 auto sandbox =
139 PrepareSandbox(*mounter, kSomeSource, {"password=" + password}, &error);
140 EXPECT_EQ(MOUNT_ERROR_NONE, error);
141 ASSERT_TRUE(sandbox);
142 EXPECT_EQ(password, sandbox->input());
143 // Make sure password is not in args.
144 std::vector<std::string> opts =
145 base::SplitString(sandbox->arguments()[1], ",", base::KEEP_WHITESPACE,
146 base::SPLIT_WANT_ALL);
147 EXPECT_THAT(opts,
148 UnorderedElementsAre("umask=0222", "uid=1000", "gid=1001", "ro"));
149}
150
151TEST_F(ArchiveMounterTest, NoPassword) {
152 auto mounter = CreateMounter({kPasswordNeededCode});
153 MountErrorType error = MOUNT_ERROR_UNKNOWN;
154 auto sandbox = PrepareSandbox(*mounter, kSomeSource,
155 {
156 "Password=1", // Options are case sensitive
157 "password =2", // Space is significant
158 " password=3", // Space is significant
159 "password", // Not a valid option
160 },
161 &error);
162 ASSERT_TRUE(sandbox);
163 EXPECT_EQ("", sandbox->input());
164}
165
166TEST_F(ArchiveMounterTest, CopiesPassword) {
167 for (const std::string password : {
168 "",
169 " ",
170 "=",
171 "simple",
172 R"( !@#$%^&*()_-+={[}]|\:;"'<,>.?/ )",
173 }) {
174 auto mounter = CreateMounter({kPasswordNeededCode});
175 MountErrorType error = MOUNT_ERROR_UNKNOWN;
176 auto sandbox =
177 PrepareSandbox(*mounter, kSomeSource, {"password=" + password}, &error);
178 ASSERT_TRUE(sandbox);
179 EXPECT_EQ(password, sandbox->input());
180 }
181}
182
183TEST_F(ArchiveMounterTest, IgnoredIfNotNeeded) {
184 auto mounter = CreateMounter({});
185 MountErrorType error = MOUNT_ERROR_UNKNOWN;
186 auto sandbox =
187 PrepareSandbox(*mounter, kSomeSource, {"password=foo"}, &error);
188 EXPECT_EQ(MOUNT_ERROR_NONE, error);
189 ASSERT_TRUE(sandbox);
190 EXPECT_EQ("", sandbox->input());
191}
192
193} // namespace cros_disks