diff --git a/libdl/libdl.c b/libdl/libdl.c index e8b01bebc..378f521b6 100644 --- a/libdl/libdl.c +++ b/libdl/libdl.c @@ -24,6 +24,8 @@ void *dlsym(void *handle, const char *symbol) { return 0; } int dladdr(const void *addr, Dl_info *info) { return 0; } int dlclose(void *handle) { return 0; } +void android_update_LD_LIBRARY_PATH(const char* ld_library_path) { } + #if defined(__arm__) void *dl_unwind_find_exidx(void *pc, int *pcount) { return 0; } diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp index 2184f3a12..a5f8944d8 100644 --- a/linker/dlfcn.cpp +++ b/linker/dlfcn.cpp @@ -55,6 +55,11 @@ const char* dlerror() { return old_value; } +void android_update_LD_LIBRARY_PATH(const char* ld_library_path) { + ScopedPthreadMutexLocker locker(&gDlMutex); + do_android_update_LD_LIBRARY_PATH(ld_library_path); +} + void* dlopen(const char* filename, int flags) { ScopedPthreadMutexLocker locker(&gDlMutex); soinfo* result = do_dlopen(filename, flags); @@ -141,16 +146,16 @@ int dlclose(void* handle) { } #if defined(ANDROID_ARM_LINKER) -// 0000000 00011111 111112 22222222 2333333 333344444444445555555 -// 0123456 78901234 567890 12345678 9012345 678901234567890123456 +// 0000000 00011111 111112 22222222 2333333 3333444444444455555555556666666 6667 +// 0123456 78901234 567890 12345678 9012345 6789012345678901234567890123456 7890 #define ANDROID_LIBDL_STRTAB \ - "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0dl_unwind_find_exidx\0" + "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0android_update_LD_LIBRARY_PATH\0dl_unwind_find_exidx\0" #elif defined(ANDROID_X86_LINKER) || defined(ANDROID_MIPS_LINKER) -// 0000000 00011111 111112 22222222 2333333 3333444444444455 -// 0123456 78901234 567890 12345678 9012345 6789012345678901 +// 0000000 00011111 111112 22222222 2333333 3333444444444455555555556666666 6667 +// 0123456 78901234 567890 12345678 9012345 6789012345678901234567890123456 7890 #define ANDROID_LIBDL_STRTAB \ - "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0dl_iterate_phdr\0" + "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0android_update_LD_LIBRARY_PATH\0dl_iterate_phdr\0" #else #error Unsupported architecture. Only ARM, MIPS, and x86 are presently supported. #endif @@ -175,10 +180,11 @@ static Elf32_Sym gLibDlSymtab[] = { ELF32_SYM_INITIALIZER(15, &dlsym, 1), ELF32_SYM_INITIALIZER(21, &dlerror, 1), ELF32_SYM_INITIALIZER(29, &dladdr, 1), + ELF32_SYM_INITIALIZER(36, &android_update_LD_LIBRARY_PATH, 1), #if defined(ANDROID_ARM_LINKER) - ELF32_SYM_INITIALIZER(36, &dl_unwind_find_exidx, 1), + ELF32_SYM_INITIALIZER(67, &dl_unwind_find_exidx, 1), #elif defined(ANDROID_X86_LINKER) || defined(ANDROID_MIPS_LINKER) - ELF32_SYM_INITIALIZER(36, &dl_iterate_phdr, 1), + ELF32_SYM_INITIALIZER(67, &dl_iterate_phdr, 1), #endif }; @@ -201,7 +207,7 @@ static Elf32_Sym gLibDlSymtab[] = { // Note that adding any new symbols here requires // stubbing them out in libdl. static unsigned gLibDlBuckets[1] = { 1 }; -static unsigned gLibDlChains[7] = { 0, 2, 3, 4, 5, 6, 0 }; +static unsigned gLibDlChains[8] = { 0, 2, 3, 4, 5, 6, 7, 0 }; // This is used by the dynamic linker. Every process gets these symbols for free. soinfo libdl_info = { @@ -218,7 +224,7 @@ soinfo libdl_info = { symtab: gLibDlSymtab, nbucket: 1, - nchain: 7, + nchain: 8, bucket: gLibDlBuckets, chain: gLibDlChains, diff --git a/linker/linker.cpp b/linker/linker.cpp index 0bdff9975..6a2a958ec 100755 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -351,6 +351,43 @@ static void soinfo_free(soinfo* si) gSoInfoFreeList = si; } + +static void parse_path(const char* path, const char* delimiters, + const char** array, char* buf, size_t buf_size, size_t max_count) { + if (path == NULL) { + return; + } + + size_t len = strlcpy(buf, path, buf_size); + + size_t i = 0; + char* buf_p = buf; + while (i < max_count && (array[i] = strsep(&buf_p, delimiters))) { + if (*array[i] != '\0') { + ++i; + } + } + + // Forget the last path if we had to truncate; this occurs if the 2nd to + // last char isn't '\0' (i.e. wasn't originally a delimiter). + if (i > 0 && len >= buf_size && buf[buf_size - 2] != '\0') { + array[i - 1] = NULL; + } else { + array[i] = NULL; + } +} + +static void parse_LD_LIBRARY_PATH(const char* path) { + parse_path(path, ":", gLdPaths, + gLdPathsBuffer, sizeof(gLdPathsBuffer), LDPATH_MAX); +} + +static void parse_LD_PRELOAD(const char* path) { + // We have historically supported ':' as well as ' ' in LD_PRELOAD. + parse_path(path, " :", gLdPreloadNames, + gLdPreloadsBuffer, sizeof(gLdPreloadsBuffer), LDPRELOAD_MAX); +} + #ifdef ANDROID_ARM_LINKER /* For a given PC, find the .so that it belongs to. @@ -561,34 +598,28 @@ Elf32_Sym *soinfo_lookup(soinfo *si, const char *name) /* This is used by dl_sym(). It performs a global symbol lookup. */ -Elf32_Sym *lookup(const char *name, soinfo **found, soinfo *start) -{ - unsigned elf_hash = elfhash(name); - Elf32_Sym *s = NULL; - soinfo *si; +Elf32_Sym* lookup(const char* name, soinfo** found, soinfo* start) { + unsigned elf_hash = elfhash(name); - if(start == NULL) { - start = solist; + if (start == NULL) { + start = solist; + } + + Elf32_Sym* s = NULL; + for (soinfo* si = start; (s == NULL) && (si != NULL); si = si->next) { + s = soinfo_elf_lookup(si, elf_hash, name); + if (s != NULL) { + *found = si; + break; } + } - for(si = start; (s == NULL) && (si != NULL); si = si->next) - { - if(si->flags & FLAG_ERROR) - continue; - s = soinfo_elf_lookup(si, elf_hash, name); - if (s != NULL) { - *found = si; - break; - } - } + if (s != NULL) { + TRACE_TYPE(LOOKUP, "%s s->st_value = 0x%08x, found->base = 0x%08x\n", + name, s->st_value, (*found)->base); + } - if(s != NULL) { - TRACE_TYPE(LOOKUP, "%s s->st_value = 0x%08x, si->base = 0x%08x\n", - name, s->st_value, si->base); - return s; - } - - return NULL; + return s; } soinfo *find_containing_library(const void *addr) @@ -869,20 +900,6 @@ static soinfo* load_library(const char* name) { return si.release(); } -static soinfo* init_library(soinfo* si) { - // At this point we know that whatever is loaded @ base is a valid ELF - // shared library whose segments are properly mapped in. - TRACE("[ init_library base=0x%08x sz=0x%08x name='%s') ]\n", - si->base, si->size, si->name); - - if (!soinfo_link_image(si)) { - munmap((void *)si->base, si->size); - return NULL; - } - - return si; -} - static soinfo *find_loaded_library(const char *name) { soinfo *si; @@ -909,10 +926,6 @@ static soinfo* find_library_internal(const char* name) { soinfo* si = find_loaded_library(name); if (si != NULL) { - if (si->flags & FLAG_ERROR) { - DL_ERR("\"%s\" failed to load previously", name); - return NULL; - } if (si->flags & FLAG_LINKED) { return si; } @@ -922,8 +935,19 @@ static soinfo* find_library_internal(const char* name) { TRACE("[ '%s' has not been loaded yet. Locating...]\n", name); si = load_library(name); - if (si != NULL) { - si = init_library(si); + if (si == NULL) { + return NULL; + } + + // At this point we know that whatever is loaded @ base is a valid ELF + // shared library whose segments are properly mapped in. + TRACE("[ init_library base=0x%08x sz=0x%08x name='%s') ]\n", + si->base, si->size, si->name); + + if (!soinfo_link_image(si)) { + munmap(reinterpret_cast(si->base), si->size); + soinfo_free(si); + return NULL; } return si; @@ -966,6 +990,12 @@ static int soinfo_unload(soinfo* si) { return 0; } +void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path) { + if (!get_AT_SECURE()) { + parse_LD_LIBRARY_PATH(ld_library_path); + } +} + soinfo* do_dlopen(const char* name, int flags) { if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL)) != 0) { DL_ERR("invalid flags to dlopen: %x", flags); @@ -1466,8 +1496,6 @@ static int nullify_closed_stdio() { } static bool soinfo_link_image(soinfo* si) { - si->flags |= FLAG_ERROR; - /* "base" might wrap around UINT32_MAX. */ Elf32_Addr base = si->load_bias; const Elf32_Phdr *phdr = si->phdr; @@ -1747,47 +1775,9 @@ static bool soinfo_link_image(soinfo* si) { nullify_closed_stdio(); } notify_gdb_of_load(si); - si->flags &= ~FLAG_ERROR; return true; } -static void parse_path(const char* path, const char* delimiters, - const char** array, char* buf, size_t buf_size, size_t max_count) -{ - if (path == NULL) { - return; - } - - size_t len = strlcpy(buf, path, buf_size); - - size_t i = 0; - char* buf_p = buf; - while (i < max_count && (array[i] = strsep(&buf_p, delimiters))) { - if (*array[i] != '\0') { - ++i; - } - } - - // Forget the last path if we had to truncate; this occurs if the 2nd to - // last char isn't '\0' (i.e. wasn't originally a delimiter). - if (i > 0 && len >= buf_size && buf[buf_size - 2] != '\0') { - array[i - 1] = NULL; - } else { - array[i] = NULL; - } -} - -static void parse_LD_LIBRARY_PATH(const char* path) { - parse_path(path, ":", gLdPaths, - gLdPathsBuffer, sizeof(gLdPathsBuffer), LDPATH_MAX); -} - -static void parse_LD_PRELOAD(const char* path) { - // We have historically supported ':' as well as ' ' in LD_PRELOAD. - parse_path(path, " :", gLdPreloadNames, - gLdPreloadsBuffer, sizeof(gLdPreloadsBuffer), LDPRELOAD_MAX); -} - /* * This code is called after the linker has linked itself and * fixed it's own GOT. It is safe to make references to externs diff --git a/linker/linker.h b/linker/linker.h index 60c76fa91..377ba156c 100644 --- a/linker/linker.h +++ b/linker/linker.h @@ -72,7 +72,6 @@ struct r_debug { }; #define FLAG_LINKED 0x00000001 -#define FLAG_ERROR 0x00000002 #define FLAG_EXE 0x00000004 // The main executable #define FLAG_LINKER 0x00000010 // The linker itself @@ -207,6 +206,7 @@ extern soinfo libdl_info; #define DT_PREINIT_ARRAYSZ 33 #endif +void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path); soinfo* do_dlopen(const char* name, int flags); int do_dlclose(soinfo* si);