Merge "Generate linkerconfig per mount namespaces"
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 62a19ab..3c32d8b 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -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 @@
     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 @@
     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 @@
         {"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 648b3bb..93eb244 100644
--- a/init/mount_namespace.cpp
+++ b/init/mount_namespace.cpp
@@ -151,6 +151,20 @@
     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 @@
             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 803d44a..9cf11a4 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -38,9 +38,18 @@
     # 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 @@
     # 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