xref: /aosp_15_r20/system/core/fs_mgr/fs_mgr_overlayfs_mount.cpp (revision 00c7fec1bb09f3284aad6a6f96d2f63dfc3650ad)
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