diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp index ea9d33350..af71fe6d5 100644 --- a/fs_mgr/fs_mgr.cpp +++ b/fs_mgr/fs_mgr.cpp @@ -2265,3 +2265,81 @@ std::string fs_mgr_get_super_partition_name(int slot) { } return LP_METADATA_DEFAULT_PARTITION_NAME; } + +bool fs_mgr_create_canonical_mount_point(const std::string& mount_point) { + auto saved_errno = errno; + auto ok = true; + auto created_mount_point = !mkdir(mount_point.c_str(), 0755); + std::string real_mount_point; + if (!Realpath(mount_point, &real_mount_point)) { + ok = false; + PERROR << "failed to realpath(" << mount_point << ")"; + } else if (mount_point != real_mount_point) { + ok = false; + LERROR << "mount point is not canonical: realpath(" << mount_point << ") -> " + << real_mount_point; + } + if (!ok && created_mount_point) { + rmdir(mount_point.c_str()); + } + errno = saved_errno; + return ok; +} + +bool fs_mgr_mount_overlayfs_fstab_entry(const FstabEntry& entry) { + auto overlayfs_valid_result = fs_mgr_overlayfs_valid(); + if (overlayfs_valid_result == OverlayfsValidResult::kNotSupported) { + LERROR << __FUNCTION__ << "(): kernel does not support overlayfs"; + return false; + } + +#if ALLOW_ADBD_DISABLE_VERITY == 0 + // Allowlist the mount point if user build. + static const std::vector kAllowedPaths = { + "/odm", "/odm_dlkm", "/oem", "/product", "/system_ext", "/vendor", "/vendor_dlkm", + }; + static const std::vector kAllowedPrefixes = { + "/mnt/product/", + "/mnt/vendor/", + }; + if (std::none_of(kAllowedPaths.begin(), kAllowedPaths.end(), + [&entry](const auto& path) -> bool { + return entry.mount_point == path || + StartsWith(entry.mount_point, path + "/"); + }) && + std::none_of(kAllowedPrefixes.begin(), kAllowedPrefixes.end(), + [&entry](const auto& prefix) -> bool { + return entry.mount_point != prefix && + StartsWith(entry.mount_point, prefix); + })) { + LERROR << __FUNCTION__ + << "(): mount point is forbidden on user build: " << entry.mount_point; + return false; + } +#endif // ALLOW_ADBD_DISABLE_VERITY == 0 + + if (!fs_mgr_create_canonical_mount_point(entry.mount_point)) { + return false; + } + + auto options = "lowerdir=" + entry.lowerdir; + if (overlayfs_valid_result == OverlayfsValidResult::kOverrideCredsRequired) { + options += ",override_creds=off"; + } + + // Use "overlay-" + entry.blk_device as the mount() source, so that adb-remout-test don't + // confuse this with adb remount overlay, whose device name is "overlay". + // Overlayfs is a pseudo filesystem, so the source device is a symbolic value and isn't used to + // back the filesystem. However the device name would be shown in /proc/mounts. + auto source = "overlay-" + entry.blk_device; + auto report = "__mount(source=" + source + ",target=" + entry.mount_point + ",type=overlay," + + options + ")="; + auto ret = mount(source.c_str(), entry.mount_point.c_str(), "overlay", MS_RDONLY | MS_NOATIME, + options.c_str()); + if (ret) { + PERROR << report << ret; + return false; + } + LINFO << report << ret; + return true; +} diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp index 853b24d8b..d0c89b909 100644 --- a/fs_mgr/fs_mgr_fstab.cpp +++ b/fs_mgr/fs_mgr_fstab.cpp @@ -127,15 +127,16 @@ void ParseMountFlags(const std::string& flags, FstabEntry* entry) { } fs_options.append(flag); - if (entry->fs_type == "f2fs" && StartsWith(flag, "reserve_root=")) { - std::string arg; - if (auto equal_sign = flag.find('='); equal_sign != std::string::npos) { - arg = flag.substr(equal_sign + 1); - } - if (!ParseInt(arg, &entry->reserved_size)) { - LWARNING << "Warning: reserve_root= flag malformed: " << arg; - } else { - entry->reserved_size <<= 12; + if (auto equal_sign = flag.find('='); equal_sign != std::string::npos) { + const auto arg = flag.substr(equal_sign + 1); + if (entry->fs_type == "f2fs" && StartsWith(flag, "reserve_root=")) { + if (!ParseInt(arg, &entry->reserved_size)) { + LWARNING << "Warning: reserve_root= flag malformed: " << arg; + } else { + entry->reserved_size <<= 12; + } + } else if (StartsWith(flag, "lowerdir=")) { + entry->lowerdir = std::move(arg); } } } @@ -298,8 +299,6 @@ void ParseFsMgrFlags(const std::string& flags, FstabEntry* entry) { if (!ParseByteCount(arg, &entry->zram_backingdev_size)) { LWARNING << "Warning: zram_backingdev_size= flag malformed: " << arg; } - } else if (StartsWith(flag, "lowerdir=")) { - entry->lowerdir = arg; } else { LWARNING << "Warning: unknown flag: " << flag; } diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp index 9a94d7912..4d32bda80 100644 --- a/fs_mgr/fs_mgr_overlayfs.cpp +++ b/fs_mgr/fs_mgr_overlayfs.cpp @@ -92,14 +92,6 @@ bool fs_mgr_overlayfs_mount_all(Fstab*) { return false; } -bool fs_mgr_overlayfs_mount_fstab_entry(const std::string&, const std::string&) { - return false; -} - -std::vector fs_mgr_overlayfs_required_devices(Fstab*) { - return {}; -} - bool fs_mgr_overlayfs_setup(const char*, const char*, bool* change, bool) { if (change) *change = false; return false; @@ -1299,18 +1291,6 @@ static void TryMountScratch() { } } -bool fs_mgr_overlayfs_mount_fstab_entry(const std::string& lowers, - const std::string& mount_point) { - if (fs_mgr_overlayfs_invalid()) return false; - - std::string aux = "lowerdir=" + lowers + ",override_creds=off"; - auto rc = mount("overlay", mount_point.c_str(), "overlay", MS_RDONLY | MS_NOATIME, aux.c_str()); - - if (rc == 0) return true; - - return false; -} - bool fs_mgr_overlayfs_mount_all(Fstab* fstab) { auto ret = false; if (fs_mgr_overlayfs_invalid()) return ret; diff --git a/fs_mgr/fs_mgr_vendor_overlay.cpp b/fs_mgr/fs_mgr_vendor_overlay.cpp index 830f0dd01..1372511a7 100644 --- a/fs_mgr/fs_mgr_vendor_overlay.cpp +++ b/fs_mgr/fs_mgr_vendor_overlay.cpp @@ -92,7 +92,7 @@ bool fs_mgr_vendor_overlay_mount(const std::pair& moun } auto report = "__mount(source=overlay,target="s + vendor_mount_point + ",type=overlay," + options + ")="; - auto ret = mount("overlay", vendor_mount_point.c_str(), "overlay", MS_RDONLY | MS_RELATIME, + auto ret = mount("overlay", vendor_mount_point.c_str(), "overlay", MS_RDONLY | MS_NOATIME, options.c_str()); if (ret) { PERROR << report << ret; diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h index 22c02ccf8..4d3ecc9dc 100644 --- a/fs_mgr/include/fs_mgr.h +++ b/fs_mgr/include/fs_mgr.h @@ -131,3 +131,12 @@ int fs_mgr_remount_userdata_into_checkpointing(android::fs_mgr::Fstab* fstab); // Finds the dm_bow device on which this block device is stacked, or returns // empty string std::string fs_mgr_find_bow_device(const std::string& block_device); + +// Creates mount point if not already existed, and checks that mount point is a +// canonical path that doesn't contain any symbolic link or /../. +bool fs_mgr_create_canonical_mount_point(const std::string& mount_point); + +// Like fs_mgr_do_mount_one() but for overlayfs fstab entries. +// Unlike fs_mgr_overlayfs, mount overlayfs without upperdir and workdir, so the +// filesystem cannot be remount read-write. +bool fs_mgr_mount_overlayfs_fstab_entry(const android::fs_mgr::FstabEntry& entry); diff --git a/fs_mgr/include/fs_mgr_overlayfs.h b/fs_mgr/include/fs_mgr_overlayfs.h index ac95ef519..6caab1fee 100644 --- a/fs_mgr/include/fs_mgr_overlayfs.h +++ b/fs_mgr/include/fs_mgr_overlayfs.h @@ -27,8 +27,6 @@ android::fs_mgr::Fstab fs_mgr_overlayfs_candidate_list(const android::fs_mgr::Fstab& fstab); bool fs_mgr_overlayfs_mount_all(android::fs_mgr::Fstab* fstab); -bool fs_mgr_overlayfs_mount_fstab_entry (const std::string& lowers, const std::string& mount_point); -std::vector fs_mgr_overlayfs_required_devices(android::fs_mgr::Fstab* fstab); bool fs_mgr_overlayfs_setup(const char* backing = nullptr, const char* mount_point = nullptr, bool* change = nullptr, bool force = true); bool fs_mgr_overlayfs_teardown(const char* mount_point = nullptr, bool* change = nullptr); diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh index 242fa93fa..9542bc167 100755 --- a/fs_mgr/tests/adb-remount-test.sh +++ b/fs_mgr/tests/adb-remount-test.sh @@ -735,23 +735,46 @@ check_ne() { fi } +[ "USAGE: join_with + +Joins strings with delimiter" ] +join_with() { + if [ "${#}" -lt 2 ]; then + echo + return + fi + local delimiter="${1}" + local result="${2}" + shift 2 + for element in "${@}"; do + result+="${delimiter}${element}" + done + echo "${result}" +} + [ "USAGE: skip_administrative_mounts [data] < /proc/mounts Filters out all administrative (eg: sysfs) mounts uninteresting to the test" ] skip_administrative_mounts() { + local exclude_filesystems=( + "overlay" "tmpfs" "none" "sysfs" "proc" "selinuxfs" "debugfs" "bpf" + "binfmt_misc" "cg2_bpf" "pstore" "tracefs" "adb" "mtp" "ptp" "devpts" + "ramdumpfs" "binder" "securityfs" "functionfs" "rootfs" + ) + local exclude_devices=( + "\/sys\/kernel\/debug" "\/data\/media" "\/dev\/block\/loop[0-9]*" + "${exclude_filesystems[@]}" + ) + local exclude_mount_points=( + "\/cache" "\/mnt\/scratch" "\/mnt\/vendor\/persist" "\/persist" + "\/metadata" + ) if [ "data" = "${1}" ]; then - grep -v " /data " - else - cat - - fi | - grep -v \ - -e "^\(overlay\|tmpfs\|none\|sysfs\|proc\|selinuxfs\|debugfs\|bpf\) " \ - -e "^\(binfmt_misc\|cg2_bpf\|pstore\|tracefs\|adb\|mtp\|ptp\|devpts\) " \ - -e "^\(ramdumpfs\|binder\|/sys/kernel/debug\|securityfs\) " \ - -e " functionfs " \ - -e "^\(/data/media\|/dev/block/loop[0-9]*\) " \ - -e "^rootfs / rootfs rw," \ - -e " /\(cache\|mnt/scratch\|mnt/vendor/persist\|persist\|metadata\) " + exclude_mount_points+=("\/data") + fi + awk '$1 !~ /^('"$(join_with "|" "${exclude_devices[@]}")"')$/ && + $2 !~ /^('"$(join_with "|" "${exclude_mount_points[@]}")"')$/ && + $3 !~ /^('"$(join_with "|" "${exclude_filesystems[@]}")"')$/' } [ "USAGE: skip_unrelated_mounts < /proc/mounts @@ -907,9 +930,11 @@ ACTIVE_SLOT=`get_active_slot` # Acquire list of system partitions +# KISS (assume system partition mount point is "/") PARTITIONS=`adb_su cat /vendor/etc/fstab* devices) { if (devices.empty()) { return true; } - // excluding overlays - for (auto iter = devices.begin(); iter != devices.end(); ) { - if (*iter=="overlay") iter = devices.erase(iter); - else iter++; - } - return block_dev_init_.InitDevices(std::move(devices)); } @@ -426,6 +420,10 @@ bool FirstStageMount::MountPartition(const Fstab::iterator& begin, bool erase_sa *end = begin + 1; } + if (!fs_mgr_create_canonical_mount_point(begin->mount_point)) { + return false; + } + if (begin->fs_mgr_flags.logical) { if (!fs_mgr_update_logical_partition(&(*begin))) { return false; @@ -548,6 +546,7 @@ bool FirstStageMount::MountPartitions() { continue; } + // Handle overlayfs entries later. if (current->fs_type == "overlay") { ++current; continue; @@ -577,6 +576,12 @@ bool FirstStageMount::MountPartitions() { current = end; } + for (const auto& entry : fstab_) { + if (entry.fs_type == "overlay") { + fs_mgr_mount_overlayfs_fstab_entry(entry); + } + } + // If we don't see /system or / in the fstab, then we need to create an root entry for // overlayfs. if (!GetEntryForMountPoint(&fstab_, "/system") && !GetEntryForMountPoint(&fstab_, "/")) { @@ -602,13 +607,6 @@ bool FirstStageMount::MountPartitions() { }; MapScratchPartitionIfNeeded(&fstab_, init_devices); - for (auto current = fstab_.begin(); current != fstab_.end(); ) { - if (current->fs_type == "overlay") { - fs_mgr_overlayfs_mount_fstab_entry(current->lowerdir, current->mount_point); - } - ++current; - } - fs_mgr_overlayfs_mount_all(&fstab_); return true; @@ -695,6 +693,10 @@ bool FirstStageMountVBootV1::GetDmVerityDevices(std::set* devices) // Includes the partition names of fstab records. // Notes that fstab_rec->blk_device has A/B suffix updated by fs_mgr when A/B is used. for (const auto& fstab_entry : fstab_) { + // Skip pseudo filesystems. + if (fstab_entry.fs_type == "overlay") { + continue; + } if (!fstab_entry.fs_mgr_flags.logical) { devices->emplace(basename(fstab_entry.blk_device.c_str())); } @@ -757,6 +759,10 @@ bool FirstStageMountVBootV2::GetDmVerityDevices(std::set* devices) if (fstab_entry.fs_mgr_flags.avb) { need_dm_verity_ = true; } + // Skip pseudo filesystems. + if (fstab_entry.fs_type == "overlay") { + continue; + } if (fstab_entry.fs_mgr_flags.logical) { // Don't try to find logical partitions via uevent regeneration. logical_partitions.emplace(basename(fstab_entry.blk_device.c_str()));