1 /*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <errno.h>
18 #include <fcntl.h>
19 #include <linux/fs.h>
20 #include <selinux/selinux.h>
21 #include <stdlib.h>
22 #include <sys/mount.h>
23 #include <sys/stat.h>
24 #include <sys/statvfs.h>
25 #include <sys/types.h>
26 #include <sys/vfs.h>
27 #include <unistd.h>
28
29 #include <algorithm>
30 #include <memory>
31 #include <string>
32 #include <vector>
33
34 #include <android-base/file.h>
35 #include <android-base/macros.h>
36 #include <android-base/properties.h>
37 #include <android-base/scopeguard.h>
38 #include <android-base/strings.h>
39 #include <android-base/unique_fd.h>
40 #include <ext4_utils/ext4_utils.h>
41 #include <fs_mgr.h>
42 #include <fs_mgr/file_wait.h>
43 #include <fs_mgr_overlayfs.h>
44 #include <fstab/fstab.h>
45 #include <libgsi/libgsi.h>
46 #include <storage_literals/storage_literals.h>
47
48 #include "fs_mgr_overlayfs_control.h"
49 #include "fs_mgr_overlayfs_mount.h"
50 #include "fs_mgr_priv.h"
51
52 using namespace std::literals;
53 using namespace android::fs_mgr;
54 using namespace android::storage_literals;
55
56 constexpr char kPreferCacheBackingStorageProp[] = "fs_mgr.overlayfs.prefer_cache_backing_storage";
57
58 constexpr char kCacheMountPoint[] = "/cache";
59 constexpr char kPhysicalDevice[] = "/dev/block/by-name/";
60
61 // Mount tree to temporarily hold references to submounts.
62 constexpr char kMoveMountTempDir[] = "/dev/remount";
63
64 constexpr char kLowerdirOption[] = "lowerdir=";
65 constexpr char kUpperdirOption[] = "upperdir=";
66 constexpr char kWorkdirOption[] = "workdir=";
67
fs_mgr_is_dsu_running()68 bool fs_mgr_is_dsu_running() {
69 // Since android::gsi::CanBootIntoGsi() or android::gsi::MarkSystemAsGsi() is
70 // never called in recovery, the return value of android::gsi::IsGsiRunning()
71 // is not well-defined. In this case, just return false as being in recovery
72 // implies not running a DSU system.
73 if (InRecovery()) return false;
74 return android::gsi::IsGsiRunning();
75 }
76
OverlayMountPoints()77 std::vector<std::string> OverlayMountPoints() {
78 // Never fallback to legacy cache mount point if within a DSU system,
79 // because running a DSU system implies the device supports dynamic
80 // partitions, which means legacy cache mustn't be used.
81 if (fs_mgr_is_dsu_running()) {
82 return {kScratchMountPoint};
83 }
84
85 // For non-A/B devices prefer cache backing storage if
86 // kPreferCacheBackingStorageProp property set.
87 if (fs_mgr_get_slot_suffix().empty() &&
88 android::base::GetBoolProperty(kPreferCacheBackingStorageProp, false) &&
89 android::base::GetIntProperty("ro.vendor.api_level", -1) < __ANDROID_API_T__) {
90 return {kCacheMountPoint, kScratchMountPoint};
91 }
92
93 return {kScratchMountPoint, kCacheMountPoint};
94 }
95
GetEncodedBaseDirForMountPoint(const std::string & mount_point)96 std::string GetEncodedBaseDirForMountPoint(const std::string& mount_point) {
97 std::string normalized_path;
98 if (mount_point.empty() || !android::base::Realpath(mount_point, &normalized_path)) {
99 return "";
100 }
101 std::string_view sv(normalized_path);
102 if (sv != "/") {
103 android::base::ConsumePrefix(&sv, "/");
104 android::base::ConsumeSuffix(&sv, "/");
105 }
106 return android::base::StringReplace(sv, "/", "@", true);
107 }
108
fs_mgr_is_dir(const std::string & path)109 static bool fs_mgr_is_dir(const std::string& path) {
110 struct stat st;
111 return !stat(path.c_str(), &st) && S_ISDIR(st.st_mode);
112 }
113
114 // At less than 1% or 8MB of free space return value of false,
115 // means we will try to wrap with overlayfs.
fs_mgr_filesystem_has_space(const std::string & mount_point)116 bool fs_mgr_filesystem_has_space(const std::string& mount_point) {
117 // If we have access issues to find out space remaining, return true
118 // to prevent us trying to override with overlayfs.
119 struct statvfs vst;
120 if (statvfs(mount_point.c_str(), &vst)) {
121 PLOG(ERROR) << "statvfs " << mount_point;
122 return true;
123 }
124
125 static constexpr int kPercentThreshold = 1; // 1%
126 static constexpr unsigned long kSizeThreshold = 8 * 1024 * 1024; // 8MB
127
128 return (vst.f_bfree >= (vst.f_blocks * kPercentThreshold / 100)) &&
129 (static_cast<uint64_t>(vst.f_bfree) * vst.f_frsize) >= kSizeThreshold;
130 }
131
fs_mgr_update_blk_device(FstabEntry * entry)132 static bool fs_mgr_update_blk_device(FstabEntry* entry) {
133 if (entry->fs_mgr_flags.logical) {
134 fs_mgr_update_logical_partition(entry);
135 }
136 if (access(entry->blk_device.c_str(), F_OK) == 0) {
137 return true;
138 }
139 if (entry->blk_device != "/dev/root") {
140 return false;
141 }
142
143 // special case for system-as-root (taimen and others)
144 auto blk_device = kPhysicalDevice + "system"s;
145 if (access(blk_device.c_str(), F_OK)) {
146 blk_device += fs_mgr_get_slot_suffix();
147 if (access(blk_device.c_str(), F_OK)) {
148 return false;
149 }
150 }
151 entry->blk_device = blk_device;
152 return true;
153 }
154
fs_mgr_has_shared_blocks(const std::string & mount_point,const std::string & dev)155 static bool fs_mgr_has_shared_blocks(const std::string& mount_point, const std::string& dev) {
156 struct statfs fs;
157 if ((statfs((mount_point + "/lost+found").c_str(), &fs) == -1) ||
158 (fs.f_type != EXT4_SUPER_MAGIC)) {
159 return false;
160 }
161
162 android::base::unique_fd fd(open(dev.c_str(), O_RDONLY | O_CLOEXEC));
163 if (fd < 0) return false;
164
165 struct ext4_super_block sb;
166 if ((TEMP_FAILURE_RETRY(lseek64(fd, 1024, SEEK_SET)) < 0) ||
167 (TEMP_FAILURE_RETRY(read(fd, &sb, sizeof(sb))) < 0)) {
168 return false;
169 }
170
171 struct fs_info info;
172 if (ext4_parse_sb(&sb, &info) < 0) return false;
173
174 return (info.feat_ro_compat & EXT4_FEATURE_RO_COMPAT_SHARED_BLOCKS) != 0;
175 }
176
177 #define F2FS_SUPER_OFFSET 1024
178 #define F2FS_FEATURE_OFFSET 2180
179 #define F2FS_FEATURE_RO 0x4000
fs_mgr_is_read_only_f2fs(const std::string & dev)180 static bool fs_mgr_is_read_only_f2fs(const std::string& dev) {
181 if (!fs_mgr_is_f2fs(dev)) return false;
182
183 android::base::unique_fd fd(open(dev.c_str(), O_RDONLY | O_CLOEXEC));
184 if (fd < 0) return false;
185
186 __le32 feat;
187 if ((TEMP_FAILURE_RETRY(lseek64(fd, F2FS_SUPER_OFFSET + F2FS_FEATURE_OFFSET, SEEK_SET)) < 0) ||
188 (TEMP_FAILURE_RETRY(read(fd, &feat, sizeof(feat))) < 0)) {
189 return false;
190 }
191
192 return (feat & cpu_to_le32(F2FS_FEATURE_RO)) != 0;
193 }
194
fs_mgr_overlayfs_enabled(FstabEntry * entry)195 static bool fs_mgr_overlayfs_enabled(FstabEntry* entry) {
196 // readonly filesystem, can not be mount -o remount,rw
197 // for squashfs, erofs or if free space is (near) zero making such a remount
198 // virtually useless, or if there are shared blocks that prevent remount,rw
199 if (!fs_mgr_filesystem_has_space(entry->mount_point)) {
200 return true;
201 }
202
203 // blk_device needs to be setup so we can check superblock.
204 // If we fail here, because during init first stage and have doubts.
205 if (!fs_mgr_update_blk_device(entry)) {
206 return true;
207 }
208
209 // f2fs read-only mode doesn't support remount,rw
210 if (fs_mgr_is_read_only_f2fs(entry->blk_device)) {
211 return true;
212 }
213
214 // check if ext4 de-dupe
215 auto has_shared_blocks = fs_mgr_has_shared_blocks(entry->mount_point, entry->blk_device);
216 if (!has_shared_blocks && (entry->mount_point == "/system")) {
217 has_shared_blocks = fs_mgr_has_shared_blocks("/", entry->blk_device);
218 }
219 return has_shared_blocks;
220 }
221
fs_mgr_mount_point(const std::string & mount_point)222 const std::string fs_mgr_mount_point(const std::string& mount_point) {
223 if ("/"s != mount_point) return mount_point;
224 return "/system";
225 }
226
227 // default options for mount_point, returns empty string for none available.
fs_mgr_get_overlayfs_options(const FstabEntry & entry)228 static std::string fs_mgr_get_overlayfs_options(const FstabEntry& entry) {
229 const auto mount_point = fs_mgr_mount_point(entry.mount_point);
230 if (!fs_mgr_is_dir(mount_point)) {
231 return "";
232 }
233 const auto base = GetEncodedBaseDirForMountPoint(mount_point);
234 if (base.empty()) {
235 return "";
236 }
237 for (const auto& overlay_mount_point : OverlayMountPoints()) {
238 const auto dir = overlay_mount_point + "/" + kOverlayTopDir + "/" + base + "/";
239 const auto upper = dir + kUpperName;
240 const auto work = dir + kWorkName;
241 if (!fs_mgr_is_dir(upper) || !fs_mgr_is_dir(work) || access(work.c_str(), R_OK | W_OK)) {
242 continue;
243 }
244 auto ret = kLowerdirOption + mount_point + "," + kUpperdirOption + upper + "," +
245 kWorkdirOption + work + android::fs_mgr::CheckOverlayfs().mount_flags;
246 for (const auto& flag : android::base::Split(entry.fs_options, ",")) {
247 if (android::base::StartsWith(flag, "context=")) {
248 ret += "," + flag;
249 }
250 }
251 return ret;
252 }
253 return "";
254 }
255
Set(const std::string & context)256 bool AutoSetFsCreateCon::Set(const std::string& context) {
257 if (setfscreatecon(context.c_str())) {
258 PLOG(ERROR) << "setfscreatecon " << context;
259 return false;
260 }
261 ok_ = true;
262 return true;
263 }
264
Restore()265 bool AutoSetFsCreateCon::Restore() {
266 if (restored_ || !ok_) {
267 return true;
268 }
269 if (setfscreatecon(nullptr)) {
270 PLOG(ERROR) << "setfscreatecon null";
271 return false;
272 }
273 restored_ = true;
274 return true;
275 }
276
277 // Returns true if immediate unmount succeeded and the scratch mount point was
278 // removed.
fs_mgr_overlayfs_umount_scratch()279 bool fs_mgr_overlayfs_umount_scratch() {
280 if (umount(kScratchMountPoint) != 0) {
281 return false;
282 }
283 if (rmdir(kScratchMountPoint) != 0 && errno != ENOENT) {
284 PLOG(ERROR) << "rmdir " << kScratchMountPoint;
285 }
286 return true;
287 }
288
fs_mgr_overlayfs_set_shared_mount(const std::string & mount_point,bool shared_flag)289 static bool fs_mgr_overlayfs_set_shared_mount(const std::string& mount_point, bool shared_flag) {
290 auto ret = mount(nullptr, mount_point.c_str(), nullptr, shared_flag ? MS_SHARED : MS_PRIVATE,
291 nullptr);
292 if (ret) {
293 PERROR << "__mount(target=" << mount_point
294 << ",flag=" << (shared_flag ? "MS_SHARED" : "MS_PRIVATE") << ")=" << ret;
295 return false;
296 }
297 return true;
298 }
299
fs_mgr_overlayfs_move_mount(const std::string & source,const std::string & target)300 static bool fs_mgr_overlayfs_move_mount(const std::string& source, const std::string& target) {
301 auto ret = mount(source.c_str(), target.c_str(), nullptr, MS_MOVE, nullptr);
302 if (ret) {
303 PERROR << "__mount(source=" << source << ",target=" << target << ",flag=MS_MOVE)=" << ret;
304 return false;
305 }
306 return true;
307 }
308
fs_mgr_overlayfs_mount(const std::string & mount_point,const std::string & options)309 static bool fs_mgr_overlayfs_mount(const std::string& mount_point, const std::string& options) {
310 auto report = "__mount(source=overlay,target="s + mount_point + ",type=overlay";
311 for (const auto& opt : android::base::Split(options, ",")) {
312 if (android::base::StartsWith(opt, kUpperdirOption)) {
313 report = report + "," + opt;
314 break;
315 }
316 }
317 report = report + ")=";
318 auto ret = mount("overlay", mount_point.c_str(), "overlay", MS_RDONLY | MS_NOATIME,
319 options.c_str());
320 if (ret) {
321 PERROR << report << ret;
322 } else {
323 LINFO << report << ret;
324 }
325 return !ret;
326 }
327
328 struct mount_info {
329 std::string mount_point;
330 bool shared_flag;
331 };
332
ReadMountinfoFromFile(const std::string & path)333 static std::vector<mount_info> ReadMountinfoFromFile(const std::string& path) {
334 std::vector<mount_info> info;
335
336 auto file = std::unique_ptr<FILE, decltype(&fclose)>{fopen(path.c_str(), "re"), fclose};
337 if (!file) {
338 PERROR << __FUNCTION__ << "(): cannot open file: '" << path << "'";
339 return info;
340 }
341
342 ssize_t len;
343 size_t alloc_len = 0;
344 char* line = nullptr;
345 while ((len = getline(&line, &alloc_len, file.get())) != -1) {
346 /* if the last character is a newline, shorten the string by 1 byte */
347 if (line[len - 1] == '\n') {
348 line[len - 1] = '\0';
349 }
350
351 static constexpr char delim[] = " \t";
352 char* save_ptr;
353 if (!strtok_r(line, delim, &save_ptr)) {
354 LERROR << "Error parsing mount ID";
355 break;
356 }
357 if (!strtok_r(nullptr, delim, &save_ptr)) {
358 LERROR << "Error parsing parent ID";
359 break;
360 }
361 if (!strtok_r(nullptr, delim, &save_ptr)) {
362 LERROR << "Error parsing mount source";
363 break;
364 }
365 if (!strtok_r(nullptr, delim, &save_ptr)) {
366 LERROR << "Error parsing root";
367 break;
368 }
369
370 char* p;
371 if (!(p = strtok_r(nullptr, delim, &save_ptr))) {
372 LERROR << "Error parsing mount_point";
373 break;
374 }
375 mount_info entry = {p, false};
376
377 if (!strtok_r(nullptr, delim, &save_ptr)) {
378 LERROR << "Error parsing mount_flags";
379 break;
380 }
381
382 while ((p = strtok_r(nullptr, delim, &save_ptr))) {
383 if ((p[0] == '-') && (p[1] == '\0')) break;
384 if (android::base::StartsWith(p, "shared:")) entry.shared_flag = true;
385 }
386 if (!p) {
387 LERROR << "Error parsing fields";
388 break;
389 }
390 info.emplace_back(std::move(entry));
391 }
392
393 free(line);
394 if (info.empty()) {
395 LERROR << __FUNCTION__ << "(): failed to load mountinfo from : '" << path << "'";
396 }
397 return info;
398 }
399
fs_mgr_overlayfs_mount_one(const FstabEntry & fstab_entry)400 static bool fs_mgr_overlayfs_mount_one(const FstabEntry& fstab_entry) {
401 const auto mount_point = fs_mgr_mount_point(fstab_entry.mount_point);
402 const auto options = fs_mgr_get_overlayfs_options(fstab_entry);
403 if (options.empty()) return false;
404
405 struct MoveEntry {
406 std::string mount_point;
407 std::string dir;
408 bool shared_flag;
409 };
410 std::vector<MoveEntry> moved_mounts;
411
412 bool retval = true;
413 bool move_dir_shared = true;
414 bool parent_shared = true;
415 bool parent_have_parent = false;
416 bool parent_made_private = false;
417 bool root_shared = true;
418 bool root_made_private = false;
419
420 // There could be multiple mount entries with the same mountpoint.
421 // Group these entries together with stable_sort, and keep only the last entry of a group.
422 // Only move mount the last entry in an over mount group, because the other entries are
423 // overshadowed and only the filesystem mounted with the last entry participates in file
424 // pathname resolution.
425 auto mountinfo = ReadMountinfoFromFile("/proc/self/mountinfo");
426 std::stable_sort(mountinfo.begin(), mountinfo.end(), [](const auto& lhs, const auto& rhs) {
427 return lhs.mount_point < rhs.mount_point;
428 });
429 std::reverse(mountinfo.begin(), mountinfo.end());
430 auto erase_from = std::unique(
431 mountinfo.begin(), mountinfo.end(),
432 [](const auto& lhs, const auto& rhs) { return lhs.mount_point == rhs.mount_point; });
433 mountinfo.erase(erase_from, mountinfo.end());
434 std::reverse(mountinfo.begin(), mountinfo.end());
435 // mountinfo is reversed twice, so still is in lexical sorted order.
436
437 for (const auto& entry : mountinfo) {
438 if (entry.mount_point == kMoveMountTempDir) {
439 move_dir_shared = entry.shared_flag;
440 }
441 if (entry.mount_point == mount_point ||
442 (mount_point == "/system" && entry.mount_point == "/")) {
443 parent_shared = entry.shared_flag;
444 }
445 if (entry.mount_point == "/") {
446 root_shared = entry.shared_flag;
447 }
448 // Ignore "/" as we don't overlay "/" directly.
449 if (entry.mount_point != "/") {
450 parent_have_parent |= android::base::StartsWith(mount_point, entry.mount_point + "/");
451 }
452 }
453
454 // Precondition is that kMoveMountTempDir is MS_PRIVATE, otherwise don't try to move any
455 // submount in to or out of it.
456 if (move_dir_shared) {
457 mountinfo.clear();
458 }
459
460 // Need to make the original mountpoint MS_PRIVATE, so that the overlayfs can be MS_MOVE.
461 // This could happen if its parent mount is remounted later.
462 if (parent_have_parent) {
463 parent_made_private |= fs_mgr_overlayfs_set_shared_mount(mount_point, false);
464 if (!parent_made_private && errno == EINVAL && mount_point == "/system") {
465 // If failed to set "/system" mount type, it might be due to "/system" not being a valid
466 // mountpoint after switch root. Retry with "/" in this case.
467 parent_made_private |= fs_mgr_overlayfs_set_shared_mount("/", false);
468 root_made_private |= parent_made_private;
469 }
470 }
471
472 for (const auto& entry : mountinfo) {
473 // Find all immediate submounts.
474 if (!android::base::StartsWith(entry.mount_point, mount_point + "/")) {
475 continue;
476 }
477 // Exclude duplicated or more specific entries.
478 if (std::find_if(moved_mounts.begin(), moved_mounts.end(), [&entry](const auto& it) {
479 return it.mount_point == entry.mount_point ||
480 android::base::StartsWith(entry.mount_point, it.mount_point + "/");
481 }) != moved_mounts.end()) {
482 continue;
483 }
484 // mountinfo is in lexical order, so no need to worry about |entry| being a parent mount of
485 // entries of |moved_mounts|.
486
487 MoveEntry new_entry{entry.mount_point, kMoveMountTempDir + "/TemporaryDir-XXXXXX"s,
488 entry.shared_flag};
489 {
490 AutoSetFsCreateCon createcon;
491 auto new_context = fs_mgr_get_context(entry.mount_point);
492 if (new_context.empty() || !createcon.Set(new_context)) {
493 continue;
494 }
495 const auto target = mkdtemp(new_entry.dir.data());
496 if (!target) {
497 retval = false;
498 PERROR << "temporary directory for MS_MOVE";
499 continue;
500 }
501 if (!createcon.Restore()) {
502 retval = false;
503 rmdir(new_entry.dir.c_str());
504 continue;
505 }
506 }
507 if (!parent_made_private) {
508 parent_made_private |= fs_mgr_overlayfs_set_shared_mount(mount_point, false);
509 if (!parent_made_private && errno == EINVAL && mount_point == "/system") {
510 // If failed to set "/system" mount type, it might be due to "/system" not being a
511 // valid mountpoint after switch root. Retry with "/" in this case.
512 parent_made_private |= fs_mgr_overlayfs_set_shared_mount("/", false);
513 root_made_private |= parent_made_private;
514 }
515 }
516
517 if (new_entry.shared_flag) {
518 new_entry.shared_flag = fs_mgr_overlayfs_set_shared_mount(new_entry.mount_point, false);
519 }
520 if (!fs_mgr_overlayfs_move_mount(new_entry.mount_point, new_entry.dir)) {
521 retval = false;
522 if (new_entry.shared_flag) {
523 fs_mgr_overlayfs_set_shared_mount(new_entry.mount_point, true);
524 }
525 rmdir(new_entry.dir.c_str());
526 continue;
527 }
528 moved_mounts.push_back(std::move(new_entry));
529 }
530
531 retval &= fs_mgr_overlayfs_mount(mount_point, options);
532
533 // Move submounts back.
534 for (const auto& entry : moved_mounts) {
535 if (!fs_mgr_overlayfs_move_mount(entry.dir, entry.mount_point)) {
536 retval = false;
537 } else if (entry.shared_flag &&
538 !fs_mgr_overlayfs_set_shared_mount(entry.mount_point, true)) {
539 retval = false;
540 }
541 rmdir(entry.dir.c_str());
542 }
543 // If the original (overridden) mount was MS_SHARED, then set the overlayfs mount to MS_SHARED.
544 if (parent_shared && parent_made_private) {
545 fs_mgr_overlayfs_set_shared_mount(mount_point, true);
546 }
547 if (root_shared && root_made_private) {
548 fs_mgr_overlayfs_set_shared_mount("/", true);
549 }
550
551 return retval;
552 }
553
554 // Mount kScratchMountPoint
MountScratch(const std::string & device_path,bool readonly)555 bool MountScratch(const std::string& device_path, bool readonly) {
556 if (readonly) {
557 if (access(device_path.c_str(), F_OK)) {
558 LOG(ERROR) << "Path does not exist: " << device_path;
559 return false;
560 }
561 } else if (access(device_path.c_str(), R_OK | W_OK)) {
562 LOG(ERROR) << "Path does not exist or is not readwrite: " << device_path;
563 return false;
564 }
565
566 std::vector<const char*> filesystem_candidates;
567 if (fs_mgr_is_f2fs(device_path)) {
568 filesystem_candidates = {"f2fs", "ext4"};
569 } else if (fs_mgr_is_ext4(device_path)) {
570 filesystem_candidates = {"ext4", "f2fs"};
571 } else {
572 LOG(ERROR) << "Scratch partition is not f2fs or ext4";
573 return false;
574 }
575
576 AutoSetFsCreateCon createcon(kOverlayfsFileContext);
577 if (!createcon.Ok()) {
578 return false;
579 }
580 if (mkdir(kScratchMountPoint, 0755) && (errno != EEXIST)) {
581 PERROR << "create " << kScratchMountPoint;
582 return false;
583 }
584
585 FstabEntry entry;
586 entry.blk_device = device_path;
587 entry.mount_point = kScratchMountPoint;
588 entry.flags = MS_NOATIME | MS_RDONLY;
589 if (!readonly) {
590 entry.flags &= ~MS_RDONLY;
591 entry.flags |= MS_SYNCHRONOUS;
592 entry.fs_options = "nodiscard";
593 fs_mgr_set_blk_ro(device_path, false);
594 }
595 // check_fs requires apex runtime library
596 if (fs_mgr_overlayfs_already_mounted("/data", false)) {
597 entry.fs_mgr_flags.check = true;
598 }
599 bool mounted = false;
600 for (auto fs_type : filesystem_candidates) {
601 entry.fs_type = fs_type;
602 if (fs_mgr_do_mount_one(entry) == 0) {
603 mounted = true;
604 break;
605 }
606 }
607 if (!createcon.Restore()) {
608 return false;
609 }
610 if (!mounted) {
611 rmdir(kScratchMountPoint);
612 return false;
613 }
614 return true;
615 }
616
617 // NOTE: OverlayfsSetupAllowed() must be "stricter" than OverlayfsTeardownAllowed().
618 // Setup is allowed only if teardown is also allowed.
OverlayfsSetupAllowed(bool verbose)619 bool OverlayfsSetupAllowed(bool verbose) {
620 if (!kAllowOverlayfs) {
621 if (verbose) {
622 LOG(ERROR) << "Overlayfs remounts can only be used in debuggable builds";
623 }
624 return false;
625 }
626 // Check mandatory kernel patches.
627 if (!android::fs_mgr::CheckOverlayfs().supported) {
628 if (verbose) {
629 LOG(ERROR) << "Kernel does not support overlayfs";
630 }
631 return false;
632 }
633 // in recovery or fastbootd, not allowed!
634 if (InRecovery()) {
635 if (verbose) {
636 LOG(ERROR) << "Unsupported overlayfs setup from recovery";
637 }
638 return false;
639 }
640 return true;
641 }
642
fs_mgr_wants_overlayfs(FstabEntry * entry)643 bool fs_mgr_wants_overlayfs(FstabEntry* entry) {
644 // Don't check entries that are managed by vold.
645 if (entry->fs_mgr_flags.vold_managed || entry->fs_mgr_flags.recovery_only) return false;
646
647 // *_other doesn't want overlayfs.
648 if (entry->fs_mgr_flags.slot_select_other) return false;
649
650 // Only concerned with readonly partitions.
651 if (!(entry->flags & MS_RDONLY)) return false;
652
653 // If unbindable, do not allow overlayfs as this could expose us to
654 // security issues. On Android, this could also be used to turn off
655 // the ability to overlay an otherwise acceptable filesystem since
656 // /system and /vendor are never bound(sic) to.
657 if (entry->flags & MS_UNBINDABLE) return false;
658
659 if (!fs_mgr_overlayfs_enabled(entry)) return false;
660
661 return true;
662 }
663
fs_mgr_overlayfs_candidate_list(const Fstab & fstab)664 Fstab fs_mgr_overlayfs_candidate_list(const Fstab& fstab) {
665 android::fs_mgr::Fstab mounts;
666 if (!android::fs_mgr::ReadFstabFromFile("/proc/mounts", &mounts)) {
667 PLOG(ERROR) << "Failed to read /proc/mounts";
668 return {};
669 }
670
671 Fstab candidates;
672 for (const auto& entry : fstab) {
673 // Filter out partitions whose type doesn't match what's mounted.
674 // This avoids spammy behavior on devices which can mount different
675 // filesystems for each partition.
676 auto proc_mount_point = (entry.mount_point == "/system") ? "/" : entry.mount_point;
677 auto mounted = GetEntryForMountPoint(&mounts, proc_mount_point);
678 if (!mounted || mounted->fs_type != entry.fs_type) {
679 continue;
680 }
681
682 FstabEntry new_entry = entry;
683 if (!fs_mgr_overlayfs_already_mounted(entry.mount_point) &&
684 !fs_mgr_wants_overlayfs(&new_entry)) {
685 continue;
686 }
687 const auto new_mount_point = fs_mgr_mount_point(new_entry.mount_point);
688 if (std::find_if(candidates.begin(), candidates.end(), [&](const auto& it) {
689 return fs_mgr_mount_point(it.mount_point) == new_mount_point;
690 }) != candidates.end()) {
691 continue;
692 }
693 candidates.push_back(std::move(new_entry));
694 }
695 return candidates;
696 }
697
TryMountScratch()698 static void TryMountScratch() {
699 // Note we get the boot scratch device here, which means if scratch was
700 // just created through ImageManager, this could fail. In practice this
701 // should not happen because "remount" detects this scenario (by checking
702 // if verity is still disabled, i.e. no reboot occurred), and skips calling
703 // fs_mgr_overlayfs_mount_all().
704 auto scratch_device = GetBootScratchDevice();
705 if (access(scratch_device.c_str(), R_OK | W_OK)) {
706 return;
707 }
708 if (!WaitForFile(scratch_device, 10s)) {
709 return;
710 }
711 if (!MountScratch(scratch_device, true /* readonly */)) {
712 return;
713 }
714 const auto top = kScratchMountPoint + "/"s + kOverlayTopDir;
715 const bool has_overlayfs_dir = access(top.c_str(), F_OK) == 0;
716 fs_mgr_overlayfs_umount_scratch();
717 if (has_overlayfs_dir) {
718 MountScratch(scratch_device);
719 }
720 }
721
fs_mgr_overlayfs_mount_all(Fstab * fstab)722 bool fs_mgr_overlayfs_mount_all(Fstab* fstab) {
723 if (!OverlayfsSetupAllowed()) {
724 return false;
725 }
726
727 // Ensure kMoveMountTempDir is standalone mount tree with 'private' propagation by bind mounting
728 // to itself and set to MS_PRIVATE.
729 // Otherwise mounts moved in to it would have their propagation type changed unintentionally.
730 // Section 5d, https://www.kernel.org/doc/Documentation/filesystems/sharedsubtree.txt
731 if (!fs_mgr_overlayfs_already_mounted(kMoveMountTempDir, false)) {
732 if (mkdir(kMoveMountTempDir, 0755) && errno != EEXIST) {
733 PERROR << "mkdir " << kMoveMountTempDir;
734 }
735 if (mount(kMoveMountTempDir, kMoveMountTempDir, nullptr, MS_BIND, nullptr)) {
736 PERROR << "bind mount " << kMoveMountTempDir;
737 }
738 }
739 fs_mgr_overlayfs_set_shared_mount(kMoveMountTempDir, false);
740 android::base::ScopeGuard umountDir([]() {
741 umount(kMoveMountTempDir);
742 rmdir(kMoveMountTempDir);
743 });
744
745 auto ret = true;
746 auto scratch_can_be_mounted = !fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false);
747 for (const auto& entry : fs_mgr_overlayfs_candidate_list(*fstab)) {
748 if (fs_mgr_is_verity_enabled(entry)) continue;
749 auto mount_point = fs_mgr_mount_point(entry.mount_point);
750 if (fs_mgr_overlayfs_already_mounted(mount_point)) {
751 continue;
752 }
753 if (scratch_can_be_mounted) {
754 scratch_can_be_mounted = false;
755 TryMountScratch();
756 }
757 ret &= fs_mgr_overlayfs_mount_one(entry);
758 }
759 return ret;
760 }
761
fs_mgr_overlayfs_is_setup()762 bool fs_mgr_overlayfs_is_setup() {
763 if (!OverlayfsSetupAllowed()) {
764 return false;
765 }
766 if (fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) return true;
767 Fstab fstab;
768 if (!ReadDefaultFstab(&fstab)) {
769 return false;
770 }
771 for (const auto& entry : fs_mgr_overlayfs_candidate_list(fstab)) {
772 if (fs_mgr_is_verity_enabled(entry)) continue;
773 if (fs_mgr_overlayfs_already_mounted(fs_mgr_mount_point(entry.mount_point))) return true;
774 }
775 return false;
776 }
777
fs_mgr_overlayfs_already_mounted(const std::string & mount_point,bool overlay_only)778 bool fs_mgr_overlayfs_already_mounted(const std::string& mount_point, bool overlay_only) {
779 Fstab fstab;
780 if (!ReadFstabFromProcMounts(&fstab)) {
781 return false;
782 }
783 const auto lowerdir = kLowerdirOption + mount_point;
784 for (const auto& entry : GetEntriesForMountPoint(&fstab, mount_point)) {
785 if (!overlay_only) {
786 return true;
787 }
788 if (entry->fs_type != "overlay" && entry->fs_type != "overlayfs") {
789 continue;
790 }
791 const auto options = android::base::Split(entry->fs_options, ",");
792 for (const auto& opt : options) {
793 if (opt == lowerdir) {
794 return true;
795 }
796 }
797 }
798 return false;
799 }
800
801 namespace android {
802 namespace fs_mgr {
803
MountOverlayfs(const FstabEntry & fstab_entry,bool * scratch_can_be_mounted)804 void MountOverlayfs(const FstabEntry& fstab_entry, bool* scratch_can_be_mounted) {
805 if (!OverlayfsSetupAllowed()) {
806 return;
807 }
808 const auto candidates = fs_mgr_overlayfs_candidate_list({fstab_entry});
809 if (candidates.empty()) {
810 return;
811 }
812 const auto& entry = candidates.front();
813 if (fs_mgr_is_verity_enabled(entry)) {
814 return;
815 }
816 const auto mount_point = fs_mgr_mount_point(entry.mount_point);
817 if (fs_mgr_overlayfs_already_mounted(mount_point)) {
818 return;
819 }
820 if (*scratch_can_be_mounted) {
821 *scratch_can_be_mounted = false;
822 if (!fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) {
823 TryMountScratch();
824 }
825 }
826 const auto options = fs_mgr_get_overlayfs_options(entry);
827 if (options.empty()) {
828 return;
829 }
830 fs_mgr_overlayfs_mount(mount_point, options);
831 }
832
833 } // namespace fs_mgr
834 } // namespace android
835