summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitriy Ivanov <dimitry@google.com>2015-04-01 14:45:10 -0700
committerDmitriy Ivanov <dimitry@google.com>2015-04-02 14:12:45 -0700
commit76ac1acdacc045cf1e56504e011dca68137dcd61 (patch)
tree9eb3bee0f92ae74f1eba59efad4c037d50aa3dcd
parentab7c79e22e5495a2aa171047a044ce1037e461a9 (diff)
downloadbionic-76ac1acdacc045cf1e56504e011dca68137dcd61.zip
bionic-76ac1acdacc045cf1e56504e011dca68137dcd61.tar.gz
bionic-76ac1acdacc045cf1e56504e011dca68137dcd61.tar.bz2
Look into local group on dlsym with RTLD_DEFAULT
Fix dlsym to look into local group when called with RTLD_DEFAULT and RTLD_NEXT. Bug: 17512583 Change-Id: I541354e89539c712af2ea4ec751e546913027084
-rw-r--r--linker/dlfcn.cpp15
-rw-r--r--linker/linker.cpp38
-rw-r--r--linker/linker.h2
-rw-r--r--tests/dlfcn_test.cpp23
-rw-r--r--tests/libs/Android.mk9
-rw-r--r--tests/libs/dlsym_from_this.cpp30
6 files changed, 101 insertions, 16 deletions
diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp
index 64df7a5..479e831 100644
--- a/linker/dlfcn.cpp
+++ b/linker/dlfcn.cpp
@@ -101,16 +101,11 @@ void* dlsym(void* handle, const char* symbol) {
soinfo* found = nullptr;
ElfW(Sym)* sym = nullptr;
- if (handle == RTLD_DEFAULT) {
- sym = dlsym_linear_lookup(symbol, &found, nullptr);
- } else if (handle == RTLD_NEXT) {
- void* caller_addr = __builtin_return_address(0);
- soinfo* si = find_containing_library(caller_addr);
-
- sym = nullptr;
- if (si && si->next) {
- sym = dlsym_linear_lookup(symbol, &found, si->next);
- }
+ void* caller_addr = __builtin_return_address(0);
+ soinfo* caller = find_containing_library(caller_addr);
+
+ if (handle == RTLD_DEFAULT || handle == RTLD_NEXT) {
+ sym = dlsym_linear_lookup(symbol, &found, caller, handle);
} else {
sym = dlsym_handle_lookup(reinterpret_cast<soinfo*>(handle), &found, symbol);
}
diff --git a/linker/linker.cpp b/linker/linker.cpp
index ebf125e..002a4f9 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -738,15 +738,21 @@ ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name) {
beginning of the global solist. Otherwise the search starts at the
specified soinfo (for RTLD_NEXT).
*/
-ElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* start) {
+ElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* caller, void* handle) {
SymbolName symbol_name(name);
- if (start == nullptr) {
- start = solist;
+ soinfo* start = solist;
+
+ if (handle == RTLD_NEXT) {
+ if (caller == nullptr || caller->next == nullptr) {
+ return nullptr;
+ } else {
+ start = caller->next;
+ }
}
ElfW(Sym)* s = nullptr;
- for (soinfo* si = start; (s == nullptr) && (si != nullptr); si = si->next) {
+ for (soinfo* si = start; si != nullptr; si = si->next) {
if ((si->get_rtld_flags() & RTLD_GLOBAL) == 0) {
continue;
}
@@ -758,6 +764,30 @@ ElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* start)
}
}
+ // If not found - look into local_group unless
+ // caller is part of the global group in which
+ // case we already did it.
+ if (s == nullptr && caller != nullptr &&
+ (caller->get_rtld_flags() & RTLD_GLOBAL) == 0) {
+ soinfo* local_group_root = caller->get_local_group_root();
+
+ if (handle == RTLD_DEFAULT) {
+ start = local_group_root;
+ }
+
+ for (soinfo* si = start; si != nullptr; si = si->next) {
+ if (si->get_local_group_root() != local_group_root) {
+ break;
+ }
+
+ s = si->find_symbol_by_name(symbol_name);
+ if (s != nullptr) {
+ *found = si;
+ break;
+ }
+ }
+ }
+
if (s != nullptr) {
TRACE_TYPE(LOOKUP, "%s s->st_value = %p, found->base = %p",
name, reinterpret_cast<void*>(s->st_value), reinterpret_cast<void*>((*found)->base));
diff --git a/linker/linker.h b/linker/linker.h
index bf3e7bf..ec3d8f0 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -351,7 +351,7 @@ void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path);
soinfo* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo);
void do_dlclose(soinfo* si);
-ElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* start);
+ElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* caller, void* handle);
soinfo* find_containing_library(const void* addr);
ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name);
diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp
index 1061e84..a63c070 100644
--- a/tests/dlfcn_test.cpp
+++ b/tests/dlfcn_test.cpp
@@ -46,7 +46,7 @@ TEST(dlfcn, ctor_function_call) {
ASSERT_EQ(17, g_ctor_function_called);
}
-TEST(dlfcn, dlsym_in_self) {
+TEST(dlfcn, dlsym_in_executable) {
dlerror(); // Clear any pending errors.
void* self = dlopen(NULL, RTLD_NOW);
ASSERT_TRUE(self != NULL);
@@ -64,6 +64,27 @@ TEST(dlfcn, dlsym_in_self) {
ASSERT_EQ(0, dlclose(self));
}
+TEST(dlfcn, dlsym_from_sofile) {
+ void* handle = dlopen("libtest_dlsym_from_this.so", RTLD_LAZY | RTLD_LOCAL);
+ ASSERT_TRUE(handle != nullptr) << dlerror();
+
+ // check that we cant find '_test_dlsym_symbol' via dlsym(RTLD_DEFAULT)
+ void* symbol = dlsym(RTLD_DEFAULT, "test_dlsym_symbol");
+ ASSERT_TRUE(symbol == nullptr);
+ ASSERT_SUBSTR("undefined symbol: test_dlsym_symbol", dlerror());
+
+ typedef int* (*fn_t)();
+ fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol_using_RTLD_DEFAULT"));
+
+ ASSERT_TRUE(fn != nullptr) << dlerror();
+
+ int* ptr = fn();
+ ASSERT_TRUE(ptr != nullptr) << dlerror();
+ ASSERT_EQ(42, *ptr);
+
+ dlclose(handle);
+}
+
TEST(dlfcn, dlsym_with_dependencies) {
void* handle = dlopen("libtest_with_dependency.so", RTLD_NOW);
ASSERT_TRUE(handle != NULL);
diff --git a/tests/libs/Android.mk b/tests/libs/Android.mk
index 665ce0c..eb0a52a 100644
--- a/tests/libs/Android.mk
+++ b/tests/libs/Android.mk
@@ -371,6 +371,15 @@ module := libtest_dlsym_weak_func
include $(LOCAL_PATH)/Android.build.testlib.mk
# -----------------------------------------------------------------------------
+# Library to check RTLD_LOCAL with dlsym in 'this'
+# -----------------------------------------------------------------------------
+libtest_dlsym_from_this_src_files := dlsym_from_this.cpp
+
+module := libtest_dlsym_from_this
+
+include $(LOCAL_PATH)/Android.build.testlib.mk
+
+# -----------------------------------------------------------------------------
# Library with weak undefined function
# -----------------------------------------------------------------------------
libtest_dlopen_weak_undefined_func_src_files := \
diff --git a/tests/libs/dlsym_from_this.cpp b/tests/libs/dlsym_from_this.cpp
new file mode 100644
index 0000000..b5215c9
--- /dev/null
+++ b/tests/libs/dlsym_from_this.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <dlfcn.h>
+#include <stdio.h>
+
+int test_dlsym_symbol = 42;
+
+extern "C" int* lookup_dlsym_symbol_using_RTLD_DEFAULT() {
+ dlerror();
+ int* result = static_cast<int*>(dlsym(RTLD_DEFAULT, "test_dlsym_symbol"));
+ // TODO: remove this once b/20049306 is fixed
+ if (result == nullptr) {
+ printf("Cannot find the answer\n");
+ }
+ return result;
+}
+