aboutsummaryrefslogtreecommitdiffstats
path: root/linker
diff options
context:
space:
mode:
Diffstat (limited to 'linker')
-rw-r--r--linker/linker.cpp64
-rw-r--r--linker/linker.h2
-rw-r--r--linker/linker_main.cpp3
3 files changed, 69 insertions, 0 deletions
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 4ebb476aa..f07285d77 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -691,6 +691,68 @@ enum walk_action_result_t : uint32_t {
kWalkSkip = 2
};
+static soinfo* find_library(android_namespace_t* ns,
+ const char* name, int rtld_flags,
+ const android_dlextinfo* extinfo,
+ soinfo* needed_by);
+
+// 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.
+
+typedef std::pair<std::string, std::string> ShimDescriptor;
+static std::vector<ShimDescriptor> 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 ShimDescriptor> g_active_shim_libs;
+
+static void reset_g_active_shim_libs(void) {
+ g_active_shim_libs.clear();
+ for (const auto& pair : g_ld_all_shim_libs) {
+ g_active_shim_libs.push_back(&pair);
+ }
+}
+
+void parse_LD_SHIM_LIBS(const char* path) {
+ g_ld_all_shim_libs.clear();
+ if (path != nullptr) {
+ // We have historically supported ':' as well as ' ' in LD_SHIM_LIBS.
+ for (const auto& pair : android::base::Split(path, " :")) {
+ size_t pos = pair.find('|');
+ if (pos > 0 && pos < pair.length() - 1) {
+ auto desc = std::pair<std::string, std::string>(pair.substr(0, pos), pair.substr(pos + 1));
+ g_ld_all_shim_libs.push_back(desc);
+ }
+ }
+ }
+ reset_g_active_shim_libs();
+}
+
+template<typename F>
+static void for_each_matching_shim(const char *const path, F action) {
+ if (path == nullptr) return;
+ INFO("Finding shim libs for \"%s\"\n", path);
+ std::vector<const ShimDescriptor *> matched;
+
+ g_active_shim_libs.for_each([&](const ShimDescriptor *a_pair) {
+ if (a_pair->first == path) {
+ matched.push_back(a_pair);
+ }
+ });
+
+ g_active_shim_libs.remove_if([&](const ShimDescriptor *a_pair) {
+ return a_pair->first == path;
+ });
+
+ for (const auto& one_pair : matched) {
+ INFO("Injecting shim lib \"%s\" as needed for %s", one_pair->second.c_str(), path);
+ action(one_pair->second.c_str());
+ }
+}
+
// This function walks down the tree of soinfo dependencies
// in breadth-first order and
// * calls action(soinfo* si) for each node, and
@@ -1108,6 +1170,7 @@ const char* fix_dt_needed(const char* dt_needed, const char* sopath __unused) {
template<typename F>
static void for_each_dt_needed(const ElfReader& elf_reader, F action) {
+ for_each_matching_shim(elf_reader.name(), action);
for (const ElfW(Dyn)* d = elf_reader.dynamic(); d->d_tag != DT_NULL; ++d) {
if (d->d_tag == DT_NEEDED) {
action(fix_dt_needed(elf_reader.get_string(d->d_un.d_val), elf_reader.name()));
@@ -1967,6 +2030,7 @@ void* do_dlopen(const char* name, int flags,
}
ProtectedDataGuard guard;
+ reset_g_active_shim_libs();
soinfo* si = find_library(ns, translated_name, flags, extinfo, caller);
loading_trace.End();
diff --git a/linker/linker.h b/linker/linker.h
index 43d345c45..256c2d7db 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -104,6 +104,8 @@ soinfo* get_libdl_info(const char* linker_path, const link_map& linker_map);
soinfo* find_containing_library(const void* p);
+void parse_LD_SHIM_LIBS(const char* path);
+
void do_android_get_LD_LIBRARY_PATH(char*, size_t);
void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path);
void* do_dlopen(const char* name,
diff --git a/linker/linker_main.cpp b/linker/linker_main.cpp
index 5dc215f9d..0a5500fac 100644
--- a/linker/linker_main.cpp
+++ b/linker/linker_main.cpp
@@ -252,6 +252,7 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args) {
// 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");
if (ldpath_env != nullptr) {
@@ -261,6 +262,7 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args) {
if (ldpreload_env != nullptr) {
INFO("[ LD_PRELOAD set to \"%s\" ]", ldpreload_env);
}
+ ldshim_libs_env = getenv("LD_SHIM_LIBS");
}
struct stat file_stat;
@@ -330,6 +332,7 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args) {
// 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;