diff --git a/linker/Android.bp b/linker/Android.bp index d8fdb1158..0a23cfd71 100644 --- a/linker/Android.bp +++ b/linker/Android.bp @@ -74,6 +74,9 @@ cc_object { // Configuration for the linker binary and any of its static libraries. cc_defaults { name: "linker_defaults", + defaults: [ + "shim_libs_defaults", + ], arch: { arm: { cflags: ["-D__work_around_b_24465209__"], diff --git a/linker/linker.cpp b/linker/linker.cpp index 8b467a376..f9efd8c14 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -690,6 +690,68 @@ enum walk_action_result_t : uint32_t { kWalkSkip = 2 }; +#ifdef LD_SHIM_LIBS +// 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 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 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) { + for (const auto& pair : android::base::Split(path, ":")) { + std::vector pieces = android::base::Split(pair, "|"); + if (pieces.size() != 2) continue; + // If the path can be resolved, resolve it + char buf[PATH_MAX]; + std::string resolved_path = pieces[0]; + if (access(pieces[0].c_str(), R_OK) != 0) { + if (errno == ENOENT) { + // no need to test for non-existing path. skip. + continue; + } + // If not accessible, don't call realpath as it will just cause + // SELinux denial spam. Use the path unresolved. + } else if (realpath(pieces[0].c_str(), buf) != nullptr) { + resolved_path = buf; + } + auto desc = std::pair(resolved_path, pieces[1]); + g_ld_all_shim_libs.push_back(desc); + } + } + reset_g_active_shim_libs(); +} + +std::vector shim_matching_pairs(const char* path) { + std::vector matched_pairs; + + g_active_shim_libs.for_each([&](const ShimDescriptor* a_pair) { + if (a_pair->first == path) { + matched_pairs.push_back(a_pair); + } + }); + + g_active_shim_libs.remove_if([&](const ShimDescriptor* a_pair) { + return a_pair->first == path; + }); + + return matched_pairs; +} +#endif + // This function walks down the tree of soinfo dependencies // in breadth-first order and // * calls action(soinfo* si) for each node, and @@ -1302,6 +1364,12 @@ static bool load_library(android_namespace_t* ns, } #endif +#ifdef LD_SHIM_LIBS + for_each_matching_shim(realpath.c_str(), [&](const char* name) { + load_tasks->push_back(LoadTask::create(name, si, ns, task->get_readers_map())); + }); +#endif + for_each_dt_needed(task->get_elf_reader(), [&](const char* name) { LD_LOG(kLogDlopen, "load_library(ns=%s, task=%s): Adding DT_NEEDED task: %s", ns->get_name(), task->get_name(), name); @@ -2227,6 +2295,9 @@ void* do_dlopen(const char* name, int flags, } } ProtectedDataGuard guard; +#ifdef LD_SHIM_LIBS + reset_g_active_shim_libs(); +#endif soinfo* si = find_library(ns, translated_name, flags, extinfo, caller); loading_trace.End(); diff --git a/linker/linker.h b/linker/linker.h index ac2222d47..fbfc4db15 100644 --- a/linker/linker.h +++ b/linker/linker.h @@ -42,6 +42,10 @@ #include "linker_logger.h" #include "linker_soinfo.h" +#ifdef LD_SHIM_LIBS +#include "linker_debug.h" +#endif + #include #include @@ -81,6 +85,22 @@ soinfo* find_containing_library(const void* p); int open_executable(const char* path, off64_t* file_offset, std::string* realpath); +#ifdef LD_SHIM_LIBS +typedef std::pair ShimDescriptor; +void parse_LD_SHIM_LIBS(const char* path); +std::vector shim_matching_pairs(const char* path); + +template +void for_each_matching_shim(const char* path, F action) { + if (path == nullptr) return; + INFO("Finding shim libs for \"%s\"", path); + for (const auto& one_pair : shim_matching_pairs(path)) { + INFO("Injecting shim lib \"%s\" as needed for %s", one_pair->second.c_str(), path); + action(one_pair->second.c_str()); + } +} +#endif + 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 2b230a870..107f97126 100644 --- a/linker/linker_main.cpp +++ b/linker/linker_main.cpp @@ -434,6 +434,11 @@ static ElfW(Addr) linker_main(KernelArgumentBlock& args, const char* exe_to_load parse_LD_LIBRARY_PATH(ldpath_env); parse_LD_PRELOAD(ldpreload_env); +#ifdef LD_SHIM_LIBS + // Read from TARGET_LD_SHIM_LIBS + parse_LD_SHIM_LIBS(LD_SHIM_LIBS); +#endif + std::vector namespaces = init_default_namespaces(exe_info.path.c_str()); if (!si->prelink_image()) __linker_cannot_link(g_argv[0]); @@ -459,6 +464,12 @@ static ElfW(Addr) linker_main(KernelArgumentBlock& args, const char* exe_to_load ++ld_preloads_count; } +#ifdef LD_SHIM_LIBS + for_each_matching_shim(si->get_realpath(), [&](const char* name) { + needed_library_name_list.push_back(name); + }); +#endif + for_each_dt_needed(si, [&](const char* name) { needed_library_name_list.push_back(name); });