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
This commit is contained in:
Kiyoung Kim 2019-12-16 14:31:04 +09:00
parent 1cdcc5f7e8
commit e4d3f2123f
3 changed files with 77 additions and 2 deletions

View file

@ -59,6 +59,7 @@
#include <fs_mgr.h>
#include <fscrypt/fscrypt.h>
#include <libgsi/libgsi.h>
#include <logwrap/logwrap.h>
#include <selinux/android.h>
#include <selinux/label.h>
#include <selinux/selinux.h>
@ -1176,6 +1177,42 @@ static Result<void> do_mark_post_data(const BuiltinArguments& args) {
return {};
}
static Result<void> 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<void> 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<void> parse_apex_configs() {
glob_t glob_result;
static constexpr char glob_pattern[] = "/apex/*/etc/*.rc";
@ -1251,6 +1288,12 @@ static Result<void> 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}}},

View file

@ -151,6 +151,20 @@ static bool ActivateFlattenedApexesIfPossible() {
return true;
}
static Result<void> 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";

View file

@ -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