blob: 57df9c3123457a10dd4a9d2e9e934ab4e5342af9 [file] [log] [blame]
Ben Chancb517732012-04-11 17:00:00 -07001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Ben Chan8dcede82011-07-25 20:56:13 -07002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Ben Chan5ccd9fe2013-11-13 18:28:27 -08005#include "cros-disks/archive_manager.h"
Ben Chan8dcede82011-07-25 20:56:13 -07006
Sergei Datsenkoc9904bb2020-12-11 12:46:02 +11007#include <utility>
8
Ben Chan97e20d42014-02-05 18:38:07 -08009#include <base/files/file_path.h>
Ben Chancd8fda42014-09-05 08:21:06 -070010#include <base/files/file_util.h>
François Degrosf76886e2020-07-24 18:13:40 +100011#include <base/strings/string_number_conversions.h>
Ben Chan97e20d42014-02-05 18:38:07 -080012#include <base/strings/string_util.h>
Alex Vakulenkoe7696532015-10-16 16:27:29 -070013#include <brillo/cryptohome.h>
Ben Chan8dcede82011-07-25 20:56:13 -070014
Sergei Datsenkoc9904bb2020-12-11 12:46:02 +110015#include "cros-disks/archive_mounter.h"
Ben Chan8dcede82011-07-25 20:56:13 -070016#include "cros-disks/platform.h"
Sergei Datsenkoc9904bb2020-12-11 12:46:02 +110017#include "cros-disks/quote.h"
18#include "cros-disks/rar_mounter.h"
Sergei Datsenkof3ebcc32020-12-07 23:47:56 +110019#include "cros-disks/user.h"
Ben Chan8dcede82011-07-25 20:56:13 -070020
Anand K Mistry40cff452019-07-30 10:24:48 +100021namespace cros_disks {
Ben Chan460439f2011-09-13 09:16:28 -070022
Sergei Datsenkoc9904bb2020-12-11 12:46:02 +110023ArchiveManager::ArchiveManager(const std::string& mount_root,
24 Platform* platform,
25 Metrics* metrics,
26 brillo::ProcessReaper* process_reaper)
27 : MountManager(mount_root, platform, metrics, process_reaper) {}
28
29ArchiveManager::~ArchiveManager() = default;
30
31bool ArchiveManager::Initialize() {
32 if (!MountManager::Initialize())
33 return false;
34
Sergei Datsenkoc9904bb2020-12-11 12:46:02 +110035 {
Sergei Datsenko87c49bb2021-01-13 15:08:07 +110036 SandboxedExecutable executable = {
Sergei Datsenkoc9904bb2020-12-11 12:46:02 +110037 base::FilePath("/usr/bin/fuse-zip"),
38 base::FilePath("/usr/share/policy/fuse-zip-seccomp.policy")};
39
Sergei Datsenko87c49bb2021-01-13 15:08:07 +110040 auto sandbox_factory =
41 CreateSandboxFactory(std::move(executable), "fuse-zip");
Sergei Datsenkoc9904bb2020-12-11 12:46:02 +110042 std::vector<int> password_needed_codes = {
43 23, // ZIP_ER_BASE + ZIP_ER_ZLIB
44 36, // ZIP_ER_BASE + ZIP_ER_NOPASSWD
45 37}; // ZIP_ER_BASE + ZIP_ER_WRONGPASSWD
46
47 mounters_.push_back(std::make_unique<ArchiveMounter>(
48 platform(), process_reaper(), "zip", metrics(), "FuseZip",
49 std::move(password_needed_codes), std::move(sandbox_factory)));
50 }
51
52 {
Sergei Datsenko87c49bb2021-01-13 15:08:07 +110053 SandboxedExecutable executable = {
Sergei Datsenkoc9904bb2020-12-11 12:46:02 +110054 base::FilePath("/usr/bin/rar2fs"),
55 base::FilePath("/usr/share/policy/rar2fs-seccomp.policy")};
56
Sergei Datsenko87c49bb2021-01-13 15:08:07 +110057 auto sandbox_factory =
58 CreateSandboxFactory(std::move(executable), "fuse-rar2fs");
Sergei Datsenkoc9904bb2020-12-11 12:46:02 +110059
60 mounters_.push_back(std::make_unique<RarMounter>(
61 platform(), process_reaper(), metrics(), std::move(sandbox_factory)));
62 }
63
64 return true;
65}
66
François Degros7f7a4162020-06-13 00:13:00 +100067bool ArchiveManager::ResolvePath(const std::string& path,
68 std::string* real_path) {
Sergei Datsenkoc9904bb2020-12-11 12:46:02 +110069 std::unique_ptr<brillo::ScopedMountNamespace> mount_ns;
70 if (!platform()->PathExists(path)) {
71 // Try to locate the file in Chrome's mount namespace.
72 mount_ns = brillo::ScopedMountNamespace::CreateFromPath(
73 base::FilePath(ArchiveMounter::kChromeNamespace));
74 if (!mount_ns) {
François Degrosca450862021-01-14 14:40:02 +110075 PLOG(ERROR) << "Cannot find archive " << redact(path)
76 << " in mount namespace "
77 << quote(ArchiveMounter::kChromeNamespace);
Sergei Datsenkoc9904bb2020-12-11 12:46:02 +110078 return false;
79 }
80 }
François Degros7f7a4162020-06-13 00:13:00 +100081 return platform()->GetRealPath(path, real_path);
82}
83
François Degros7f7a4162020-06-13 00:13:00 +100084bool ArchiveManager::IsInAllowedFolder(const std::string& source_path) {
85 std::vector<std::string> parts;
86 base::FilePath(source_path).GetComponents(&parts);
87
88 if (parts.size() < 2 || parts[0] != "/")
François Degros853c7d92020-02-17 10:32:21 +110089 return false;
90
François Degros7f7a4162020-06-13 00:13:00 +100091 if (parts[1] == "home")
92 return parts.size() > 5 && parts[2] == "chronos" &&
93 base::StartsWith(parts[3], "u-", base::CompareCase::SENSITIVE) &&
94 brillo::cryptohome::home::IsSanitizedUserName(parts[3].substr(2)) &&
95 parts[4] == "MyFiles";
Ben Chan8dcede82011-07-25 20:56:13 -070096
François Degros7f7a4162020-06-13 00:13:00 +100097 if (parts[1] == "media")
98 return parts.size() > 4 && (parts[2] == "archive" || parts[2] == "fuse" ||
99 parts[2] == "removable");
100
101 if (parts[1] == "run")
102 return parts.size() > 8 && parts[2] == "arc" && parts[3] == "sdcard" &&
103 parts[4] == "write" && parts[5] == "emulated" && parts[6] == "0";
104
Ben Chan8dcede82011-07-25 20:56:13 -0700105 return false;
106}
107
Ben Chan213c6d92019-04-10 16:21:52 -0700108std::string ArchiveManager::SuggestMountPath(
109 const std::string& source_path) const {
Ben Chan8dcede82011-07-25 20:56:13 -0700110 // Use the archive name to name the mount directory.
Ben Chan213c6d92019-04-10 16:21:52 -0700111 base::FilePath base_name = base::FilePath(source_path).BaseName();
Anand K Mistry30e32fa2020-02-04 10:07:57 +1100112 return mount_root().Append(base_name).value();
Ben Chan8dcede82011-07-25 20:56:13 -0700113}
114
François Degrosf76886e2020-07-24 18:13:40 +1000115std::vector<gid_t> ArchiveManager::GetSupplementaryGroups() const {
116 std::vector<gid_t> groups;
117
118 // To access Play Files.
119 gid_t gid;
120 if (platform()->GetGroupId("android-everybody", &gid))
121 groups.push_back(gid);
122
123 return groups;
124}
125
Sergei Datsenkoc9904bb2020-12-11 12:46:02 +1100126bool ArchiveManager::CanMount(const std::string& source_path) const {
127 if (IsInAllowedFolder(source_path)) {
128 base::FilePath name;
129 for (const auto& m : mounters_) {
130 if (m->CanMount(source_path, {}, &name)) {
131 return true;
132 }
133 }
François Degrosf76886e2020-07-24 18:13:40 +1000134 }
Sergei Datsenkoc9904bb2020-12-11 12:46:02 +1100135 return false;
136}
137
138std::unique_ptr<MountPoint> ArchiveManager::DoMount(
139 const std::string& source_path,
François Degrosca450862021-01-14 14:40:02 +1100140 const std::string& filesystem_type,
Sergei Datsenkoc9904bb2020-12-11 12:46:02 +1100141 const std::vector<std::string>& options,
142 const base::FilePath& mount_path,
Sergei Datsenkoc9904bb2020-12-11 12:46:02 +1100143 MountErrorType* error) {
144 // Here source_path is already resolved and free from symlinks and '..' by
145 // the base class.
146 if (!IsInAllowedFolder(source_path)) {
François Degrosca450862021-01-14 14:40:02 +1100147 LOG(ERROR) << "Source path " << redact(source_path) << " is not allowed";
Sergei Datsenkoc9904bb2020-12-11 12:46:02 +1100148 *error = MOUNT_ERROR_INVALID_DEVICE_PATH;
149 return nullptr;
150 }
151 base::FilePath name;
152 for (const auto& m : mounters_) {
153 if (m->CanMount(source_path, {}, &name)) {
Sergei Datsenkoc9904bb2020-12-11 12:46:02 +1100154 return m->Mount(source_path, mount_path, options, error);
155 }
156 }
François Degrosca450862021-01-14 14:40:02 +1100157 LOG(ERROR) << "Cannot find mounter for archive " << redact(source_path)
158 << " of type " << quote(filesystem_type);
Sergei Datsenkoc9904bb2020-12-11 12:46:02 +1100159 *error = MOUNT_ERROR_UNKNOWN_FILESYSTEM;
160 return nullptr;
François Degrosf76886e2020-07-24 18:13:40 +1000161}
162
Sergei Datsenko87c49bb2021-01-13 15:08:07 +1100163std::unique_ptr<FUSESandboxedProcessFactory>
164ArchiveManager::CreateSandboxFactory(SandboxedExecutable executable,
165 const std::string& user_name) const {
166 // To access Play Files.
167 std::vector<gid_t> groups;
168 gid_t gid;
169 if (platform()->GetGroupId("android-everybody", &gid))
170 groups.push_back(gid);
171
172 OwnerUser run_as;
173 if (!platform()->GetUserAndGroupId(user_name, &run_as.uid, &run_as.gid)) {
174 PLOG(ERROR) << "Cannot resolve required user " << quote(user_name);
175 return nullptr;
176 }
177 // Archivers need to run in chronos-access group to be able to access
178 // user's files.
179 run_as.gid = kChronosAccessGID;
180
181 return std::make_unique<FUSESandboxedProcessFactory>(
182 platform(), std::move(executable), std::move(run_as),
183 /* has_network_access= */ false, std::move(groups));
184}
185
Ben Chan8dcede82011-07-25 20:56:13 -0700186} // namespace cros_disks