From 566c65239f1cf3fcb0d8745715e5ef1083d4bd3a Mon Sep 17 00:00:00 2001 From: Jooyung Han Date: Wed, 9 Aug 2023 07:05:31 +0000 Subject: [PATCH] Use /bootstrap-apex for bootstrap APEXes This new directory is bind-mounted to /apex in the bootstrap mount namespace so that apexd-bootstrap mounts bootstrap APEXes there via /apex. The directory is shared between two mount namespaces, hence visible in the default mount namespace. Bug: 290148078 Test: VendorApexHostTestCases Change-Id: I841480e41be8def5a4c6a4aa874c4e21465a71d3 --- init/init.cpp | 6 ++++++ init/mount_namespace.cpp | 35 ++++++++++++++++++++++++++--------- init/mount_namespace.h | 3 +++ init/selinux.cpp | 2 +- rootdir/Android.mk | 2 +- 5 files changed, 37 insertions(+), 11 deletions(-) diff --git a/init/init.cpp b/init/init.cpp index da63fdc3b..4bb8eecb9 100644 --- a/init/init.cpp +++ b/init/init.cpp @@ -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")); diff --git a/init/mount_namespace.cpp b/init/mount_namespace.cpp index 5b53d5092..7918f23e9 100644 --- a/init/mount_namespace.cpp +++ b/init/mount_namespace.cpp @@ -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; @@ -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 @@ -163,6 +163,23 @@ bool SetupMountNamespaces() { PLOG(ERROR) << "Cannot switch back to bootstrap mount namespace"; return false; } + + // Some components (e.g. servicemanager) need to access bootstrap + // APEXes from the default mount namespace. To achieve that, we bind-mount + // /apex to /bootstrap-apex in the bootstrap mount namespace. Since /bootstrap-apex + // is "shared", the mounts are visible in the default mount namespace as well. + // + // 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 (!(BindMount("/bootstrap-apex", "/apex"))) return false; } else { // Otherwise, default == bootstrap default_ns_fd.reset(OpenMountNamespace()); diff --git a/init/mount_namespace.h b/init/mount_namespace.h index 5e3dab241..43c5476a6 100644 --- a/init/mount_namespace.h +++ b/init/mount_namespace.h @@ -24,9 +24,12 @@ namespace init { enum MountNamespace { NS_BOOTSTRAP, NS_DEFAULT }; bool SetupMountNamespaces(); + base::Result SwitchToMountNamespaceIfNeeded(MountNamespace target_mount_namespace); base::Result GetCurrentMountNamespace(); +bool NeedsTwoMountNamespaces(); + } // namespace init } // namespace android diff --git a/init/selinux.cpp b/init/selinux.cpp index f34474f85..ebdcaa62d 100644 --- a/init/selinux.cpp +++ b/init/selinux.cpp @@ -757,7 +757,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 diff --git a/rootdir/Android.mk b/rootdir/Android.mk index 3362872c0..52187536f 100644 --- a/rootdir/Android.mk +++ b/rootdir/Android.mk @@ -91,7 +91,7 @@ endif # # create some directories (some are mount points) and symlinks LOCAL_POST_INSTALL_CMD := mkdir -p $(addprefix $(TARGET_ROOT_OUT)/, \ - dev proc sys system data data_mirror odm oem acct config storage mnt apex debug_ramdisk \ + dev proc sys system data data_mirror odm oem acct config storage mnt apex bootstrap-apex debug_ramdisk \ linkerconfig second_stage_resources postinstall $(BOARD_ROOT_EXTRA_FOLDERS)); \ ln -sf /system/bin $(TARGET_ROOT_OUT)/bin; \ ln -sf /system/etc $(TARGET_ROOT_OUT)/etc; \