From ebd506c69e12b6dcaf5be94cc8ed1b53af299f9f Mon Sep 17 00:00:00 2001 From: Sergey Melnikov Date: Thu, 31 Oct 2013 18:02:12 +0400 Subject: [PATCH] Fix linker crashes during unknown symbol lookup Integration of kernel VDSO into internal bionic data structures using common functions. Fix for dl_iterate_phdr function: the function provides incorrect address of object in case of nonzero virtual and base addresses. Location in address space of a particular program header should be calculated using the formula: addr = base_addr + virtual_addr. Signed-off-by: Sergey Melnikov Change-Id: Ie2ab4257fd456242aab8afed0bd5bd6b29e81d6d --- linker/linker.cpp | 18 ++++++++++-------- tests/dlfcn_test.cpp | 12 ++++++++++++ 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/linker/linker.cpp b/linker/linker.cpp index 6bf18ac9b..fe4d6c49a 100755 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -73,6 +73,7 @@ */ static bool soinfo_link_image(soinfo* si); +static Elf_Addr get_elf_exec_load_bias(const Elf_Ehdr* elf); // We can't use malloc(3) in the dynamic linker. We use a linked list of anonymous // maps, each a single page in size. The pages are broken up into as many struct soinfo @@ -186,7 +187,7 @@ static pthread_mutex_t gDebugMutex = PTHREAD_MUTEX_INITIALIZER; static void insert_soinfo_into_debug_map(soinfo * info) { // Copy the necessary fields into the debug structure. link_map_t* map = &(info->link_map); - map->l_addr = info->base; + map->l_addr = info->load_bias; map->l_name = (char*) info->name; map->l_ld = (uintptr_t)info->dynamic; @@ -1751,15 +1752,16 @@ static void add_vdso(KernelArgumentBlock& args UNUSED) { Elf_Ehdr* ehdr_vdso = reinterpret_cast(args.getauxval(AT_SYSINFO_EHDR)); soinfo* si = soinfo_alloc("[vdso]"); + si->phdr = reinterpret_cast(reinterpret_cast(ehdr_vdso) + ehdr_vdso->e_phoff); si->phnum = ehdr_vdso->e_phnum; - si->link_map.l_name = si->name; - for (size_t i = 0; i < si->phnum; ++i) { - if (si->phdr[i].p_type == PT_LOAD) { - si->link_map.l_addr = reinterpret_cast(ehdr_vdso) - si->phdr[i].p_vaddr; - break; - } - } + si->base = reinterpret_cast(ehdr_vdso); + si->size = phdr_table_get_load_size(si->phdr, si->phnum); + si->flags = 0; + si->load_bias = get_elf_exec_load_bias(ehdr_vdso); + + soinfo_link_image(si); + insert_soinfo_into_debug_map(si); #endif } diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp index 938b8a543..6ba8e6636 100644 --- a/tests/dlfcn_test.cpp +++ b/tests/dlfcn_test.cpp @@ -222,3 +222,15 @@ TEST(dlfcn, dlopen_bad_flags) { ASSERT_TRUE(handle != NULL); ASSERT_SUBSTR(NULL, dlerror()); } + +TEST(dlfcn, rtld_default_unknown_symbol) { + void* self = RTLD_DEFAULT; + void* addr = dlsym(self, "ANY_UNKNOWN_SYMBOL_NAME"); + ASSERT_TRUE(addr == NULL); +} + +TEST(dlfcn, rtld_default_known_symbol) { + void* self = RTLD_DEFAULT; + void* addr = dlsym(self, "fopen"); + ASSERT_TRUE(addr != NULL); +}