diff options
-rw-r--r-- | libc/bionic/libc_init_common.cpp | 1 | ||||
-rw-r--r-- | linker/linker.cpp | 64 | ||||
-rw-r--r-- | linker/linker.h | 2 | ||||
-rw-r--r-- | linker/linker_main.cpp | 3 |
4 files changed, 70 insertions, 0 deletions
diff --git a/libc/bionic/libc_init_common.cpp b/libc/bionic/libc_init_common.cpp index e051762fd..aad3d2cb8 100644 --- a/libc/bionic/libc_init_common.cpp +++ b/libc/bionic/libc_init_common.cpp @@ -262,6 +262,7 @@ static bool __is_unsafe_environment_variable(const char* name) { "LD_ORIGIN_PATH", "LD_PRELOAD", "LD_PROFILE", + "LD_SHIM_LIBS", "LD_SHOW_AUXV", "LD_USE_LOAD_BIAS", "LOCALDOMAIN", 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; |