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<const 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 root_shared = true;
416 bool root_made_private = false;
417
418 // There could be multiple mount entries with the same mountpoint.
419 // Group these entries together with stable_sort, and keep only the last entry of a group.
420 // Only move mount the last entry in an over mount group, because the other entries are
421 // overshadowed and only the filesystem mounted with the last entry participates in file
422 // pathname resolution.
423 auto mountinfo = ReadMountinfoFromFile("/proc/self/mountinfo");
424 std::stable_sort(mountinfo.begin(), mountinfo.end(), [](const auto& lhs, const auto& rhs) {
425 return lhs.mount_point < rhs.mount_point;
426 });
427 std::reverse(mountinfo.begin(), mountinfo.end());
428 auto erase_from = std::unique(
429 mountinfo.begin(), mountinfo.end(),
430 [](const auto& lhs, const auto& rhs) { return lhs.mount_point == rhs.mount_point; });
431 mountinfo.erase(erase_from, mountinfo.end());
432 std::reverse(mountinfo.begin(), mountinfo.end());
433 // mountinfo is reversed twice, so still is in lexical sorted order.
434
435 for (const auto& entry : mountinfo) {
436 if (entry.mount_point == kMoveMountTempDir) {
437 move_dir_shared = entry.shared_flag;
438 }
439 if (entry.mount_point == mount_point ||
440 (mount_point == "/system" && entry.mount_point == "/")) {
441 parent_shared = entry.shared_flag;
442 }
443 if (entry.mount_point == "/") {
444 root_shared = entry.shared_flag;
445 }
446 }
447
448 // Precondition is that kMoveMountTempDir is MS_PRIVATE, otherwise don't try to move any
449 // submount in to or out of it.
450 if (move_dir_shared) {
451 mountinfo.clear();
452 }
453
454 // Need to make the original mountpoint MS_PRIVATE, so that the overlayfs can be MS_MOVE.
455 // This could happen if its parent mount is remounted later.
456 if (!fs_mgr_overlayfs_set_shared_mount(mount_point, false)) {
457 // If failed to set "/system" mount type, it might be due to "/system" not being a valid
458 // mountpoint after switch root. Retry with "/" in this case.
459 if (errno == EINVAL && mount_point == "/system") {
460 root_made_private = fs_mgr_overlayfs_set_shared_mount("/", false);
461 }
462 }
463
464 for (const auto& entry : mountinfo) {
465 // Find all immediate submounts.
466 if (!android::base::StartsWith(entry.mount_point, mount_point + "/")) {
467 continue;
468 }
469 // Exclude duplicated or more specific entries.
470 if (std::find_if(moved_mounts.begin(), moved_mounts.end(), [&entry](const auto& it) {
471 return it.mount_point == entry.mount_point ||
472 android::base::StartsWith(entry.mount_point, it.mount_point + "/");
473 }) != moved_mounts.end()) {
474 continue;
475 }
476 // mountinfo is in lexical order, so no need to worry about |entry| being a parent mount of
477 // entries of |moved_mounts|.
478
479 MoveEntry new_entry{entry.mount_point, kMoveMountTempDir + "/TemporaryDir-XXXXXX"s,
480 entry.shared_flag};
481 {
482 AutoSetFsCreateCon createcon;
483 auto new_context = fs_mgr_get_context(entry.mount_point);
484 if (new_context.empty() || !createcon.Set(new_context)) {
485 continue;
486 }
487 const auto target = mkdtemp(new_entry.dir.data());
488 if (!target) {
489 retval = false;
490 PERROR << "temporary directory for MS_MOVE";
491 continue;
492 }
493 if (!createcon.Restore()) {
494 retval = false;
495 rmdir(new_entry.dir.c_str());
496 continue;
497 }
498 }
499
500 if (new_entry.shared_flag) {
501 new_entry.shared_flag = fs_mgr_overlayfs_set_shared_mount(new_entry.mount_point, false);
502 }
503 if (!fs_mgr_overlayfs_move_mount(new_entry.mount_point, new_entry.dir)) {
504 retval = false;
505 if (new_entry.shared_flag) {
506 fs_mgr_overlayfs_set_shared_mount(new_entry.mount_point, true);
507 }
508 rmdir(new_entry.dir.c_str());
509 continue;
510 }
511 moved_mounts.push_back(std::move(new_entry));
512 }
513
514 retval &= fs_mgr_overlayfs_mount(mount_point, options);
515
516 // Move submounts back.
517 for (const auto& entry : moved_mounts) {
518 if (!fs_mgr_overlayfs_move_mount(entry.dir, entry.mount_point)) {
519 retval = false;
520 } else if (entry.shared_flag &&
521 !fs_mgr_overlayfs_set_shared_mount(entry.mount_point, true)) {
522 retval = false;
523 }
524 rmdir(entry.dir.c_str());
525 }
526 // If the original (overridden) mount was MS_SHARED, then set the overlayfs mount to MS_SHARED.
527 if (parent_shared) {
528 fs_mgr_overlayfs_set_shared_mount(mount_point, true);
529 }
530 if (root_shared && root_made_private) {
531 fs_mgr_overlayfs_set_shared_mount("/", true);
532 }
533
534 return retval;
535 }
536
537 // Mount kScratchMountPoint
MountScratch(const std::string & device_path,bool readonly)538 bool MountScratch(const std::string& device_path, bool readonly) {
539 if (readonly) {
540 if (access(device_path.c_str(), F_OK)) {
541 LOG(ERROR) << "Path does not exist: " << device_path;
542 return false;
543 }
544 } else if (access(device_path.c_str(), R_OK | W_OK)) {
545 LOG(ERROR) << "Path does not exist or is not readwrite: " << device_path;
546 return false;
547 }
548
549 std::vector<const char*> filesystem_candidates;
550 if (fs_mgr_is_f2fs(device_path)) {
551 filesystem_candidates = {"f2fs", "ext4"};
552 } else if (fs_mgr_is_ext4(device_path)) {
553 filesystem_candidates = {"ext4", "f2fs"};
554 } else {
555 LOG(ERROR) << "Scratch partition is not f2fs or ext4";
556 return false;
557 }
558
559 AutoSetFsCreateCon createcon(kOverlayfsFileContext);
560 if (!createcon.Ok()) {
561 return false;
562 }
563 if (mkdir(kScratchMountPoint, 0755) && (errno != EEXIST)) {
564 PERROR << "create " << kScratchMountPoint;
565 return false;
566 }
567
568 FstabEntry entry;
569 entry.blk_device = device_path;
570 entry.mount_point = kScratchMountPoint;
571 entry.flags = MS_NOATIME | MS_RDONLY;
572 if (!readonly) {
573 entry.flags &= ~MS_RDONLY;
574 entry.flags |= MS_SYNCHRONOUS;
575 entry.fs_options = "nodiscard";
576 fs_mgr_set_blk_ro(device_path, false);
577 }
578 // check_fs requires apex runtime library
579 if (fs_mgr_overlayfs_already_mounted("/data", false)) {
580 entry.fs_mgr_flags.check = true;
581 }
582 bool mounted = false;
583 for (auto fs_type : filesystem_candidates) {
584 entry.fs_type = fs_type;
585 if (fs_mgr_do_mount_one(entry) == 0) {
586 mounted = true;
587 break;
588 }
589 }
590 if (!createcon.Restore()) {
591 return false;
592 }
593 if (!mounted) {
594 rmdir(kScratchMountPoint);
595 return false;
596 }
597 return true;
598 }
599
600 // NOTE: OverlayfsSetupAllowed() must be "stricter" than OverlayfsTeardownAllowed().
601 // Setup is allowed only if teardown is also allowed.
OverlayfsSetupAllowed(bool verbose)602 bool OverlayfsSetupAllowed(bool verbose) {
603 if (!kAllowOverlayfs) {
604 if (verbose) {
605 LOG(ERROR) << "Overlayfs remounts can only be used in debuggable builds";
606 }
607 return false;
608 }
609 // Check mandatory kernel patches.
610 if (!android::fs_mgr::CheckOverlayfs().supported) {
611 if (verbose) {
612 LOG(ERROR) << "Kernel does not support overlayfs";
613 }
614 return false;
615 }
616 // in recovery or fastbootd, not allowed!
617 if (InRecovery()) {
618 if (verbose) {
619 LOG(ERROR) << "Unsupported overlayfs setup from recovery";
620 }
621 return false;
622 }
623 return true;
624 }
625
fs_mgr_wants_overlayfs(FstabEntry * entry)626 bool fs_mgr_wants_overlayfs(FstabEntry* entry) {
627 // Don't check entries that are managed by vold.
628 if (entry->fs_mgr_flags.vold_managed || entry->fs_mgr_flags.recovery_only) return false;
629
630 // *_other doesn't want overlayfs.
631 if (entry->fs_mgr_flags.slot_select_other) return false;
632
633 // Only concerned with readonly partitions.
634 if (!(entry->flags & MS_RDONLY)) return false;
635
636 // If unbindable, do not allow overlayfs as this could expose us to
637 // security issues. On Android, this could also be used to turn off
638 // the ability to overlay an otherwise acceptable filesystem since
639 // /system and /vendor are never bound(sic) to.
640 if (entry->flags & MS_UNBINDABLE) return false;
641
642 if (!fs_mgr_overlayfs_enabled(entry)) return false;
643
644 return true;
645 }
646
fs_mgr_overlayfs_candidate_list(const Fstab & fstab)647 Fstab fs_mgr_overlayfs_candidate_list(const Fstab& fstab) {
648 android::fs_mgr::Fstab mounts;
649 if (!android::fs_mgr::ReadFstabFromFile("/proc/mounts", &mounts)) {
650 PLOG(ERROR) << "Failed to read /proc/mounts";
651 return {};
652 }
653
654 Fstab candidates;
655 for (const auto& entry : fstab) {
656 // Filter out partitions whose type doesn't match what's mounted.
657 // This avoids spammy behavior on devices which can mount different
658 // filesystems for each partition.
659 auto proc_mount_point = (entry.mount_point == "/system") ? "/" : entry.mount_point;
660 auto mounted = GetEntryForMountPoint(&mounts, proc_mount_point);
661 if (!mounted || mounted->fs_type != entry.fs_type) {
662 continue;
663 }
664
665 FstabEntry new_entry = entry;
666 if (!fs_mgr_overlayfs_already_mounted(entry.mount_point) &&
667 !fs_mgr_wants_overlayfs(&new_entry)) {
668 continue;
669 }
670 const auto new_mount_point = fs_mgr_mount_point(new_entry.mount_point);
671 if (std::find_if(candidates.begin(), candidates.end(), [&](const auto& it) {
672 return fs_mgr_mount_point(it.mount_point) == new_mount_point;
673 }) != candidates.end()) {
674 continue;
675 }
676 candidates.push_back(std::move(new_entry));
677 }
678 return candidates;
679 }
680
TryMountScratch()681 static void TryMountScratch() {
682 // Note we get the boot scratch device here, which means if scratch was
683 // just created through ImageManager, this could fail. In practice this
684 // should not happen because "remount" detects this scenario (by checking
685 // if verity is still disabled, i.e. no reboot occurred), and skips calling
686 // fs_mgr_overlayfs_mount_all().
687 auto scratch_device = GetBootScratchDevice();
688 if (access(scratch_device.c_str(), R_OK | W_OK)) {
689 return;
690 }
691 if (!WaitForFile(scratch_device, 10s)) {
692 return;
693 }
694 if (!MountScratch(scratch_device, true /* readonly */)) {
695 return;
696 }
697 const auto top = kScratchMountPoint + "/"s + kOverlayTopDir;
698 const bool has_overlayfs_dir = access(top.c_str(), F_OK) == 0;
699 fs_mgr_overlayfs_umount_scratch();
700 if (has_overlayfs_dir) {
701 MountScratch(scratch_device);
702 }
703 }
704
fs_mgr_overlayfs_mount_all(Fstab * fstab)705 bool fs_mgr_overlayfs_mount_all(Fstab* fstab) {
706 if (!OverlayfsSetupAllowed()) {
707 return false;
708 }
709
710 // Ensure kMoveMountTempDir is standalone mount tree with 'private' propagation by bind mounting
711 // to itself and set to MS_PRIVATE.
712 // Otherwise mounts moved in to it would have their propagation type changed unintentionally.
713 // Section 5d, https://www.kernel.org/doc/Documentation/filesystems/sharedsubtree.txt
714 if (!fs_mgr_overlayfs_already_mounted(kMoveMountTempDir, false)) {
715 if (mkdir(kMoveMountTempDir, 0755) && errno != EEXIST) {
716 PERROR << "mkdir " << kMoveMountTempDir;
717 }
718 if (mount(kMoveMountTempDir, kMoveMountTempDir, nullptr, MS_BIND, nullptr)) {
719 PERROR << "bind mount " << kMoveMountTempDir;
720 }
721 }
722 fs_mgr_overlayfs_set_shared_mount(kMoveMountTempDir, false);
723 android::base::ScopeGuard umountDir([]() {
724 umount(kMoveMountTempDir);
725 rmdir(kMoveMountTempDir);
726 });
727
728 auto ret = true;
729 auto scratch_can_be_mounted = !fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false);
730 for (const auto& entry : fs_mgr_overlayfs_candidate_list(*fstab)) {
731 if (fs_mgr_is_verity_enabled(entry)) continue;
732 auto mount_point = fs_mgr_mount_point(entry.mount_point);
733 if (fs_mgr_overlayfs_already_mounted(mount_point)) {
734 continue;
735 }
736 if (scratch_can_be_mounted) {
737 scratch_can_be_mounted = false;
738 TryMountScratch();
739 }
740 ret &= fs_mgr_overlayfs_mount_one(entry);
741 }
742 return ret;
743 }
744
fs_mgr_overlayfs_is_setup()745 bool fs_mgr_overlayfs_is_setup() {
746 if (!OverlayfsSetupAllowed()) {
747 return false;
748 }
749 if (fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) return true;
750 Fstab fstab;
751 if (!ReadDefaultFstab(&fstab)) {
752 return false;
753 }
754 for (const auto& entry : fs_mgr_overlayfs_candidate_list(fstab)) {
755 if (fs_mgr_is_verity_enabled(entry)) continue;
756 if (fs_mgr_overlayfs_already_mounted(fs_mgr_mount_point(entry.mount_point))) return true;
757 }
758 return false;
759 }
760
fs_mgr_overlayfs_already_mounted(const std::string & mount_point,bool overlay_only)761 bool fs_mgr_overlayfs_already_mounted(const std::string& mount_point, bool overlay_only) {
762 Fstab fstab;
763 if (!ReadFstabFromProcMounts(&fstab)) {
764 return false;
765 }
766 const auto lowerdir = kLowerdirOption + mount_point;
767 for (const auto& entry : GetEntriesForMountPoint(&fstab, mount_point)) {
768 if (!overlay_only) {
769 return true;
770 }
771 if (entry->fs_type != "overlay" && entry->fs_type != "overlayfs") {
772 continue;
773 }
774 const auto options = android::base::Split(entry->fs_options, ",");
775 for (const auto& opt : options) {
776 if (opt == lowerdir) {
777 return true;
778 }
779 }
780 }
781 return false;
782 }
783
784 namespace android {
785 namespace fs_mgr {
786
MountOverlayfs(const FstabEntry & fstab_entry,bool * scratch_can_be_mounted)787 void MountOverlayfs(const FstabEntry& fstab_entry, bool* scratch_can_be_mounted) {
788 if (!OverlayfsSetupAllowed()) {
789 return;
790 }
791 const auto candidates = fs_mgr_overlayfs_candidate_list({fstab_entry});
792 if (candidates.empty()) {
793 return;
794 }
795 const auto& entry = candidates.front();
796 if (fs_mgr_is_verity_enabled(entry)) {
797 return;
798 }
799 const auto mount_point = fs_mgr_mount_point(entry.mount_point);
800 if (fs_mgr_overlayfs_already_mounted(mount_point)) {
801 return;
802 }
803 if (*scratch_can_be_mounted) {
804 *scratch_can_be_mounted = false;
805 if (!fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) {
806 TryMountScratch();
807 }
808 }
809 const auto options = fs_mgr_get_overlayfs_options(entry);
810 if (options.empty()) {
811 return;
812 }
813 fs_mgr_overlayfs_mount(mount_point, options);
814 }
815
816 } // namespace fs_mgr
817 } // namespace android
818