Loading init/builtins.cpp +50 −0 Original line number Diff line number Diff line Loading @@ -1262,6 +1262,51 @@ static Result<void> MountLinkerConfigForDefaultNamespace() { return {}; } static Result<void> MountApexRootForDefaultNamespace() { auto mount_namespace_id = GetCurrentMountNamespace(); if (!mount_namespace_id.ok()) { return mount_namespace_id.error(); } // There's nothing to do if it's still in the bootstrap mount namespace. // This happens when we don't need to update APEXes (e.g. Microdroid) // where bootstrap mount namespace == default mount namespace. if (mount_namespace_id.value() == NS_BOOTSTRAP) { return {}; } // Now, we're in the "default" mount namespace and need a fresh /apex for // the default mount namespace. // // At this point, there are two mounts at the same mount point: /apex // - to tmpfs (private) // - to /bootstrap-apex (shared) // // We need unmount the second mount so that /apex in the default mount // namespace becomes RW/empty and "private" (we don't want mount events to // propagate to the bootstrap mount namespace). // // Likewise, we don't want the unmount event itself to propagate to the // bootstrap mount namespace. Otherwise, /apex in the bootstrap mount // namespace would become empty due to the unmount. // // Hence, before unmounting, we make /apex (the second one) "private" first. // so that the unmouting below doesn't affect to the bootstrap mount namespace. if (mount(nullptr, "/apex", nullptr, MS_PRIVATE | MS_REC, nullptr) == -1) { return ErrnoError() << "Failed to remount /apex as private"; } // Now we can unmount /apex (bind-mount to /bootstrap-apex). This only affects // in the default mount namespace and /apex is now seen as tmpfs mount. // Note that /apex in the bootstrap mount namespace is still a bind-mount to // /bootstrap-apex and holds the APEX mounts. if (umount2("/apex", MNT_DETACH) == -1) { return ErrnoError() << "Failed to umount /apex"; } return {}; } static Result<void> do_update_linker_config(const BuiltinArguments&) { return GenerateLinkerConfiguration(); } Loading Loading @@ -1315,6 +1360,11 @@ static Result<void> do_enter_default_mount_ns(const BuiltinArguments& args) { if (auto result = SwitchToMountNamespaceIfNeeded(NS_DEFAULT); !result.ok()) { return result.error(); } if (auto result = MountApexRootForDefaultNamespace(); !result.ok()) { return result.error(); } if (auto result = MountLinkerConfigForDefaultNamespace(); !result.ok()) { return result.error(); } Loading init/init.cpp +6 −0 Original line number Diff line number Diff line Loading @@ -832,6 +832,12 @@ static void MountExtraFilesystems() { CHECKCALL(mount("tmpfs", "/apex", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV, "mode=0755,uid=0,gid=0")); if (NeedsTwoMountNamespaces()) { // /bootstrap-apex is used to mount "bootstrap" APEXes. CHECKCALL(mount("tmpfs", "/bootstrap-apex", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV, "mode=0755,uid=0,gid=0")); } // /linkerconfig is used to keep generated linker configuration CHECKCALL(mount("tmpfs", "/linkerconfig", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV, "mode=0755,uid=0,gid=0")); Loading init/mount_namespace.cpp +30 −9 Original line number Diff line number Diff line Loading @@ -66,15 +66,6 @@ static std::string GetMountNamespaceId() { return ret; } // In case we have two sets of APEXes (non-updatable, updatable), we need two separate mount // namespaces. static bool NeedsTwoMountNamespaces() { if (IsRecoveryMode()) return false; // In microdroid, there's only one set of APEXes in built-in directories include block devices. if (IsMicrodroid()) return false; return true; } static android::base::unique_fd bootstrap_ns_fd; static android::base::unique_fd default_ns_fd; Loading @@ -83,6 +74,15 @@ static std::string default_ns_id; } // namespace // In case we have two sets of APEXes (non-updatable, updatable), we need two separate mount // namespaces. bool NeedsTwoMountNamespaces() { if (IsRecoveryMode()) return false; // In microdroid, there's only one set of APEXes in built-in directories include block devices. if (IsMicrodroid()) return false; return true; } bool SetupMountNamespaces() { // Set the propagation type of / as shared so that any mounting event (e.g. // /data) is by default visible to all processes. When private mounting is Loading @@ -96,6 +96,27 @@ bool SetupMountNamespaces() { // the bootstrap namespace get APEXes from the read-only partition. if (!(ChangeMount("/apex", MS_PRIVATE))) return false; // However, some components (e.g. servicemanager) need to access bootstrap // APEXes from the default mount namespace. To achieve that, we bind-mount // /apex with /bootstrap-apex (not private) in the bootstrap mount namespace. // Bootstrap APEXes are mounted in /apex and also visible in /bootstrap-apex. // In the default mount namespace, we detach /bootstrap-apex from /apex and // bootstrap APEXes are still be visible in /bootstrap-apex. // // The end result will look like: // in the bootstrap mount namespace: // /apex (== /bootstrap-apex) // {bootstrap APEXes from the read-only partition} // // in the default mount namespace: // /bootstrap-apex // {bootstrap APEXes from the read-only partition} // /apex // {APEXes, can be from /data partition} if (NeedsTwoMountNamespaces()) { if (!(BindMount("/bootstrap-apex", "/apex"))) return false; } // /linkerconfig is a private mountpoint to give a different linker configuration // based on the mount namespace. Subdirectory will be bind-mounted based on current mount // namespace Loading init/mount_namespace.h +3 −0 Original line number Diff line number Diff line Loading @@ -24,9 +24,12 @@ namespace init { enum MountNamespace { NS_BOOTSTRAP, NS_DEFAULT }; bool SetupMountNamespaces(); base::Result<void> SwitchToMountNamespaceIfNeeded(MountNamespace target_mount_namespace); base::Result<MountNamespace> GetCurrentMountNamespace(); bool NeedsTwoMountNamespaces(); } // namespace init } // namespace android init/selinux.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -766,7 +766,7 @@ void SelinuxRestoreContext() { selinux_android_restorecon("/dev/device-mapper", 0); selinux_android_restorecon("/apex", 0); selinux_android_restorecon("/bootstrap-apex", 0); selinux_android_restorecon("/linkerconfig", 0); // adb remount, snapshot-based updates, and DSUs all create files during Loading Loading
init/builtins.cpp +50 −0 Original line number Diff line number Diff line Loading @@ -1262,6 +1262,51 @@ static Result<void> MountLinkerConfigForDefaultNamespace() { return {}; } static Result<void> MountApexRootForDefaultNamespace() { auto mount_namespace_id = GetCurrentMountNamespace(); if (!mount_namespace_id.ok()) { return mount_namespace_id.error(); } // There's nothing to do if it's still in the bootstrap mount namespace. // This happens when we don't need to update APEXes (e.g. Microdroid) // where bootstrap mount namespace == default mount namespace. if (mount_namespace_id.value() == NS_BOOTSTRAP) { return {}; } // Now, we're in the "default" mount namespace and need a fresh /apex for // the default mount namespace. // // At this point, there are two mounts at the same mount point: /apex // - to tmpfs (private) // - to /bootstrap-apex (shared) // // We need unmount the second mount so that /apex in the default mount // namespace becomes RW/empty and "private" (we don't want mount events to // propagate to the bootstrap mount namespace). // // Likewise, we don't want the unmount event itself to propagate to the // bootstrap mount namespace. Otherwise, /apex in the bootstrap mount // namespace would become empty due to the unmount. // // Hence, before unmounting, we make /apex (the second one) "private" first. // so that the unmouting below doesn't affect to the bootstrap mount namespace. if (mount(nullptr, "/apex", nullptr, MS_PRIVATE | MS_REC, nullptr) == -1) { return ErrnoError() << "Failed to remount /apex as private"; } // Now we can unmount /apex (bind-mount to /bootstrap-apex). This only affects // in the default mount namespace and /apex is now seen as tmpfs mount. // Note that /apex in the bootstrap mount namespace is still a bind-mount to // /bootstrap-apex and holds the APEX mounts. if (umount2("/apex", MNT_DETACH) == -1) { return ErrnoError() << "Failed to umount /apex"; } return {}; } static Result<void> do_update_linker_config(const BuiltinArguments&) { return GenerateLinkerConfiguration(); } Loading Loading @@ -1315,6 +1360,11 @@ static Result<void> do_enter_default_mount_ns(const BuiltinArguments& args) { if (auto result = SwitchToMountNamespaceIfNeeded(NS_DEFAULT); !result.ok()) { return result.error(); } if (auto result = MountApexRootForDefaultNamespace(); !result.ok()) { return result.error(); } if (auto result = MountLinkerConfigForDefaultNamespace(); !result.ok()) { return result.error(); } Loading
init/init.cpp +6 −0 Original line number Diff line number Diff line Loading @@ -832,6 +832,12 @@ static void MountExtraFilesystems() { CHECKCALL(mount("tmpfs", "/apex", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV, "mode=0755,uid=0,gid=0")); if (NeedsTwoMountNamespaces()) { // /bootstrap-apex is used to mount "bootstrap" APEXes. CHECKCALL(mount("tmpfs", "/bootstrap-apex", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV, "mode=0755,uid=0,gid=0")); } // /linkerconfig is used to keep generated linker configuration CHECKCALL(mount("tmpfs", "/linkerconfig", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV, "mode=0755,uid=0,gid=0")); Loading
init/mount_namespace.cpp +30 −9 Original line number Diff line number Diff line Loading @@ -66,15 +66,6 @@ static std::string GetMountNamespaceId() { return ret; } // In case we have two sets of APEXes (non-updatable, updatable), we need two separate mount // namespaces. static bool NeedsTwoMountNamespaces() { if (IsRecoveryMode()) return false; // In microdroid, there's only one set of APEXes in built-in directories include block devices. if (IsMicrodroid()) return false; return true; } static android::base::unique_fd bootstrap_ns_fd; static android::base::unique_fd default_ns_fd; Loading @@ -83,6 +74,15 @@ static std::string default_ns_id; } // namespace // In case we have two sets of APEXes (non-updatable, updatable), we need two separate mount // namespaces. bool NeedsTwoMountNamespaces() { if (IsRecoveryMode()) return false; // In microdroid, there's only one set of APEXes in built-in directories include block devices. if (IsMicrodroid()) return false; return true; } bool SetupMountNamespaces() { // Set the propagation type of / as shared so that any mounting event (e.g. // /data) is by default visible to all processes. When private mounting is Loading @@ -96,6 +96,27 @@ bool SetupMountNamespaces() { // the bootstrap namespace get APEXes from the read-only partition. if (!(ChangeMount("/apex", MS_PRIVATE))) return false; // However, some components (e.g. servicemanager) need to access bootstrap // APEXes from the default mount namespace. To achieve that, we bind-mount // /apex with /bootstrap-apex (not private) in the bootstrap mount namespace. // Bootstrap APEXes are mounted in /apex and also visible in /bootstrap-apex. // In the default mount namespace, we detach /bootstrap-apex from /apex and // bootstrap APEXes are still be visible in /bootstrap-apex. // // The end result will look like: // in the bootstrap mount namespace: // /apex (== /bootstrap-apex) // {bootstrap APEXes from the read-only partition} // // in the default mount namespace: // /bootstrap-apex // {bootstrap APEXes from the read-only partition} // /apex // {APEXes, can be from /data partition} if (NeedsTwoMountNamespaces()) { if (!(BindMount("/bootstrap-apex", "/apex"))) return false; } // /linkerconfig is a private mountpoint to give a different linker configuration // based on the mount namespace. Subdirectory will be bind-mounted based on current mount // namespace Loading
init/mount_namespace.h +3 −0 Original line number Diff line number Diff line Loading @@ -24,9 +24,12 @@ namespace init { enum MountNamespace { NS_BOOTSTRAP, NS_DEFAULT }; bool SetupMountNamespaces(); base::Result<void> SwitchToMountNamespaceIfNeeded(MountNamespace target_mount_namespace); base::Result<MountNamespace> GetCurrentMountNamespace(); bool NeedsTwoMountNamespaces(); } // namespace init } // namespace android
init/selinux.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -766,7 +766,7 @@ void SelinuxRestoreContext() { selinux_android_restorecon("/dev/device-mapper", 0); selinux_android_restorecon("/apex", 0); selinux_android_restorecon("/bootstrap-apex", 0); selinux_android_restorecon("/linkerconfig", 0); // adb remount, snapshot-based updates, and DSUs all create files during Loading