From e4d3f2123f8c241d457f235eb7b7b5ad401a221d Mon Sep 17 00:00:00 2001 From: Kiyoung Kim Date: Mon, 16 Dec 2019 14:31:04 +0900 Subject: [PATCH] Generate linkerconfig per mount namespaces There are two namespaces from init - bootstrap and default - and those will have different set of APEX modules. To support difference between two namespaces, linker config should be generated per namespace and each namespace should use its own linker configuration. As a first step of the work, this change will create different mount point for each namespace, and re-generate linker config after APEX mount from each namespaces. Bug: 144664390 Test: m -j passed & tested from cuttlefish Change-Id: Iac2e222376ec4b0ced6c29eed18b21d39ff0b1ba --- init/builtins.cpp | 44 ++++++++++++++++++++++++++++++++++++++++ init/mount_namespace.cpp | 19 +++++++++++++++++ rootdir/init.rc | 16 +++++++++++++-- 3 files changed, 77 insertions(+), 2 deletions(-) diff --git a/init/builtins.cpp b/init/builtins.cpp index 62a19abc5..3c32d8ba2 100644 --- a/init/builtins.cpp +++ b/init/builtins.cpp @@ -59,6 +59,7 @@ #include #include #include +#include #include #include #include @@ -1176,6 +1177,42 @@ static Result do_mark_post_data(const BuiltinArguments& args) { return {}; } +static Result GenerateLinkerConfiguration() { + const char* linkerconfig_binary = "/system/bin/linkerconfig"; + const char* linkerconfig_target = "/linkerconfig/ld.config.txt"; + const char* arguments[] = {linkerconfig_binary, "--target", linkerconfig_target}; + + if (logwrap_fork_execvp(arraysize(arguments), arguments, nullptr, false, LOG_KLOG, false, + nullptr) != 0) { + return ErrnoError() << "failed to execute linkerconfig"; + } + + mode_t mode = get_mode("0444"); + if (fchmodat(AT_FDCWD, linkerconfig_target, mode, AT_SYMLINK_NOFOLLOW) < 0) { + return ErrnoErrorIgnoreEnoent() << "fchmodat() failed"; + } + + LOG(INFO) << "linkerconfig generated " << linkerconfig_target + << " with mounted APEX modules info"; + + return {}; +} + +static bool IsApexUpdatable() { + static bool updatable = android::sysprop::ApexProperties::updatable().value_or(false); + return updatable; +} + +static Result do_update_linker_config(const BuiltinArguments&) { + // If APEX is not updatable, then all APEX information are already included in the first + // linker config generation, so there is no need to update linker configuration again. + if (IsApexUpdatable()) { + return GenerateLinkerConfiguration(); + } + + return {}; +} + static Result parse_apex_configs() { glob_t glob_result; static constexpr char glob_pattern[] = "/apex/*/etc/*.rc"; @@ -1251,6 +1288,12 @@ static Result do_perform_apex_config(const BuiltinArguments& args) { if (!parse_configs) { return parse_configs.error(); } + + auto update_linker_config = do_update_linker_config(args); + if (!update_linker_config) { + return update_linker_config.error(); + } + return {}; } @@ -1317,6 +1360,7 @@ const BuiltinFunctionMap& GetBuiltinFunctionMap() { {"perform_apex_config", {0, 0, {false, do_perform_apex_config}}}, {"umount", {1, 1, {false, do_umount}}}, {"umount_all", {1, 1, {false, do_umount_all}}}, + {"update_linker_config", {0, 0, {false, do_update_linker_config}}}, {"readahead", {1, 2, {true, do_readahead}}}, {"remount_userdata", {0, 0, {false, do_remount_userdata}}}, {"restart", {1, 1, {false, do_restart}}}, diff --git a/init/mount_namespace.cpp b/init/mount_namespace.cpp index 648b3bb0e..93eb2440c 100644 --- a/init/mount_namespace.cpp +++ b/init/mount_namespace.cpp @@ -151,6 +151,20 @@ static bool ActivateFlattenedApexesIfPossible() { return true; } +static Result MountLinkerConfigForDefaultNamespace() { + // No need to mount linkerconfig for default mount namespace if the path does not exist (which + // would mean it is already mounted) + if (access("/linkerconfig/default", 0) != 0) { + return {}; + } + + if (mount("/linkerconfig/default", "/linkerconfig", nullptr, MS_BIND | MS_REC, nullptr) != 0) { + return ErrnoError() << "Failed to mount linker configuration for default mount namespace."; + } + + return {}; +} + static android::base::unique_fd bootstrap_ns_fd; static android::base::unique_fd default_ns_fd; @@ -222,6 +236,11 @@ bool SwitchToDefaultMountNamespace() { PLOG(ERROR) << "Failed to switch back to the default mount namespace."; return false; } + + if (auto result = MountLinkerConfigForDefaultNamespace(); !result) { + LOG(ERROR) << result.error(); + return false; + } } LOG(INFO) << "Switched to default mount namespace"; diff --git a/rootdir/init.rc b/rootdir/init.rc index b89c45e0d..26b6877a3 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -38,9 +38,18 @@ on early-init # Allow up to 32K FDs per process setrlimit nofile 32768 32768 + # Set up linker config subdirectories based on mount namespaces + mkdir /linkerconfig/bootstrap 0755 + mkdir /linkerconfig/default 0755 + # Generate ld.config.txt for early executed processes - exec -- /system/bin/linkerconfig --target /linkerconfig/ld.config.txt - chmod 444 /linkerconfig/ld.config.txt + exec -- /system/bin/linkerconfig --target /linkerconfig/bootstrap/ld.config.txt + chmod 644 /linkerconfig/bootstrap/ld.config.txt + copy /linkerconfig/bootstrap/ld.config.txt /linkerconfig/default/ld.config.txt + chmod 644 /linkerconfig/default/ld.config.txt + + # Mount bootstrap linker configuration as current + mount none /linkerconfig/bootstrap /linkerconfig bind rec start ueventd @@ -49,6 +58,9 @@ on early-init # the libraries are available to the processes started after this statement. exec_start apexd-bootstrap + # Generate linker config based on apex mounted in bootstrap namespace + update_linker_config + # These must already exist by the time boringssl_self_test32 / boringssl_self_test64 run. mkdir /dev/boringssl 0755 root root mkdir /dev/boringssl/selftest 0755 root root