OSDN Git Service

Look into local group on dlsym with RTLD_DEFAULT
authorDmitriy Ivanov <dimitry@google.com>
Wed, 1 Apr 2015 21:45:10 +0000 (14:45 -0700)
committerDmitriy Ivanov <dimitry@google.com>
Thu, 2 Apr 2015 21:12:45 +0000 (14:12 -0700)
  Fix dlsym to look into local group when called with
  RTLD_DEFAULT and RTLD_NEXT.

Bug: 17512583
Change-Id: I541354e89539c712af2ea4ec751e546913027084

linker/dlfcn.cpp
linker/linker.cpp
linker/linker.h
tests/dlfcn_test.cpp
tests/libs/Android.mk
tests/libs/dlsym_from_this.cpp [new file with mode: 0644]

index 64df7a5..479e831 100644 (file)
@@ -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);
   }
index ebf125e..002a4f9 100644 (file)
@@ -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));
index bf3e7bf..ec3d8f0 100644 (file)
@@ -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);
index 1061e84..a63c070 100644 (file)
@@ -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);
index 665ce0c..eb0a52a 100644 (file)
@@ -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 (file)
index 0000000..b5215c9
--- /dev/null
@@ -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;
+}
+