second-stage-init: Don't move submounts when mounting overlayfs

Right now there is a bug in second-stage-init that screws up the
overlayfs overrides. This happens because:
1. second-stage-init mount_all might be executed in the "bootstrap"
   mount namespace.
2. In order to move (MS_MOVE) submounts in fs_mgr_overlayfs_mount_all(),
   we change the mount propagation type of overridden filesystems to
   MS_PRIVATE.
3. This means that the "default" mount namespace would not receive the
   mount events of the overlayfs overrides.
4. After /data is mounted, init would switch to the "default" namespace.
   This means any new processes spawned after this period would not be
   able to see the overlayfs overrides.

We fix this by changing the mount order of second-stage-init mount_all
to mount the overlayfs override of a partition immediately after the
partition is mounted. This way we don't need to move any submounts as
there can't be any, thus we don't need to set any mountpoint to
MS_PRIVATE so the mount event of the overlayfs would be propagated to
the "default" mount namespace, too.

Bug: 309407859
Bug: 306124139
Test: adb-remount-test
Test: verify that overlayfs tookover successfully from second-stage-init
Change-Id: If2ff4852516292ccbc7abdeebe0e9a7c1c7ba606
This commit is contained in:
Yi-Yo Chiang 2023-11-23 14:47:58 +08:00
parent bc907c00f4
commit 28113cf3f6
3 changed files with 63 additions and 23 deletions

View file

@ -1388,6 +1388,8 @@ MountAllResult fs_mgr_mount_all(Fstab* fstab, int mount_mode) {
return {FS_MGR_MNTALL_FAIL, userdata_mounted};
}
bool scratch_can_be_mounted = true;
// Keep i int to prevent unsigned integer overflow from (i = top_idx - 1),
// where top_idx is 0. It will give SIGABRT
for (int i = 0; i < static_cast<int>(fstab->size()); i++) {
@ -1520,6 +1522,9 @@ MountAllResult fs_mgr_mount_all(Fstab* fstab, int mount_mode) {
if (current_entry.mount_point == "/data") {
userdata_mounted = true;
}
MountOverlayfs(attempted_entry, &scratch_can_be_mounted);
// Success! Go get the next one.
continue;
}
@ -1604,10 +1609,6 @@ MountAllResult fs_mgr_mount_all(Fstab* fstab, int mount_mode) {
set_type_property(encryptable);
#if ALLOW_ADBD_DISABLE_VERITY == 1 // "userdebug" build
fs_mgr_overlayfs_mount_all(fstab);
#endif
if (error_count) {
return {FS_MGR_MNTALL_FAIL, userdata_mounted};
} else {

View file

@ -302,6 +302,25 @@ static bool fs_mgr_overlayfs_move_mount(const std::string& source, const std::st
return true;
}
static bool fs_mgr_overlayfs_mount(const std::string& mount_point, const std::string& options) {
auto report = "__mount(source=overlay,target="s + mount_point + ",type=overlay";
for (const auto& opt : android::base::Split(options, ",")) {
if (android::base::StartsWith(opt, kUpperdirOption)) {
report = report + "," + opt;
break;
}
}
report = report + ")=";
auto ret = mount("overlay", mount_point.c_str(), "overlay", MS_RDONLY | MS_NOATIME,
options.c_str());
if (ret) {
PERROR << report << ret;
} else {
LINFO << report << ret;
}
return !ret;
}
struct mount_info {
std::string mount_point;
bool shared_flag;
@ -488,25 +507,7 @@ static bool fs_mgr_overlayfs_mount_one(const FstabEntry& fstab_entry) {
moved_mounts.push_back(std::move(new_entry));
}
// hijack __mount() report format to help triage
auto report = "__mount(source=overlay,target="s + mount_point + ",type=overlay";
const auto opt_list = android::base::Split(options, ",");
for (const auto& opt : opt_list) {
if (android::base::StartsWith(opt, kUpperdirOption)) {
report = report + "," + opt;
break;
}
}
report = report + ")=";
auto ret = mount("overlay", mount_point.c_str(), "overlay", MS_RDONLY | MS_NOATIME,
options.c_str());
if (ret) {
retval = false;
PERROR << report << ret;
} else {
LINFO << report << ret;
}
retval &= fs_mgr_overlayfs_mount(mount_point, options);
// Move submounts back.
for (const auto& entry : moved_mounts) {
@ -814,3 +815,38 @@ bool fs_mgr_overlayfs_already_mounted(const std::string& mount_point, bool overl
}
return false;
}
namespace android {
namespace fs_mgr {
void MountOverlayfs(const FstabEntry& fstab_entry, bool* scratch_can_be_mounted) {
if (!OverlayfsSetupAllowed()) {
return;
}
const auto candidates = fs_mgr_overlayfs_candidate_list({fstab_entry});
if (candidates.empty()) {
return;
}
const auto& entry = candidates.front();
if (fs_mgr_is_verity_enabled(entry)) {
return;
}
const auto mount_point = fs_mgr_mount_point(entry.mount_point);
if (fs_mgr_overlayfs_already_mounted(mount_point)) {
return;
}
if (*scratch_can_be_mounted) {
*scratch_can_be_mounted = false;
if (!fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) {
TryMountScratch();
}
}
const auto options = fs_mgr_get_overlayfs_options(entry);
if (options.empty()) {
return;
}
fs_mgr_overlayfs_mount(mount_point, options);
}
} // namespace fs_mgr
} // namespace android

View file

@ -30,6 +30,9 @@ bool fs_mgr_overlayfs_is_setup();
namespace android {
namespace fs_mgr {
// Mount the overlayfs override for |fstab_entry|.
void MountOverlayfs(const FstabEntry& fstab_entry, bool* scratch_can_be_mounted);
void MapScratchPartitionIfNeeded(Fstab* fstab,
const std::function<bool(const std::set<std::string>&)>& init);