summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--linker/linker.cpp63
1 files changed, 63 insertions, 0 deletions
diff --git a/linker/linker.cpp b/linker/linker.cpp
index b860f70b9..146937a6f 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -882,6 +882,60 @@ typedef linked_list_t<soinfo> SoinfoLinkedList;
typedef linked_list_t<const char> StringLinkedList;
typedef linked_list_t<LoadTask> LoadTaskList;
+static soinfo* find_library(const char* name, int rtld_flags, const android_dlextinfo* extinfo);
+
+// g_ld_all_shim_libs maintains the references to memory as it used
+// in the soinfo structures and in the g_active_shim_libs list.
+
+static std::vector<std::string> g_ld_all_shim_libs;
+
+// g_active_shim_libs are all shim libs that are still eligible
+// to be loaded. We must remove a shim lib from the list before
+// we load the library to avoid recursive loops (load shim libA
+// for libB where libA also links against libB).
+
+static linked_list_t<const std::string> g_active_shim_libs;
+
+static void parse_LD_SHIM_LIBS(const char* path) {
+ parse_path(path, " :", &g_ld_all_shim_libs);
+ for (const auto& pair : g_ld_all_shim_libs) {
+ g_active_shim_libs.push_back(&pair);
+ }
+}
+
+static bool shim_lib_matches(const char *shim_lib, const char *realpath) {
+ const char *sep = strchr(shim_lib, '|');
+ return sep != nullptr && strncmp(realpath, shim_lib, sep - shim_lib) == 0;
+}
+
+template<typename F>
+static bool shim_libs_for_each(const char *const path, F action) {
+ if (path == nullptr) return true;
+ INFO("finding shim libs for \"%s\"\n", path);
+ std::vector<const std::string *> matched;
+
+ g_active_shim_libs.for_each([&](const std::string *a_pair) {
+ const char *pair = a_pair->c_str();
+ if (shim_lib_matches(pair, path)) {
+ matched.push_back(a_pair);
+ }
+ });
+
+ g_active_shim_libs.remove_if([&](const std::string *a_pair) {
+ const char *pair = a_pair->c_str();
+ return shim_lib_matches(pair, path);
+ });
+
+ for (const auto& one_pair : matched) {
+ const char* const pair = one_pair->c_str();
+ const char* sep = strchr(pair, '|');
+ INFO("found shim lib \"%s\"\n", sep+1);
+ soinfo *child = find_library(sep+1, RTLD_GLOBAL, nullptr);
+ if (! child) return false;
+ action(child);
+ }
+ return true;
+}
// This function walks down the tree of soinfo dependencies
// in breadth-first order and
@@ -914,6 +968,12 @@ static bool walk_dependencies_tree(soinfo* root_soinfos[], size_t root_soinfos_s
si->get_children().for_each([&](soinfo* child) {
visit_list.push_back(child);
});
+
+ if (!shim_libs_for_each(si->get_realpath(), [&](soinfo* child) {
+ visit_list.push_back(child);
+ })) {
+ return false;
+ }
}
return true;
@@ -3154,9 +3214,11 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(
// doesn't cost us anything.
const char* ldpath_env = nullptr;
const char* ldpreload_env = nullptr;
+ const char* ldshim_libs_env = nullptr;
if (!getauxval(AT_SECURE)) {
ldpath_env = getenv("LD_LIBRARY_PATH");
ldpreload_env = getenv("LD_PRELOAD");
+ ldshim_libs_env = getenv("LD_SHIM_LIBS");
}
INFO("[ android linker & debugger ]");
@@ -3210,6 +3272,7 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(
// Use LD_LIBRARY_PATH and LD_PRELOAD (but only if we aren't setuid/setgid).
parse_LD_LIBRARY_PATH(ldpath_env);
parse_LD_PRELOAD(ldpreload_env);
+ parse_LD_SHIM_LIBS(ldshim_libs_env);
somain = si;