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
This commit is contained in:
parent
0b8f6d592a
commit
e8ba50fe0d
@ -232,7 +232,7 @@ static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0 };
|
||||
static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
|
||||
#endif
|
||||
|
||||
static soinfo __libdl_info("libdl.so", nullptr);
|
||||
static soinfo __libdl_info("libdl.so", nullptr, RTLD_GLOBAL);
|
||||
|
||||
// This is used by the dynamic linker. Every process gets these symbols for free.
|
||||
soinfo* get_libdl_info() {
|
||||
|
@ -282,13 +282,13 @@ static void protect_data(int protection) {
|
||||
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 @@ static ElfW(Sym)* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name)
|
||||
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 @@ soinfo::soinfo(const char* name, const struct stat* file_stat) {
|
||||
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)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* start)
|
||||
|
||||
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 void for_each_dt_needed(const soinfo* si, F action) {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ static soinfo* load_library(LoadTaskList& load_tasks, const char* name, int dlfl
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ static soinfo* load_library(LoadTaskList& load_tasks, const char* name, int dlfl
|
||||
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 @@ static soinfo *find_loaded_library_by_name(const char* name) {
|
||||
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 @@ static soinfo* find_library_internal(LoadTaskList& load_tasks, const char* name,
|
||||
// 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 is_recursive(soinfo* si, soinfo* parent) {
|
||||
}
|
||||
|
||||
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 @@ static bool find_libraries(const char* const library_names[], size_t library_nam
|
||||
|
||||
// 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 @@ static bool find_libraries(const char* const library_names[], size_t library_nam
|
||||
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 @@ static soinfo* find_library(const char* name, int dlflags, const android_dlextin
|
||||
|
||||
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 @@ ino_t soinfo::get_st_ino() {
|
||||
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 @@ static void add_vdso(KernelArgumentBlock& args __unused) {
|
||||
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 @@ static void add_vdso(KernelArgumentBlock& args __unused) {
|
||||
#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 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(
|
||||
|
||||
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 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(
|
||||
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 @@ extern "C" ElfW(Addr) __linker_init(void* raw_args) {
|
||||
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
|
||||
|
@ -201,7 +201,7 @@ struct soinfo {
|
||||
// should not use it in any way.
|
||||
bool has_DT_SYMBOLIC;
|
||||
|
||||
soinfo(const char* name, const struct stat* file_stat);
|
||||
soinfo(const char* name, const struct stat* file_stat, int rtld_flags);
|
||||
|
||||
void CallConstructors();
|
||||
void CallDestructors();
|
||||
@ -217,6 +217,8 @@ struct soinfo {
|
||||
ino_t get_st_ino();
|
||||
dev_t get_st_dev();
|
||||
|
||||
int get_rtld_flags();
|
||||
|
||||
soinfo_list_t& get_children();
|
||||
soinfo_list_t& get_parents();
|
||||
|
||||
@ -248,6 +250,7 @@ struct soinfo {
|
||||
soinfo_list_t parents;
|
||||
|
||||
// version >= 1
|
||||
int rtld_flags;
|
||||
};
|
||||
|
||||
extern soinfo* get_libdl_info();
|
||||
|
@ -202,6 +202,42 @@ TEST(dlfcn, dlopen_check_order) {
|
||||
dlclose(handle);
|
||||
}
|
||||
|
||||
TEST(dlfcn, dlopen_check_rtld_local) {
|
||||
void* sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
|
||||
ASSERT_TRUE(sym == nullptr);
|
||||
|
||||
// implicit RTLD_LOCAL
|
||||
void* handle = dlopen("libtest_simple.so", RTLD_NOW);
|
||||
sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
|
||||
ASSERT_TRUE(sym == nullptr);
|
||||
ASSERT_SUBSTR("undefined symbol: dlopen_testlib_simple_func", dlerror());
|
||||
sym = dlsym(handle, "dlopen_testlib_simple_func");
|
||||
ASSERT_TRUE(sym != nullptr);
|
||||
ASSERT_TRUE(reinterpret_cast<bool (*)(void)>(sym)());
|
||||
dlclose(handle);
|
||||
|
||||
// explicit RTLD_LOCAL
|
||||
handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_LOCAL);
|
||||
sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
|
||||
ASSERT_TRUE(sym == nullptr);
|
||||
ASSERT_SUBSTR("undefined symbol: dlopen_testlib_simple_func", dlerror());
|
||||
sym = dlsym(handle, "dlopen_testlib_simple_func");
|
||||
ASSERT_TRUE(sym != nullptr);
|
||||
ASSERT_TRUE(reinterpret_cast<bool (*)(void)>(sym)());
|
||||
dlclose(handle);
|
||||
}
|
||||
|
||||
TEST(dlfcn, dlopen_check_rtld_global) {
|
||||
void* sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
|
||||
ASSERT_TRUE(sym == nullptr);
|
||||
|
||||
void* handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_GLOBAL);
|
||||
sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
|
||||
ASSERT_TRUE(sym != nullptr) << dlerror();
|
||||
ASSERT_TRUE(reinterpret_cast<bool (*)(void)>(sym)());
|
||||
dlclose(handle);
|
||||
}
|
||||
|
||||
// libtest_with_dependency_loop.so -> libtest_with_dependency_loop_a.so ->
|
||||
// libtest_with_dependency_loop_b.so -> libtest_with_dependency_loop_c.so ->
|
||||
// libtest_with_dependency_loop_a.so
|
||||
|
@ -19,6 +19,6 @@
|
||||
|
||||
uint32_t dlopen_testlib_taxicab_number = 1729;
|
||||
|
||||
bool dlopen_testlib_simple_func() {
|
||||
extern "C" bool dlopen_testlib_simple_func() {
|
||||
return true;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user