aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristopher R. Palmer <crpalmer@gmail.com>2017-04-08 22:40:01 +0200
committerRashed Abdel-Tawab <rashed@linux.com>2017-10-28 18:46:18 -0700
commite39f25242a67bed84403365c3de6f9cc4a7fdec3 (patch)
tree9744710f0a72d073a469ffb75e184ca5f5daa4be
parent34343c81d87bafcb2bfc890360e117856738b9fc (diff)
downloadandroid_bionic-staging/lineage-15.0_rebase-android-8.0.0_r23.tar.gz
android_bionic-staging/lineage-15.0_rebase-android-8.0.0_r23.tar.bz2
android_bionic-staging/lineage-15.0_rebase-android-8.0.0_r23.zip
linker: Add support for dynamic SHIM librariesstaging/lineage-15.0_rebase-android-8.0.0_r23
Add a new environment variable LD_SHIM_LIBS that is a colon (":") separated list of vertical bar ("|") separated pairs. The pairs are the name for a soinfo reference (executable or shared library) followed by the name of the shim library to load. For example: LD_SHIM_LIBS=rmt_storage|libshim_ioprio.so:/system/lib/libicuuv.so|libshim_icu53.so will instruct the linker to load the dynamic library libshim_ioprio.so whenver rmt_storage is executed [*] and will load libshim_icu53.so whenever any executable or other shared library links against /system/lib/libicuuv.so. There are no restrictions against circular references. In this example, libshim_icu53.so can link against libicuuv.so which provides a simple and convenient means of adding compatibility symbols. [*] Note that the absolute path is not available to the linker and therefore using the name of executables does depend on the invocation and therefore should only be used if absolutely necessary. That is, running /system/bin/rmt_storage would not load any shim libs in this example because it does not match the name of the invocation of the command. If you have trouble determining the sonames being loaded, you can also set the environment variable LD_DEBUG=1 which will cause additional information to be logged to help trace the detection of the shim libs. Change-Id: I0ef80fa466167f7bcb7dac90842bef1c3cf879b6 linker: Fix the fact that shim libs do not properly call constructors Change-Id: I34333e13443a154e675b853fa41442351bc4243a linker: Don't try to walk the g_active_shim_libs when doing dlsym This is a bug in the original shim_lib implementation which was doing the shim lib resolution both when loading the libraries and when doing the dynamic symbol resolution. Change-Id: Ib2df0498cf551b3bbd37d7c351410b9908eb1795 Revert "Revert "linker: Reset the active shim libs each time we do a dlopen"" This reverts commit fd0140b028dedabc572f4659cc015edfeee3cd60. Change-Id: I42b3acfcdc6b84251a396b9e42604bb5685196bd Make shim lib load failure non-fatal. Instead, print an appropriate warning message. Aborting symbol resolution on shim lib load failure leads to weird symbol lookup failures, because symbols in libraries referenced after the one loading the shim won't be loaded anymore without a log message stating why that happened. Change-Id: Ic3ad7095ddae7ea1039cb6a18603d5cde8a16143 bionic: Do not allow LD_SHIM_LIBS for setuid executables That's really not safe... Change-Id: If79af951830966fc21812cd0f60a8998a752a941 bionic: linker: Load shim libs *before* the self-linked libs By loading them earlier, this allows us to override a symbol in a library that is being directly linked. I believe this explains why some people have had problems shimming one lib but when the changet he shim to be against a different lib it magically works. It also makes it possible to override some symbols that were nearly impossible to override before this change. For example, it is pretty much impossible to override a symbol in libutils without this change because it's loaded almost everywhere so no matter where you try to place the shimming, it will be too late and the other symbol will have priority. In particularly, this is necessary to be able to correctly shim the VectorImpl symbols for dlx. Change-Id: I461ca416bc288e28035352da00fde5f34f8d9ffa linker: Allow text-relocs for x86 (only) This effectively reverts https://android.googlesource.com/platform/bionic/+/e4ad91f86a47b39612e030a162f4793cb3421d31%5E%21/#F0 for x86 platforms. Unfortunately, this seems like it is required if we are going to support ffmpeg. The ffmpeg team decreed that they require text relocations for x86 (only) and that they would not fix the fact that android 6.0 makes ffmpeg unusable on x86: https://trac.ffmpeg.org/ticket/4928 Change-Id: I68397f4d62f4f6acd8e0d41b7ecdc115969b890a linker: Update find_library call for shimlibs commits 0cdef7e7f3c6837b56a969120d9098463d1df8d8 "Respect caller DT_RUNPATH in dlopen()." and 42d5fcb9f494eb45de3b6bf759f4a18076e84728 "Introducing linker namespaces" added new arguments to find_library, add them here. Change-Id: I8f35a45b00d14f8b2ce01a0a96d2dc7759be04a6 linker: Update LD_SHIM_LIBS parser function * Upgrade the code using the same changes as 42d5fcb9f494eb45de3b6bf759f4a18076e84728 bda20e78f0f314dbbf0f0bbcf0740cf2d6a4b85e Change-Id: Ic8be0871945bd9feccd0f94a6770f3cc78a70a0f Inject shim libs as if they were DT_NEEDED. The previous separate approach had one flaw: If the shim lib requires another lib that's already loaded, find_library_internal() would return the previously loaded copy, but the later load action would fail as the ELF reader map of the initial loading round was already discarded and thus a new ElfReader instance for the soinfo instance was created, which didn't know about the previous reading/loading state. Change-Id: Ib224dbd35d114197097e3dee14a077cc9130fedb linker: Make platform text relocations denial enabled by default * msm8960 variant to support relocations by default * Partial revert "Remove textrels support for platform libs" commit 8068786ae67835291521e52f39c695e40f3ad20d. Change-Id: I994ab1a600a0b237b496ceebe2dd54febc28a6bd linker: load shims prior to dt_needed check This allows shims to override existing symbols, not just inject new symbols. Change-Id: Ib9216bcc651d8d38999c593babb94d76dc1dbc95 Author: Adrian DC <radian.dc@gmail.com> Date: Sat, 8 Apr 2017 22:40:01 +0200 * Adapt to latest AOSP Oreo bionic linker changes * Additional header to avoid unused function Change-Id: Ib9216bcc651d8d38999c593babb94d76dc1dbc95 Change-Id: Ic3ad7095ddae7ea1039cb6a18603d5cde8a16152
-rw-r--r--libc/bionic/libc_init_common.cpp1
-rw-r--r--linker/linker.cpp64
-rw-r--r--linker/linker.h2
-rw-r--r--linker/linker_main.cpp3
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;