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