• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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