Fix dlsym() to take into account RTLD_GLOBAL/LOCAL
Symbols from libraries opened with RTLD_LOCAL (default)
should not be visible via dlsym(RLTD_DEFAULT/RTLD_NEXT, .)
Bug: 17512583
Change-Id: I1758943081a67cf3d49ba5808e061b8251a91964
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 6589684..3b18900 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -282,13 +282,13 @@
g_soinfo_links_allocator.protect_all(protection);
}
-static soinfo* soinfo_alloc(const char* name, struct stat* file_stat) {
+static soinfo* soinfo_alloc(const char* name, struct stat* file_stat, int rtld_flags) {
if (strlen(name) >= SOINFO_NAME_LEN) {
DL_ERR("library name \"%s\" too long", name);
return nullptr;
}
- soinfo* si = new (g_soinfo_allocator.alloc()) soinfo(name, file_stat);
+ soinfo* si = new (g_soinfo_allocator.alloc()) soinfo(name, file_stat, rtld_flags);
sonext->next = si;
sonext = si;
@@ -453,7 +453,7 @@
return nullptr;
}
-soinfo::soinfo(const char* name, const struct stat* file_stat) {
+soinfo::soinfo(const char* name, const struct stat* file_stat, int rtld_flags) {
memset(this, 0, sizeof(*this));
strlcpy(this->name, name, sizeof(this->name));
@@ -464,6 +464,8 @@
set_st_dev(file_stat->st_dev);
set_st_ino(file_stat->st_ino);
}
+
+ this->rtld_flags = rtld_flags;
}
static unsigned elfhash(const char* _name) {
@@ -713,6 +715,10 @@
ElfW(Sym)* s = nullptr;
for (soinfo* si = start; (s == nullptr) && (si != nullptr); si = si->next) {
+ if ((si->get_rtld_flags() & RTLD_GLOBAL) == 0) {
+ continue;
+ }
+
s = soinfo_elf_lookup(si, elf_hash, name);
if (s != nullptr) {
*found = si;
@@ -803,7 +809,7 @@
}
}
-static soinfo* load_library(LoadTaskList& load_tasks, const char* name, int dlflags, const android_dlextinfo* extinfo) {
+static soinfo* load_library(LoadTaskList& load_tasks, const char* name, int rtld_flags, const android_dlextinfo* extinfo) {
int fd = -1;
ScopedFd file_guard(-1);
@@ -838,7 +844,7 @@
}
}
- if ((dlflags & RTLD_NOLOAD) != 0) {
+ if ((rtld_flags & RTLD_NOLOAD) != 0) {
DL_ERR("library \"%s\" wasn't loaded and RTLD_NOLOAD prevented it", name);
return nullptr;
}
@@ -849,7 +855,7 @@
return nullptr;
}
- soinfo* si = soinfo_alloc(SEARCH_NAME(name), &file_stat);
+ soinfo* si = soinfo_alloc(SEARCH_NAME(name), &file_stat, rtld_flags);
if (si == nullptr) {
return nullptr;
}
@@ -881,7 +887,7 @@
return nullptr;
}
-static soinfo* find_library_internal(LoadTaskList& load_tasks, const char* name, int dlflags, const android_dlextinfo* extinfo) {
+static soinfo* find_library_internal(LoadTaskList& load_tasks, const char* name, int rtld_flags, const android_dlextinfo* extinfo) {
soinfo* si = find_loaded_library_by_name(name);
@@ -889,7 +895,7 @@
// of this fact is done by load_library.
if (si == nullptr) {
TRACE("[ '%s' has not been found by name. Trying harder...]", name);
- si = load_library(load_tasks, name, dlflags, extinfo);
+ si = load_library(load_tasks, name, rtld_flags, extinfo);
}
return si;
@@ -913,7 +919,7 @@
}
static bool find_libraries(const char* const library_names[], size_t library_names_size, soinfo* soinfos[],
- soinfo* ld_preloads[], size_t ld_preloads_size, int dlflags, const android_dlextinfo* extinfo) {
+ soinfo* ld_preloads[], size_t ld_preloads_size, int rtld_flags, const android_dlextinfo* extinfo) {
// Step 0: prepare.
LoadTaskList load_tasks;
for (size_t i = 0; i < library_names_size; ++i) {
@@ -939,7 +945,7 @@
// Step 1: load and pre-link all DT_NEEDED libraries in breadth first order.
for (LoadTask::unique_ptr task(load_tasks.pop_front()); task.get() != nullptr; task.reset(load_tasks.pop_front())) {
- soinfo* si = find_library_internal(load_tasks, task->get_name(), dlflags, extinfo);
+ soinfo* si = find_library_internal(load_tasks, task->get_name(), rtld_flags, extinfo);
if (si == nullptr) {
return false;
}
@@ -984,7 +990,7 @@
return true;
}
-static soinfo* find_library(const char* name, int dlflags, const android_dlextinfo* extinfo) {
+static soinfo* find_library(const char* name, int rtld_flags, const android_dlextinfo* extinfo) {
if (name == nullptr) {
somain->ref_count++;
return somain;
@@ -992,7 +998,7 @@
soinfo* si;
- if (!find_libraries(&name, 1, &si, nullptr, 0, dlflags, extinfo)) {
+ if (!find_libraries(&name, 1, &si, nullptr, 0, rtld_flags, extinfo)) {
return nullptr;
}
@@ -1774,6 +1780,14 @@
return 0;
}
+int soinfo::get_rtld_flags() {
+ if (has_min_version(1)) {
+ return rtld_flags;
+ }
+
+ return 0;
+}
+
// This is a return on get_children()/get_parents() if
// 'this->flags' does not have FLAG_NEW_SOINFO set.
static soinfo::soinfo_list_t g_empty_list;
@@ -2194,7 +2208,7 @@
return;
}
- soinfo* si = soinfo_alloc("[vdso]", nullptr);
+ soinfo* si = soinfo_alloc("[vdso]", nullptr, 0);
si->phdr = reinterpret_cast<ElfW(Phdr)*>(reinterpret_cast<char*>(ehdr_vdso) + ehdr_vdso->e_phoff);
si->phnum = ehdr_vdso->e_phnum;
@@ -2215,7 +2229,7 @@
#else
#define LINKER_PATH "/system/bin/linker"
#endif
-static soinfo linker_soinfo_for_gdb(LINKER_PATH, nullptr);
+static soinfo linker_soinfo_for_gdb(LINKER_PATH, nullptr, 0);
/* gdb expects the linker to be in the debug shared object list.
* Without this, gdb has trouble locating the linker's ".text"
@@ -2279,7 +2293,7 @@
INFO("[ android linker & debugger ]");
- soinfo* si = soinfo_alloc(args.argv[0], nullptr);
+ soinfo* si = soinfo_alloc(args.argv[0], nullptr, RTLD_GLOBAL);
if (si == nullptr) {
exit(EXIT_FAILURE);
}
@@ -2354,7 +2368,7 @@
memset(needed_library_names, 0, sizeof(needed_library_names));
needed_library_name_list.copy_to_array(needed_library_names, needed_libraries_count);
- if (needed_libraries_count > 0 && !find_libraries(needed_library_names, needed_libraries_count, needed_library_si, g_ld_preloads, ld_preloads_count, 0, nullptr)) {
+ if (needed_libraries_count > 0 && !find_libraries(needed_library_names, needed_libraries_count, needed_library_si, g_ld_preloads, ld_preloads_count, RTLD_GLOBAL, nullptr)) {
__libc_format_fd(2, "CANNOT LINK EXECUTABLE DEPENDENCIES: %s\n", linker_get_error_buffer());
exit(EXIT_FAILURE);
}
@@ -2467,7 +2481,7 @@
ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_addr);
ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(linker_addr + elf_hdr->e_phoff);
- soinfo linker_so("[dynamic linker]", nullptr);
+ soinfo linker_so("[dynamic linker]", nullptr, 0);
// If the linker is not acting as PT_INTERP entry_point is equal to
// _start. Which means that the linker is running as an executable and