summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--linker/Android.bp5
-rw-r--r--linker/linker.cpp71
-rw-r--r--linker/linker.h20
-rw-r--r--linker/linker_main.cpp11
4 files changed, 107 insertions, 0 deletions
diff --git a/linker/Android.bp b/linker/Android.bp
index f75088d60..435ae8cf7 100644
--- a/linker/Android.bp
+++ b/linker/Android.bp
@@ -91,6 +91,11 @@ cc_defaults {
debuggable: {
cppflags: ["-DUSE_LD_CONFIG_FILE"],
},
+ lineage: {
+ target_shim_libs: {
+ cppflags: ["-DLD_SHIM_LIBS=\"%s\""],
+ },
+ },
},
cppflags: ["-Wold-style-cast"],
diff --git a/linker/linker.cpp b/linker/linker.cpp
index f24167722..25cfd300e 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -644,6 +644,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<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) {
+ for (const auto& pair : android::base::Split(path, ":")) {
+ std::vector<std::string> 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<std::string, std::string>(resolved_path, pieces[1]);
+ g_ld_all_shim_libs.push_back(desc);
+ }
+ }
+ reset_g_active_shim_libs();
+}
+
+std::vector<const ShimDescriptor*> shim_matching_pairs(const char* path) {
+ std::vector<const ShimDescriptor*> 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
@@ -1279,6 +1341,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);
@@ -2181,6 +2249,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 2da14041b..dce6c5e4c 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 <string>
#include <vector>
@@ -77,6 +81,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<std::string, std::string> ShimDescriptor;
+void parse_LD_SHIM_LIBS(const char* path);
+std::vector<const ShimDescriptor*> shim_matching_pairs(const char* path);
+
+template<typename F>
+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 98af54ac2..22c034b61 100644
--- a/linker/linker_main.cpp
+++ b/linker/linker_main.cpp
@@ -417,6 +417,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<android_namespace_t*> namespaces = init_default_namespaces(exe_info.path.c_str());
if (!si->prelink_image()) __linker_cannot_link(g_argv[0]);
@@ -442,6 +447,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);
});