From f439b5a3186ca0fef1092f45770abc716da9d87a Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Sat, 30 May 2015 13:04:39 -0700 Subject: [PATCH] Fix dlsym(handle_of_main_executable, ...) According to man dlopen(3) and posix docs in the case when si is handle of the main executable we need to search not only in the executable and its dependencies but also in all libraries loaded with RTLD_GLOBAL. see also: http://pubs.opengroup.org/onlinepubs/9699919799/functions/dlopen.html Bug: http://b/21528224 Bug: http://b/17512583 Bug: https://code.google.com/p/android/issues/detail?id=173822 Change-Id: Ib2801367ba48b6f3704da89a6d9f5e6911430013 --- linker/linker.cpp | 11 +++++++++++ tests/dlfcn_test.cpp | 28 ++++++++++++++++++++++++++-- tests/libs/Android.mk | 8 ++++++++ 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/linker/linker.cpp b/linker/linker.cpp index 531cd1908..1382a9cdc 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -948,6 +948,17 @@ static const ElfW(Sym)* dlsym_handle_lookup(soinfo* root, soinfo* skip_until, // This is used by dlsym(3). It performs symbol lookup only within the // specified soinfo object and its dependencies in breadth first order. const ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name) { + // According to man dlopen(3) and posix docs in the case when si is handle + // of the main executable we need to search not only in the executable and its + // dependencies but also in all libraries loaded with RTLD_GLOBAL. + // + // Since RTLD_GLOBAL is always set for the main executable and all dt_needed shared + // libraries and they are loaded in breath-first (correct) order we can just execute + // dlsym(RTLD_DEFAULT, ...); instead of doing two stage lookup. + if (si == somain) { + return dlsym_linear_lookup(name, found, nullptr, RTLD_DEFAULT); + } + SymbolName symbol_name(name); return dlsym_handle_lookup(si, nullptr, found, symbol_name); } diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp index a5abda7b1..3c9b8e33a 100644 --- a/tests/dlfcn_test.cpp +++ b/tests/dlfcn_test.cpp @@ -145,13 +145,28 @@ TEST(dlfcn, dlsym_from_sofile_with_preload) { dlclose(preload); } +TEST(dlfcn, dlsym_handle_global_sym) { + // check that we do not look into global group + // when looking up symbol by handle + void* handle = dlopen("libtest_empty.so", RTLD_NOW); + dlopen("libtest_with_dependency.so", RTLD_NOW | RTLD_GLOBAL); + void* sym = dlsym(handle, "getRandomNumber"); + ASSERT_TRUE(sym == nullptr); + ASSERT_SUBSTR("undefined symbol: getRandomNumber", dlerror()); + + sym = dlsym(handle, "DlSymTestFunction"); + ASSERT_TRUE(sym == nullptr); + ASSERT_SUBSTR("undefined symbol: DlSymTestFunction", dlerror()); + dlclose(handle); +} + TEST(dlfcn, dlsym_with_dependencies) { void* handle = dlopen("libtest_with_dependency.so", RTLD_NOW); - ASSERT_TRUE(handle != NULL); + ASSERT_TRUE(handle != nullptr); dlerror(); // This symbol is in DT_NEEDED library. void* sym = dlsym(handle, "getRandomNumber"); - ASSERT_TRUE(sym != NULL); + ASSERT_TRUE(sym != nullptr) << dlerror(); int (*fn)(void); fn = reinterpret_cast(sym); EXPECT_EQ(4, fn()); @@ -583,6 +598,15 @@ TEST(dlfcn, dlopen_check_rtld_global) { // RTLD_GLOBAL implies RTLD_NODELETE, let's check that void* sym_after_dlclose = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func"); ASSERT_EQ(sym, sym_after_dlclose); + + // Check if dlsym() for main program's handle searches RTLD_GLOBAL + // shared libraries after symbol was not found in the main executable + // and dependent libraries. + void* handle_for_main_executable = dlopen(nullptr, RTLD_NOW); + sym = dlsym(handle_for_main_executable, "dlopen_testlib_simple_func"); + ASSERT_TRUE(sym != nullptr) << dlerror(); + + dlclose(handle_for_main_executable); } // libtest_with_dependency_loop.so -> libtest_with_dependency_loop_a.so -> diff --git a/tests/libs/Android.mk b/tests/libs/Android.mk index 15fa55c21..a5ef622c5 100644 --- a/tests/libs/Android.mk +++ b/tests/libs/Android.mk @@ -405,6 +405,14 @@ module := libtest_dlsym_from_this_grandchild include $(LOCAL_PATH)/Android.build.testlib.mk # ----------------------------------------------------------------------------- +# Empty library +# ----------------------------------------------------------------------------- +libtest_empty_src_files := empty.cpp + +module := libtest_empty +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- # Library with weak undefined function # ----------------------------------------------------------------------------- libtest_dlopen_weak_undefined_func_src_files := \ -- 2.11.0