2009-03-04 04:28:35 +01:00
|
|
|
/*
|
2015-04-09 22:42:33 +02:00
|
|
|
* Copyright (C) 2008 The Android Open Source Project
|
2009-03-04 04:28:35 +01:00
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* * Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in
|
|
|
|
* the documentation and/or other materials provided with the
|
|
|
|
* distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
|
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
|
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
|
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
|
|
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
|
|
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
|
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
|
|
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
2015-06-03 02:36:54 +02:00
|
|
|
#include <android/api-level.h>
|
2012-08-04 01:49:39 +02:00
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
2014-02-11 02:46:57 +01:00
|
|
|
#include <inttypes.h>
|
2012-08-04 01:49:39 +02:00
|
|
|
#include <pthread.h>
|
2009-03-04 04:28:35 +01:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2012-08-04 01:49:39 +02:00
|
|
|
#include <sys/mman.h>
|
2014-11-10 04:27:20 +01:00
|
|
|
#include <sys/param.h>
|
2012-08-04 01:49:39 +02:00
|
|
|
#include <unistd.h>
|
2009-03-04 04:28:35 +01:00
|
|
|
|
2014-08-22 21:25:04 +02:00
|
|
|
#include <new>
|
2015-03-24 02:43:02 +01:00
|
|
|
#include <string>
|
2015-09-29 01:38:31 +02:00
|
|
|
#include <unordered_map>
|
2015-03-24 02:43:02 +01:00
|
|
|
#include <vector>
|
2014-08-22 21:25:04 +02:00
|
|
|
|
2012-08-04 01:49:39 +02:00
|
|
|
// Private C library headers.
|
2014-09-06 01:42:53 +02:00
|
|
|
#include "private/ScopeGuard.h"
|
2009-03-04 04:28:35 +01:00
|
|
|
|
|
|
|
#include "linker.h"
|
2015-03-10 23:30:26 +01:00
|
|
|
#include "linker_block_allocator.h"
|
2016-07-06 22:20:59 +02:00
|
|
|
#include "linker_cfi.h"
|
2017-03-07 20:19:05 +01:00
|
|
|
#include "linker_config.h"
|
2016-02-18 01:08:03 +01:00
|
|
|
#include "linker_gdb_support.h"
|
2016-08-04 20:50:36 +02:00
|
|
|
#include "linker_globals.h"
|
2009-03-04 04:28:35 +01:00
|
|
|
#include "linker_debug.h"
|
2016-07-21 20:33:40 +02:00
|
|
|
#include "linker_dlwarning.h"
|
2016-09-09 19:00:39 +02:00
|
|
|
#include "linker_main.h"
|
2016-08-04 01:00:10 +02:00
|
|
|
#include "linker_namespaces.h"
|
2015-04-22 22:10:04 +02:00
|
|
|
#include "linker_sleb128.h"
|
2012-06-18 18:13:49 +02:00
|
|
|
#include "linker_phdr.h"
|
2015-01-09 08:30:15 +01:00
|
|
|
#include "linker_relocs.h"
|
2015-02-04 01:06:47 +01:00
|
|
|
#include "linker_reloc_iterators.h"
|
2015-10-02 03:41:57 +02:00
|
|
|
#include "linker_utils.h"
|
2015-07-29 12:00:22 +02:00
|
|
|
|
2015-12-05 00:27:46 +01:00
|
|
|
#include "android-base/strings.h"
|
2016-07-12 03:11:39 +02:00
|
|
|
#include "android-base/stringprintf.h"
|
2015-01-16 14:22:54 +01:00
|
|
|
#include "ziparchive/zip_archive.h"
|
2009-03-04 04:28:35 +01:00
|
|
|
|
2015-06-09 03:04:00 +02:00
|
|
|
// Override macros to use C++ style casts.
|
2015-01-23 01:04:25 +01:00
|
|
|
#undef ELF_ST_TYPE
|
|
|
|
#define ELF_ST_TYPE(x) (static_cast<uint32_t>(x) & 0xf)
|
|
|
|
|
2016-03-24 23:30:30 +01:00
|
|
|
static android_namespace_t* g_anonymous_namespace = &g_default_namespace;
|
2015-10-30 01:01:24 +01:00
|
|
|
|
2015-03-10 23:43:50 +01:00
|
|
|
static LinkerTypeAllocator<soinfo> g_soinfo_allocator;
|
|
|
|
static LinkerTypeAllocator<LinkedListEntry<soinfo>> g_soinfo_links_allocator;
|
2012-09-12 13:00:55 +02:00
|
|
|
|
2015-10-30 01:01:24 +01:00
|
|
|
static LinkerTypeAllocator<android_namespace_t> g_namespace_allocator;
|
2016-04-11 21:42:58 +02:00
|
|
|
static LinkerTypeAllocator<LinkedListEntry<android_namespace_t>> g_namespace_list_allocator;
|
2015-10-30 01:01:24 +01:00
|
|
|
|
2017-03-07 20:19:05 +01:00
|
|
|
static const char* const kLdConfigFilePath = "/system/etc/ld.config.txt";
|
|
|
|
|
2013-10-26 02:38:02 +02:00
|
|
|
#if defined(__LP64__)
|
2017-03-17 01:08:23 +01:00
|
|
|
static const char* const kSystemLibDir = "/system/lib64";
|
|
|
|
static const char* const kVendorLibDir = "/vendor/lib64";
|
2017-03-30 00:31:34 +02:00
|
|
|
static const char* const kAsanSystemLibDir = "/data/asan/system/lib64";
|
|
|
|
static const char* const kAsanVendorLibDir = "/data/asan/vendor/lib64";
|
2013-10-08 23:27:10 +02:00
|
|
|
#else
|
2017-03-17 01:08:23 +01:00
|
|
|
static const char* const kSystemLibDir = "/system/lib";
|
|
|
|
static const char* const kVendorLibDir = "/vendor/lib";
|
2017-03-30 00:31:34 +02:00
|
|
|
static const char* const kAsanSystemLibDir = "/data/asan/system/lib";
|
|
|
|
static const char* const kAsanVendorLibDir = "/data/asan/vendor/lib";
|
2013-10-08 23:27:10 +02:00
|
|
|
#endif
|
2016-08-10 04:38:43 +02:00
|
|
|
|
2017-03-30 00:31:34 +02:00
|
|
|
static const char* const kAsanLibDirPrefix = "/data/asan";
|
|
|
|
|
2016-08-10 04:38:43 +02:00
|
|
|
static const char* const kDefaultLdPaths[] = {
|
|
|
|
kSystemLibDir,
|
|
|
|
kVendorLibDir,
|
2014-08-29 21:02:36 +02:00
|
|
|
nullptr
|
2012-10-31 22:20:03 +01:00
|
|
|
};
|
|
|
|
|
2015-07-11 02:54:01 +02:00
|
|
|
static const char* const kAsanDefaultLdPaths[] = {
|
2016-08-10 04:38:43 +02:00
|
|
|
kAsanSystemLibDir,
|
|
|
|
kSystemLibDir,
|
|
|
|
kAsanVendorLibDir,
|
|
|
|
kVendorLibDir,
|
2015-07-11 02:54:01 +02:00
|
|
|
nullptr
|
|
|
|
};
|
|
|
|
|
2016-08-10 04:38:43 +02:00
|
|
|
// Is ASAN enabled?
|
|
|
|
static bool g_is_asan = false;
|
|
|
|
|
2016-07-06 22:20:59 +02:00
|
|
|
static CFIShadowWriter g_cfi_shadow;
|
|
|
|
|
|
|
|
CFIShadowWriter* get_cfi_shadow() {
|
|
|
|
return &g_cfi_shadow;
|
|
|
|
}
|
|
|
|
|
2016-07-21 20:33:40 +02:00
|
|
|
static bool is_system_library(const std::string& realpath) {
|
|
|
|
for (const auto& dir : g_default_namespace.get_default_library_paths()) {
|
|
|
|
if (file_is_in_dir(realpath, dir)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-08-10 04:38:43 +02:00
|
|
|
// Checks if the file exists and not a directory.
|
|
|
|
static bool file_exists(const char* path) {
|
2016-08-11 20:11:52 +02:00
|
|
|
struct stat s;
|
|
|
|
|
|
|
|
if (stat(path, &s) != 0) {
|
2016-08-10 04:38:43 +02:00
|
|
|
return false;
|
|
|
|
}
|
2016-08-11 20:11:52 +02:00
|
|
|
|
|
|
|
return S_ISREG(s.st_mode);
|
2016-08-10 04:38:43 +02:00
|
|
|
}
|
2016-07-21 20:33:40 +02:00
|
|
|
|
2017-02-27 21:17:47 +01:00
|
|
|
static std::string resolve_soname(const std::string& name) {
|
|
|
|
// We assume that soname equals to basename here
|
|
|
|
|
|
|
|
// TODO(dimitry): consider having honest absolute-path -> soname resolution
|
|
|
|
// note that since we might end up refusing to load this library because
|
|
|
|
// it is not in shared libs list we need to get the soname without actually loading
|
|
|
|
// the library.
|
|
|
|
//
|
|
|
|
// On the other hand there are several places where we already assume that
|
|
|
|
// soname == basename in particular for any not-loaded library mentioned
|
|
|
|
// in DT_NEEDED list.
|
|
|
|
return basename(name.c_str());
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool maybe_accessible_via_namespace_links(android_namespace_t* ns, const char* name) {
|
|
|
|
std::string soname = resolve_soname(name);
|
|
|
|
for (auto& ns_link : ns->linked_namespaces()) {
|
|
|
|
if (ns_link.is_accessible(soname.c_str())) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-07-21 20:33:40 +02:00
|
|
|
// TODO(dimitry): The grey-list is a workaround for http://b/26394120 ---
|
|
|
|
// gradually remove libraries from this list until it is gone.
|
2017-02-27 21:17:47 +01:00
|
|
|
static bool is_greylisted(android_namespace_t* ns, const char* name, const soinfo* needed_by) {
|
2016-07-21 20:33:40 +02:00
|
|
|
static const char* const kLibraryGreyList[] = {
|
|
|
|
"libandroid_runtime.so",
|
|
|
|
"libbinder.so",
|
|
|
|
"libcrypto.so",
|
|
|
|
"libcutils.so",
|
|
|
|
"libexpat.so",
|
|
|
|
"libgui.so",
|
|
|
|
"libmedia.so",
|
|
|
|
"libnativehelper.so",
|
|
|
|
"libskia.so",
|
|
|
|
"libssl.so",
|
|
|
|
"libstagefright.so",
|
|
|
|
"libsqlite.so",
|
|
|
|
"libui.so",
|
|
|
|
"libutils.so",
|
|
|
|
"libvorbisidec.so",
|
|
|
|
nullptr
|
|
|
|
};
|
|
|
|
|
2016-11-16 20:35:43 +01:00
|
|
|
// If you're targeting N, you don't get the greylist.
|
|
|
|
if (get_application_target_sdk_version() >= __ANDROID_API_N__) {
|
2016-07-21 20:33:40 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if the library needed by a system library - implicitly assume it
|
2017-02-27 21:17:47 +01:00
|
|
|
// is greylisted unless it is in the list of shared libraries for one or
|
|
|
|
// more linked namespaces
|
2016-07-21 20:33:40 +02:00
|
|
|
if (needed_by != nullptr && is_system_library(needed_by->get_realpath())) {
|
2017-02-27 21:17:47 +01:00
|
|
|
return !maybe_accessible_via_namespace_links(ns, name);
|
2016-07-21 20:33:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// if this is an absolute path - make sure it points to /system/lib(64)
|
|
|
|
if (name[0] == '/' && dirname(name) == kSystemLibDir) {
|
|
|
|
// and reduce the path to basename
|
|
|
|
name = basename(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (size_t i = 0; kLibraryGreyList[i] != nullptr; ++i) {
|
|
|
|
if (strcmp(name, kLibraryGreyList[i]) == 0) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// END OF WORKAROUND
|
|
|
|
|
2015-03-24 02:43:02 +01:00
|
|
|
static std::vector<std::string> g_ld_preload_names;
|
2014-01-14 01:37:47 +01:00
|
|
|
|
2017-02-03 23:07:34 +01:00
|
|
|
static bool g_anonymous_namespace_initialized;
|
2015-10-30 01:01:24 +01:00
|
|
|
|
2009-03-04 04:28:35 +01:00
|
|
|
#if STATS
|
2012-08-14 23:07:59 +02:00
|
|
|
struct linker_stats_t {
|
2014-09-12 18:43:13 +02:00
|
|
|
int count[kRelocMax];
|
2012-08-14 23:07:59 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
static linker_stats_t linker_stats;
|
|
|
|
|
2015-01-14 20:36:38 +01:00
|
|
|
void count_relocation(RelocationKind kind) {
|
2014-09-12 18:43:13 +02:00
|
|
|
++linker_stats.count[kind];
|
2012-08-14 23:07:59 +02:00
|
|
|
}
|
|
|
|
#else
|
2015-01-14 20:36:38 +01:00
|
|
|
void count_relocation(RelocationKind) {
|
2012-08-14 23:07:59 +02:00
|
|
|
}
|
2009-03-04 04:28:35 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#if COUNT_PAGES
|
2015-01-14 20:36:38 +01:00
|
|
|
uint32_t bitmask[4096];
|
2009-03-04 04:28:35 +01:00
|
|
|
#endif
|
|
|
|
|
2012-08-14 23:07:59 +02:00
|
|
|
static void notify_gdb_of_load(soinfo* info) {
|
2016-03-02 00:55:56 +01:00
|
|
|
if (info->is_linker() || info->is_main_executable()) {
|
|
|
|
// gdb already knows about the linker and the main executable.
|
2014-09-12 18:43:13 +02:00
|
|
|
return;
|
|
|
|
}
|
2009-03-04 04:28:35 +01:00
|
|
|
|
2016-02-18 01:08:03 +01:00
|
|
|
link_map* map = &(info->link_map_head);
|
2016-02-18 10:31:24 +01:00
|
|
|
|
2016-02-18 01:08:03 +01:00
|
|
|
map->l_addr = info->load_bias;
|
|
|
|
// link_map l_name field is not const.
|
|
|
|
map->l_name = const_cast<char*>(info->get_realpath());
|
|
|
|
map->l_ld = info->dynamic;
|
2016-02-18 10:31:24 +01:00
|
|
|
|
2016-03-02 00:55:56 +01:00
|
|
|
CHECK(map->l_name != nullptr);
|
|
|
|
CHECK(map->l_name[0] != '\0');
|
|
|
|
|
2016-02-18 01:08:03 +01:00
|
|
|
notify_gdb_of_load(map);
|
2009-03-25 03:02:00 +01:00
|
|
|
}
|
|
|
|
|
2012-08-14 23:07:59 +02:00
|
|
|
static void notify_gdb_of_unload(soinfo* info) {
|
2016-02-18 01:08:03 +01:00
|
|
|
notify_gdb_of_unload(&(info->link_map_head));
|
2009-03-04 04:28:35 +01:00
|
|
|
}
|
|
|
|
|
2014-05-09 18:10:14 +02:00
|
|
|
LinkedListEntry<soinfo>* SoinfoListAllocator::alloc() {
|
|
|
|
return g_soinfo_links_allocator.alloc();
|
|
|
|
}
|
|
|
|
|
|
|
|
void SoinfoListAllocator::free(LinkedListEntry<soinfo>* entry) {
|
|
|
|
g_soinfo_links_allocator.free(entry);
|
|
|
|
}
|
|
|
|
|
2016-04-11 21:42:58 +02:00
|
|
|
LinkedListEntry<android_namespace_t>* NamespaceListAllocator::alloc() {
|
|
|
|
return g_namespace_list_allocator.alloc();
|
|
|
|
}
|
|
|
|
|
|
|
|
void NamespaceListAllocator::free(LinkedListEntry<android_namespace_t>* entry) {
|
|
|
|
g_namespace_list_allocator.free(entry);
|
|
|
|
}
|
|
|
|
|
2016-09-09 19:00:39 +02:00
|
|
|
soinfo* soinfo_alloc(android_namespace_t* ns, const char* name,
|
|
|
|
struct stat* file_stat, off64_t file_offset,
|
|
|
|
uint32_t rtld_flags) {
|
2015-03-31 20:14:03 +02:00
|
|
|
if (strlen(name) >= PATH_MAX) {
|
2012-09-12 13:00:55 +02:00
|
|
|
DL_ERR("library name \"%s\" too long", name);
|
2014-08-29 21:02:36 +02:00
|
|
|
return nullptr;
|
2012-09-12 13:00:55 +02:00
|
|
|
}
|
|
|
|
|
2016-09-09 19:00:39 +02:00
|
|
|
TRACE("name %s: allocating soinfo for ns=%p", name, ns);
|
|
|
|
|
2015-10-30 01:01:24 +01:00
|
|
|
soinfo* si = new (g_soinfo_allocator.alloc()) soinfo(ns, name, file_stat,
|
|
|
|
file_offset, rtld_flags);
|
2014-05-09 18:10:14 +02:00
|
|
|
|
2016-09-09 19:00:39 +02:00
|
|
|
solist_add_soinfo(si);
|
2009-03-04 04:28:35 +01:00
|
|
|
|
2016-03-24 23:30:30 +01:00
|
|
|
si->generate_handle();
|
|
|
|
ns->add_soinfo(si);
|
2015-10-30 01:01:24 +01:00
|
|
|
|
2013-03-12 18:40:45 +01:00
|
|
|
TRACE("name %s: allocated soinfo @ %p", name, si);
|
2012-09-12 13:00:55 +02:00
|
|
|
return si;
|
2009-03-04 04:28:35 +01:00
|
|
|
}
|
|
|
|
|
2014-02-12 01:59:37 +01:00
|
|
|
static void soinfo_free(soinfo* si) {
|
2014-09-12 18:43:13 +02:00
|
|
|
if (si == nullptr) {
|
|
|
|
return;
|
|
|
|
}
|
2012-08-04 01:49:39 +02:00
|
|
|
|
2014-09-12 18:43:13 +02:00
|
|
|
if (si->base != 0 && si->size != 0) {
|
2016-01-15 20:13:35 +01:00
|
|
|
if (!si->is_mapped_by_caller()) {
|
|
|
|
munmap(reinterpret_cast<void*>(si->base), si->size);
|
|
|
|
} else {
|
|
|
|
// remap the region as PROT_NONE, MAP_ANONYMOUS | MAP_NORESERVE
|
|
|
|
mmap(reinterpret_cast<void*>(si->base), si->size, PROT_NONE,
|
|
|
|
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
|
|
|
|
}
|
2014-09-12 18:43:13 +02:00
|
|
|
}
|
2014-05-09 18:10:14 +02:00
|
|
|
|
2015-05-07 19:48:00 +02:00
|
|
|
TRACE("name %s: freeing soinfo @ %p", si->get_realpath(), si);
|
2009-03-04 04:28:35 +01:00
|
|
|
|
2016-09-09 19:00:39 +02:00
|
|
|
if (!solist_remove_soinfo(si)) {
|
|
|
|
// TODO (dimitry): revisit this - for now preserving the logic
|
|
|
|
// but it does not look right, abort if soinfo is not in the list instead?
|
2014-09-12 18:43:13 +02:00
|
|
|
return;
|
|
|
|
}
|
2009-03-04 04:28:35 +01:00
|
|
|
|
2014-09-12 18:43:13 +02:00
|
|
|
// clear links to/from si
|
|
|
|
si->remove_all_links();
|
2014-05-09 18:10:14 +02:00
|
|
|
|
2015-07-09 00:26:46 +02:00
|
|
|
si->~soinfo();
|
2014-09-12 18:43:13 +02:00
|
|
|
g_soinfo_allocator.free(si);
|
2009-03-04 04:28:35 +01:00
|
|
|
}
|
|
|
|
|
2015-10-30 01:01:24 +01:00
|
|
|
static void parse_path(const char* path, const char* delimiters,
|
|
|
|
std::vector<std::string>* resolved_paths) {
|
|
|
|
std::vector<std::string> paths;
|
|
|
|
split_path(path, delimiters, &paths);
|
|
|
|
resolve_paths(paths, resolved_paths);
|
|
|
|
}
|
|
|
|
|
2012-12-20 23:42:14 +01:00
|
|
|
static void parse_LD_LIBRARY_PATH(const char* path) {
|
2015-10-30 01:01:24 +01:00
|
|
|
std::vector<std::string> ld_libary_paths;
|
|
|
|
parse_path(path, ":", &ld_libary_paths);
|
|
|
|
g_default_namespace.set_ld_library_paths(std::move(ld_libary_paths));
|
2012-12-20 23:42:14 +01:00
|
|
|
}
|
|
|
|
|
2015-03-31 20:14:03 +02:00
|
|
|
static bool realpath_fd(int fd, std::string* realpath) {
|
|
|
|
std::vector<char> buf(PATH_MAX), proc_self_fd(PATH_MAX);
|
2015-10-02 03:41:57 +02:00
|
|
|
__libc_format_buffer(&proc_self_fd[0], proc_self_fd.size(), "/proc/self/fd/%d", fd);
|
2015-03-31 20:14:03 +02:00
|
|
|
if (readlink(&proc_self_fd[0], &buf[0], buf.size()) == -1) {
|
2016-07-21 20:33:40 +02:00
|
|
|
PRINT("readlink(\"%s\") failed: %s [fd=%d]", &proc_self_fd[0], strerror(errno), fd);
|
2015-03-31 20:14:03 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-10-02 03:41:57 +02:00
|
|
|
*realpath = &buf[0];
|
2015-03-31 20:14:03 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-10-26 02:38:02 +02:00
|
|
|
#if defined(__arm__)
|
2012-08-04 01:49:39 +02:00
|
|
|
|
2014-09-12 18:43:13 +02:00
|
|
|
// For a given PC, find the .so that it belongs to.
|
|
|
|
// Returns the base address of the .ARM.exidx section
|
|
|
|
// for that .so, and the number of 8-byte entries
|
|
|
|
// in that section (via *pcount).
|
|
|
|
//
|
|
|
|
// Intended to be called by libc's __gnu_Unwind_Find_exidx().
|
2016-11-23 01:55:25 +01:00
|
|
|
_Unwind_Ptr do_dl_unwind_find_exidx(_Unwind_Ptr pc, int* pcount) {
|
2015-01-23 01:04:25 +01:00
|
|
|
uintptr_t addr = reinterpret_cast<uintptr_t>(pc);
|
2009-03-04 04:28:35 +01:00
|
|
|
|
2016-09-09 19:00:39 +02:00
|
|
|
for (soinfo* si = solist_get_head(); si != 0; si = si->next) {
|
2014-09-12 18:43:13 +02:00
|
|
|
if ((addr >= si->base) && (addr < (si->base + si->size))) {
|
|
|
|
*pcount = si->ARM_exidx_count;
|
2015-01-23 01:04:25 +01:00
|
|
|
return reinterpret_cast<_Unwind_Ptr>(si->ARM_exidx);
|
2009-03-04 04:28:35 +01:00
|
|
|
}
|
2014-09-12 18:43:13 +02:00
|
|
|
}
|
|
|
|
*pcount = 0;
|
|
|
|
return nullptr;
|
2009-03-04 04:28:35 +01:00
|
|
|
}
|
2012-08-04 01:49:39 +02:00
|
|
|
|
2013-08-20 02:45:09 +02:00
|
|
|
#endif
|
2012-08-04 01:49:39 +02:00
|
|
|
|
2014-09-12 18:43:13 +02:00
|
|
|
// Here, we only have to provide a callback to iterate across all the
|
|
|
|
// loaded libraries. gcc_eh does the rest.
|
2015-06-29 23:48:25 +02:00
|
|
|
int do_dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void* data) {
|
2014-09-12 18:43:13 +02:00
|
|
|
int rv = 0;
|
2016-09-09 19:00:39 +02:00
|
|
|
for (soinfo* si = solist_get_head(); si != nullptr; si = si->next) {
|
2014-09-12 18:43:13 +02:00
|
|
|
dl_phdr_info dl_info;
|
|
|
|
dl_info.dlpi_addr = si->link_map_head.l_addr;
|
|
|
|
dl_info.dlpi_name = si->link_map_head.l_name;
|
|
|
|
dl_info.dlpi_phdr = si->phdr;
|
|
|
|
dl_info.dlpi_phnum = si->phnum;
|
|
|
|
rv = cb(&dl_info, sizeof(dl_phdr_info), data);
|
|
|
|
if (rv != 0) {
|
|
|
|
break;
|
2009-03-04 04:28:35 +01:00
|
|
|
}
|
2014-09-12 18:43:13 +02:00
|
|
|
}
|
|
|
|
return rv;
|
2009-03-04 04:28:35 +01:00
|
|
|
}
|
2012-08-04 01:49:39 +02:00
|
|
|
|
2009-03-04 04:28:35 +01:00
|
|
|
|
2015-04-09 22:42:33 +02:00
|
|
|
bool soinfo_do_lookup(soinfo* si_from, const char* name, const version_info* vi,
|
2016-08-04 01:00:10 +02:00
|
|
|
soinfo** si_found_in, const soinfo_list_t& global_group,
|
|
|
|
const soinfo_list_t& local_group, const ElfW(Sym)** symbol) {
|
2014-11-10 04:27:20 +01:00
|
|
|
SymbolName symbol_name(name);
|
2015-04-09 22:42:33 +02:00
|
|
|
const ElfW(Sym)* s = nullptr;
|
2009-09-29 04:38:04 +02:00
|
|
|
|
2014-09-29 21:10:36 +02:00
|
|
|
/* "This element's presence in a shared object library alters the dynamic linker's
|
|
|
|
* symbol resolution algorithm for references within the library. Instead of starting
|
|
|
|
* a symbol search with the executable file, the dynamic linker starts from the shared
|
|
|
|
* object itself. If the shared object fails to supply the referenced symbol, the
|
|
|
|
* dynamic linker then searches the executable file and other shared objects as usual."
|
|
|
|
*
|
|
|
|
* http://www.sco.com/developers/gabi/2012-12-31/ch5.dynamic.html
|
|
|
|
*
|
|
|
|
* Note that this is unlikely since static linker avoids generating
|
|
|
|
* relocations for -Bsymbolic linked dynamic executables.
|
|
|
|
*/
|
2014-08-28 23:12:12 +02:00
|
|
|
if (si_from->has_DT_SYMBOLIC) {
|
2015-05-07 19:48:00 +02:00
|
|
|
DEBUG("%s: looking up %s in local scope (DT_SYMBOLIC)", si_from->get_realpath(), name);
|
2015-04-09 22:42:33 +02:00
|
|
|
if (!si_from->find_symbol_by_name(symbol_name, vi, &s)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-09-16 23:31:06 +02:00
|
|
|
if (s != nullptr) {
|
2014-08-28 23:12:12 +02:00
|
|
|
*si_found_in = si_from;
|
2014-09-29 21:10:36 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-28 23:12:12 +02:00
|
|
|
// 1. Look for it in global_group
|
|
|
|
if (s == nullptr) {
|
2015-04-09 22:42:33 +02:00
|
|
|
bool error = false;
|
2014-08-28 23:12:12 +02:00
|
|
|
global_group.visit([&](soinfo* global_si) {
|
2015-03-31 20:14:03 +02:00
|
|
|
DEBUG("%s: looking up %s in %s (from global group)",
|
2015-05-07 19:48:00 +02:00
|
|
|
si_from->get_realpath(), name, global_si->get_realpath());
|
2015-04-09 22:42:33 +02:00
|
|
|
if (!global_si->find_symbol_by_name(symbol_name, vi, &s)) {
|
|
|
|
error = true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-09-29 21:10:36 +02:00
|
|
|
if (s != nullptr) {
|
2014-08-28 23:12:12 +02:00
|
|
|
*si_found_in = global_si;
|
|
|
|
return false;
|
2014-09-29 21:10:36 +02:00
|
|
|
}
|
2012-10-31 10:55:51 +01:00
|
|
|
|
2014-08-28 23:12:12 +02:00
|
|
|
return true;
|
|
|
|
});
|
2015-04-09 22:42:33 +02:00
|
|
|
|
|
|
|
if (error) {
|
|
|
|
return false;
|
|
|
|
}
|
2014-09-29 21:10:36 +02:00
|
|
|
}
|
2012-10-31 10:55:51 +01:00
|
|
|
|
2014-08-28 23:12:12 +02:00
|
|
|
// 2. Look for it in the local group
|
2014-10-21 18:23:18 +02:00
|
|
|
if (s == nullptr) {
|
2015-04-09 22:42:33 +02:00
|
|
|
bool error = false;
|
2014-10-21 18:23:18 +02:00
|
|
|
local_group.visit([&](soinfo* local_si) {
|
2014-08-28 23:12:12 +02:00
|
|
|
if (local_si == si_from && si_from->has_DT_SYMBOLIC) {
|
2014-10-23 23:19:07 +02:00
|
|
|
// we already did this - skip
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-03-31 20:14:03 +02:00
|
|
|
DEBUG("%s: looking up %s in %s (from local group)",
|
2015-05-07 19:48:00 +02:00
|
|
|
si_from->get_realpath(), name, local_si->get_realpath());
|
2015-04-09 22:42:33 +02:00
|
|
|
if (!local_si->find_symbol_by_name(symbol_name, vi, &s)) {
|
|
|
|
error = true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-10-21 18:23:18 +02:00
|
|
|
if (s != nullptr) {
|
2014-08-28 23:12:12 +02:00
|
|
|
*si_found_in = local_si;
|
2014-10-21 18:23:18 +02:00
|
|
|
return false;
|
|
|
|
}
|
2014-09-12 18:43:13 +02:00
|
|
|
|
2014-10-21 18:23:18 +02:00
|
|
|
return true;
|
|
|
|
});
|
2015-04-09 22:42:33 +02:00
|
|
|
|
|
|
|
if (error) {
|
|
|
|
return false;
|
|
|
|
}
|
2014-10-21 18:23:18 +02:00
|
|
|
}
|
|
|
|
|
2014-09-12 18:43:13 +02:00
|
|
|
if (s != nullptr) {
|
|
|
|
TRACE_TYPE(LOOKUP, "si %s sym %s s->st_value = %p, "
|
|
|
|
"found in %s, base = %p, load bias = %p",
|
2015-05-07 19:48:00 +02:00
|
|
|
si_from->get_realpath(), name, reinterpret_cast<void*>(s->st_value),
|
|
|
|
(*si_found_in)->get_realpath(), reinterpret_cast<void*>((*si_found_in)->base),
|
2014-08-28 23:12:12 +02:00
|
|
|
reinterpret_cast<void*>((*si_found_in)->load_bias));
|
2014-09-12 18:43:13 +02:00
|
|
|
}
|
|
|
|
|
2015-04-09 22:42:33 +02:00
|
|
|
*symbol = s;
|
|
|
|
return true;
|
2009-09-29 04:38:04 +02:00
|
|
|
}
|
|
|
|
|
2016-09-09 19:00:39 +02:00
|
|
|
ProtectedDataGuard::ProtectedDataGuard() {
|
|
|
|
if (ref_count_++ == 0) {
|
|
|
|
protect_data(PROT_READ | PROT_WRITE);
|
2015-01-23 21:03:53 +01:00
|
|
|
}
|
|
|
|
|
2016-09-09 19:00:39 +02:00
|
|
|
if (ref_count_ == 0) { // overflow
|
|
|
|
__libc_fatal("Too many nested calls to dlopen()");
|
2015-01-23 21:03:53 +01:00
|
|
|
}
|
2017-02-01 21:55:11 +01:00
|
|
|
}
|
2016-09-09 19:00:39 +02:00
|
|
|
|
2017-02-01 21:55:11 +01:00
|
|
|
ProtectedDataGuard::~ProtectedDataGuard() {
|
2016-09-09 19:00:39 +02:00
|
|
|
if (--ref_count_ == 0) {
|
|
|
|
protect_data(PROT_READ);
|
2015-01-23 21:03:53 +01:00
|
|
|
}
|
2016-09-09 19:00:39 +02:00
|
|
|
}
|
2015-01-23 21:03:53 +01:00
|
|
|
|
2016-09-09 19:00:39 +02:00
|
|
|
void ProtectedDataGuard::protect_data(int protection) {
|
|
|
|
g_soinfo_allocator.protect_all(protection);
|
|
|
|
g_soinfo_links_allocator.protect_all(protection);
|
|
|
|
g_namespace_allocator.protect_all(protection);
|
|
|
|
g_namespace_list_allocator.protect_all(protection);
|
|
|
|
}
|
2015-01-23 21:03:53 +01:00
|
|
|
|
|
|
|
size_t ProtectedDataGuard::ref_count_ = 0;
|
|
|
|
|
2014-09-02 01:15:52 +02:00
|
|
|
// Each size has it's own allocator.
|
|
|
|
template<size_t size>
|
|
|
|
class SizeBasedAllocator {
|
|
|
|
public:
|
|
|
|
static void* alloc() {
|
|
|
|
return allocator_.alloc();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void free(void* ptr) {
|
|
|
|
allocator_.free(ptr);
|
|
|
|
}
|
2014-08-29 23:01:48 +02:00
|
|
|
|
2014-09-02 01:15:52 +02:00
|
|
|
private:
|
|
|
|
static LinkerBlockAllocator allocator_;
|
|
|
|
};
|
|
|
|
|
|
|
|
template<size_t size>
|
|
|
|
LinkerBlockAllocator SizeBasedAllocator<size>::allocator_(size);
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
class TypeBasedAllocator {
|
|
|
|
public:
|
|
|
|
static T* alloc() {
|
|
|
|
return reinterpret_cast<T*>(SizeBasedAllocator<sizeof(T)>::alloc());
|
|
|
|
}
|
|
|
|
|
|
|
|
static void free(T* ptr) {
|
|
|
|
SizeBasedAllocator<sizeof(T)>::free(ptr);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-09-06 01:42:53 +02:00
|
|
|
class LoadTask {
|
|
|
|
public:
|
|
|
|
struct deleter_t {
|
|
|
|
void operator()(LoadTask* t) {
|
2015-10-15 21:07:25 +02:00
|
|
|
t->~LoadTask();
|
2014-09-06 01:42:53 +02:00
|
|
|
TypeBasedAllocator<LoadTask>::free(t);
|
|
|
|
}
|
|
|
|
};
|
2014-07-29 23:21:45 +02:00
|
|
|
|
2014-09-06 01:42:53 +02:00
|
|
|
static deleter_t deleter;
|
|
|
|
|
2017-02-02 00:28:52 +01:00
|
|
|
static LoadTask* create(const char* name,
|
|
|
|
soinfo* needed_by,
|
2015-10-15 21:07:25 +02:00
|
|
|
std::unordered_map<const soinfo*, ElfReader>* readers_map) {
|
2014-09-06 01:42:53 +02:00
|
|
|
LoadTask* ptr = TypeBasedAllocator<LoadTask>::alloc();
|
2015-10-15 21:07:25 +02:00
|
|
|
return new (ptr) LoadTask(name, needed_by, readers_map);
|
2014-07-29 02:32:20 +02:00
|
|
|
}
|
2014-07-29 23:21:45 +02:00
|
|
|
|
2014-09-06 01:42:53 +02:00
|
|
|
const char* get_name() const {
|
|
|
|
return name_;
|
2014-07-29 23:21:45 +02:00
|
|
|
}
|
2014-09-06 01:42:53 +02:00
|
|
|
|
|
|
|
soinfo* get_needed_by() const {
|
|
|
|
return needed_by_;
|
|
|
|
}
|
2015-10-15 21:07:25 +02:00
|
|
|
|
|
|
|
soinfo* get_soinfo() const {
|
|
|
|
return si_;
|
|
|
|
}
|
|
|
|
|
|
|
|
void set_soinfo(soinfo* si) {
|
|
|
|
si_ = si;
|
|
|
|
}
|
|
|
|
|
|
|
|
off64_t get_file_offset() const {
|
|
|
|
return file_offset_;
|
|
|
|
}
|
|
|
|
|
|
|
|
void set_file_offset(off64_t offset) {
|
|
|
|
file_offset_ = offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
int get_fd() const {
|
|
|
|
return fd_;
|
|
|
|
}
|
|
|
|
|
|
|
|
void set_fd(int fd, bool assume_ownership) {
|
|
|
|
fd_ = fd;
|
|
|
|
close_fd_ = assume_ownership;
|
|
|
|
}
|
|
|
|
|
|
|
|
const android_dlextinfo* get_extinfo() const {
|
|
|
|
return extinfo_;
|
|
|
|
}
|
|
|
|
|
|
|
|
void set_extinfo(const android_dlextinfo* extinfo) {
|
|
|
|
extinfo_ = extinfo;
|
|
|
|
}
|
|
|
|
|
2016-07-21 20:33:40 +02:00
|
|
|
bool is_dt_needed() const {
|
|
|
|
return is_dt_needed_;
|
|
|
|
}
|
|
|
|
|
|
|
|
void set_dt_needed(bool is_dt_needed) {
|
|
|
|
is_dt_needed_ = is_dt_needed;
|
|
|
|
}
|
|
|
|
|
2015-10-15 21:07:25 +02:00
|
|
|
const ElfReader& get_elf_reader() const {
|
|
|
|
CHECK(si_ != nullptr);
|
|
|
|
return (*elf_readers_map_)[si_];
|
|
|
|
}
|
|
|
|
|
|
|
|
ElfReader& get_elf_reader() {
|
|
|
|
CHECK(si_ != nullptr);
|
|
|
|
return (*elf_readers_map_)[si_];
|
|
|
|
}
|
|
|
|
|
|
|
|
std::unordered_map<const soinfo*, ElfReader>* get_readers_map() {
|
|
|
|
return elf_readers_map_;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool read(const char* realpath, off64_t file_size) {
|
|
|
|
ElfReader& elf_reader = get_elf_reader();
|
|
|
|
return elf_reader.Read(realpath, fd_, file_offset_, file_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool load() {
|
|
|
|
ElfReader& elf_reader = get_elf_reader();
|
|
|
|
if (!elf_reader.Load(extinfo_)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
si_->base = elf_reader.load_start();
|
|
|
|
si_->size = elf_reader.load_size();
|
2016-01-15 20:13:35 +01:00
|
|
|
si_->set_mapped_by_caller(elf_reader.is_mapped_by_caller());
|
2015-10-15 21:07:25 +02:00
|
|
|
si_->load_bias = elf_reader.load_bias();
|
|
|
|
si_->phnum = elf_reader.phdr_count();
|
|
|
|
si_->phdr = elf_reader.loaded_phdr();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-09-06 01:42:53 +02:00
|
|
|
private:
|
2017-02-02 00:28:52 +01:00
|
|
|
LoadTask(const char* name,
|
|
|
|
soinfo* needed_by,
|
2015-10-15 21:07:25 +02:00
|
|
|
std::unordered_map<const soinfo*, ElfReader>* readers_map)
|
|
|
|
: name_(name), needed_by_(needed_by), si_(nullptr),
|
2016-07-21 20:33:40 +02:00
|
|
|
fd_(-1), close_fd_(false), file_offset_(0), elf_readers_map_(readers_map),
|
|
|
|
is_dt_needed_(false) {}
|
2015-10-15 21:07:25 +02:00
|
|
|
|
|
|
|
~LoadTask() {
|
|
|
|
if (fd_ != -1 && close_fd_) {
|
|
|
|
close(fd_);
|
|
|
|
}
|
|
|
|
}
|
2014-09-06 01:42:53 +02:00
|
|
|
|
|
|
|
const char* name_;
|
|
|
|
soinfo* needed_by_;
|
2015-10-15 21:07:25 +02:00
|
|
|
soinfo* si_;
|
|
|
|
const android_dlextinfo* extinfo_;
|
|
|
|
int fd_;
|
|
|
|
bool close_fd_;
|
|
|
|
off64_t file_offset_;
|
|
|
|
std::unordered_map<const soinfo*, ElfReader>* elf_readers_map_;
|
2016-07-21 20:33:40 +02:00
|
|
|
// TODO(dimitry): needed by workaround for http://b/26394120 (the grey-list)
|
|
|
|
bool is_dt_needed_;
|
|
|
|
// END OF WORKAROUND
|
2014-09-06 01:42:53 +02:00
|
|
|
|
|
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(LoadTask);
|
2014-07-29 02:32:20 +02:00
|
|
|
};
|
|
|
|
|
2014-09-16 09:22:10 +02:00
|
|
|
LoadTask::deleter_t LoadTask::deleter;
|
|
|
|
|
2014-09-06 01:42:53 +02:00
|
|
|
template <typename T>
|
|
|
|
using linked_list_t = LinkedList<T, TypeBasedAllocator<LinkedListEntry<T>>>;
|
|
|
|
|
|
|
|
typedef linked_list_t<soinfo> SoinfoLinkedList;
|
|
|
|
typedef linked_list_t<const char> StringLinkedList;
|
2015-10-15 21:07:25 +02:00
|
|
|
typedef std::vector<LoadTask*> LoadTaskList;
|
2014-09-06 01:42:53 +02:00
|
|
|
|
2017-02-03 23:07:34 +01:00
|
|
|
enum walk_action_result_t : uint32_t {
|
|
|
|
kWalkStop = 0,
|
|
|
|
kWalkContinue = 1,
|
|
|
|
kWalkSkip = 2
|
|
|
|
};
|
2014-09-06 01:42:53 +02:00
|
|
|
|
2014-10-21 18:23:18 +02:00
|
|
|
// This function walks down the tree of soinfo dependencies
|
|
|
|
// in breadth-first order and
|
|
|
|
// * calls action(soinfo* si) for each node, and
|
2017-02-03 23:07:34 +01:00
|
|
|
// * terminates walk if action returns kWalkStop
|
|
|
|
// * skips children of the node if action
|
|
|
|
// return kWalkSkip
|
2014-10-21 18:23:18 +02:00
|
|
|
//
|
|
|
|
// walk_dependencies_tree returns false if walk was terminated
|
|
|
|
// by the action and true otherwise.
|
|
|
|
template<typename F>
|
|
|
|
static bool walk_dependencies_tree(soinfo* root_soinfos[], size_t root_soinfos_size, F action) {
|
2014-09-02 01:15:52 +02:00
|
|
|
SoinfoLinkedList visit_list;
|
|
|
|
SoinfoLinkedList visited;
|
|
|
|
|
2014-10-21 18:23:18 +02:00
|
|
|
for (size_t i = 0; i < root_soinfos_size; ++i) {
|
|
|
|
visit_list.push_back(root_soinfos[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
soinfo* si;
|
|
|
|
while ((si = visit_list.pop_front()) != nullptr) {
|
|
|
|
if (visited.contains(si)) {
|
2014-08-13 06:02:13 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-02-03 23:07:34 +01:00
|
|
|
walk_action_result_t result = action(si);
|
|
|
|
|
|
|
|
if (result == kWalkStop) {
|
2014-10-21 18:23:18 +02:00
|
|
|
return false;
|
2014-07-29 02:32:20 +02:00
|
|
|
}
|
|
|
|
|
2014-10-21 18:23:18 +02:00
|
|
|
visited.push_back(si);
|
|
|
|
|
2017-02-03 23:07:34 +01:00
|
|
|
if (result != kWalkSkip) {
|
|
|
|
si->get_children().for_each([&](soinfo* child) {
|
|
|
|
visit_list.push_back(child);
|
|
|
|
});
|
|
|
|
}
|
2014-07-29 02:32:20 +02:00
|
|
|
}
|
|
|
|
|
2014-10-21 18:23:18 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-02-03 23:07:34 +01:00
|
|
|
static const ElfW(Sym)* dlsym_handle_lookup(android_namespace_t* ns,
|
|
|
|
soinfo* root,
|
|
|
|
soinfo* skip_until,
|
|
|
|
soinfo** found,
|
|
|
|
SymbolName& symbol_name,
|
2015-12-11 01:08:14 +01:00
|
|
|
const version_info* vi) {
|
2015-04-09 22:42:33 +02:00
|
|
|
const ElfW(Sym)* result = nullptr;
|
2015-05-12 20:12:27 +02:00
|
|
|
bool skip_lookup = skip_until != nullptr;
|
|
|
|
|
|
|
|
walk_dependencies_tree(&root, 1, [&](soinfo* current_soinfo) {
|
|
|
|
if (skip_lookup) {
|
|
|
|
skip_lookup = current_soinfo != skip_until;
|
2017-02-03 23:07:34 +01:00
|
|
|
return kWalkContinue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ns->is_accessible(current_soinfo)) {
|
|
|
|
return kWalkSkip;
|
2015-05-12 20:12:27 +02:00
|
|
|
}
|
2014-10-21 18:23:18 +02:00
|
|
|
|
2015-12-11 01:08:14 +01:00
|
|
|
if (!current_soinfo->find_symbol_by_name(symbol_name, vi, &result)) {
|
2015-04-09 22:42:33 +02:00
|
|
|
result = nullptr;
|
2017-02-03 23:07:34 +01:00
|
|
|
return kWalkStop;
|
2015-04-09 22:42:33 +02:00
|
|
|
}
|
|
|
|
|
2014-10-21 18:23:18 +02:00
|
|
|
if (result != nullptr) {
|
|
|
|
*found = current_soinfo;
|
2017-02-03 23:07:34 +01:00
|
|
|
return kWalkStop;
|
2014-10-21 18:23:18 +02:00
|
|
|
}
|
|
|
|
|
2017-02-03 23:07:34 +01:00
|
|
|
return kWalkContinue;
|
2014-10-21 18:23:18 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
return result;
|
2009-03-04 04:28:35 +01:00
|
|
|
}
|
|
|
|
|
2015-12-11 01:08:14 +01:00
|
|
|
static const ElfW(Sym)* dlsym_linear_lookup(android_namespace_t* ns,
|
|
|
|
const char* name,
|
|
|
|
const version_info* vi,
|
|
|
|
soinfo** found,
|
|
|
|
soinfo* caller,
|
|
|
|
void* handle);
|
|
|
|
|
2015-05-12 20:12:27 +02:00
|
|
|
// This is used by dlsym(3). It performs symbol lookup only within the
|
|
|
|
// specified soinfo object and its dependencies in breadth first order.
|
2017-02-03 23:07:34 +01:00
|
|
|
static const ElfW(Sym)* dlsym_handle_lookup(soinfo* si,
|
|
|
|
soinfo** found,
|
|
|
|
const char* name,
|
|
|
|
const version_info* vi) {
|
2015-05-30 22:04:39 +02:00
|
|
|
// According to man dlopen(3) and posix docs in the case when si is handle
|
|
|
|
// of the main executable we need to search not only in the executable and its
|
|
|
|
// dependencies but also in all libraries loaded with RTLD_GLOBAL.
|
|
|
|
//
|
|
|
|
// Since RTLD_GLOBAL is always set for the main executable and all dt_needed shared
|
|
|
|
// libraries and they are loaded in breath-first (correct) order we can just execute
|
|
|
|
// dlsym(RTLD_DEFAULT, ...); instead of doing two stage lookup.
|
2016-09-09 19:00:39 +02:00
|
|
|
if (si == solist_get_somain()) {
|
2015-12-11 01:08:14 +01:00
|
|
|
return dlsym_linear_lookup(&g_default_namespace, name, vi, found, nullptr, RTLD_DEFAULT);
|
2015-05-30 22:04:39 +02:00
|
|
|
}
|
|
|
|
|
2015-05-12 20:12:27 +02:00
|
|
|
SymbolName symbol_name(name);
|
2017-02-03 23:07:34 +01:00
|
|
|
// note that the namespace is not the namespace associated with caller_addr
|
|
|
|
// we use ns associated with root si intentionally here. Using caller_ns
|
|
|
|
// causes problems when user uses dlopen_ext to open a library in the separate
|
|
|
|
// namespace and then calls dlsym() on the handle.
|
|
|
|
return dlsym_handle_lookup(si->get_primary_namespace(), si, nullptr, found, symbol_name, vi);
|
2015-05-12 20:12:27 +02:00
|
|
|
}
|
|
|
|
|
2013-03-01 00:58:45 +01:00
|
|
|
/* This is used by dlsym(3) to performs a global symbol lookup. If the
|
|
|
|
start value is null (for RTLD_DEFAULT), the search starts at the
|
|
|
|
beginning of the global solist. Otherwise the search starts at the
|
|
|
|
specified soinfo (for RTLD_NEXT).
|
2009-09-29 04:38:04 +02:00
|
|
|
*/
|
2015-12-11 01:08:14 +01:00
|
|
|
static const ElfW(Sym)* dlsym_linear_lookup(android_namespace_t* ns,
|
|
|
|
const char* name,
|
|
|
|
const version_info* vi,
|
|
|
|
soinfo** found,
|
|
|
|
soinfo* caller,
|
|
|
|
void* handle) {
|
2014-11-10 04:27:20 +01:00
|
|
|
SymbolName symbol_name(name);
|
2009-03-04 04:28:35 +01:00
|
|
|
|
2016-03-24 23:30:30 +01:00
|
|
|
auto& soinfo_list = ns->soinfo_list();
|
|
|
|
auto start = soinfo_list.begin();
|
2015-04-01 23:45:10 +02:00
|
|
|
|
|
|
|
if (handle == RTLD_NEXT) {
|
2015-05-22 21:34:42 +02:00
|
|
|
if (caller == nullptr) {
|
2015-04-01 23:45:10 +02:00
|
|
|
return nullptr;
|
|
|
|
} else {
|
2016-03-24 23:30:30 +01:00
|
|
|
auto it = soinfo_list.find(caller);
|
2015-10-30 01:01:24 +01:00
|
|
|
CHECK (it != soinfo_list.end());
|
|
|
|
start = ++it;
|
2015-04-01 23:45:10 +02:00
|
|
|
}
|
2012-12-20 23:42:14 +01:00
|
|
|
}
|
2009-12-31 19:17:56 +01:00
|
|
|
|
2015-04-09 22:42:33 +02:00
|
|
|
const ElfW(Sym)* s = nullptr;
|
2016-03-24 23:30:30 +01:00
|
|
|
for (auto it = start, end = soinfo_list.end(); it != end; ++it) {
|
2015-10-30 01:01:24 +01:00
|
|
|
soinfo* si = *it;
|
2015-06-03 02:36:54 +02:00
|
|
|
// Do not skip RTLD_LOCAL libraries in dlsym(RTLD_DEFAULT, ...)
|
2016-11-16 20:35:43 +01:00
|
|
|
// if the library is opened by application with target api level < M.
|
2015-06-03 02:36:54 +02:00
|
|
|
// See http://b/21565766
|
2016-11-16 20:35:43 +01:00
|
|
|
if ((si->get_rtld_flags() & RTLD_GLOBAL) == 0 &&
|
|
|
|
si->get_target_sdk_version() >= __ANDROID_API_M__) {
|
2014-09-16 02:00:10 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2015-12-11 01:08:14 +01:00
|
|
|
if (!si->find_symbol_by_name(symbol_name, vi, &s)) {
|
2015-04-09 22:42:33 +02:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2014-08-29 21:02:36 +02:00
|
|
|
if (s != nullptr) {
|
2012-12-20 23:42:14 +01:00
|
|
|
*found = si;
|
|
|
|
break;
|
2009-03-04 04:28:35 +01:00
|
|
|
}
|
2012-12-20 23:42:14 +01:00
|
|
|
}
|
2009-03-04 04:28:35 +01:00
|
|
|
|
2015-05-12 20:12:27 +02:00
|
|
|
// If not found - use dlsym_handle_lookup for caller's
|
|
|
|
// local_group unless it is part of the global group in which
|
2015-04-01 23:45:10 +02:00
|
|
|
// case we already did it.
|
|
|
|
if (s == nullptr && caller != nullptr &&
|
|
|
|
(caller->get_rtld_flags() & RTLD_GLOBAL) == 0) {
|
2017-02-03 23:07:34 +01:00
|
|
|
soinfo* local_group_root = caller->get_local_group_root();
|
|
|
|
|
|
|
|
return dlsym_handle_lookup(local_group_root->get_primary_namespace(),
|
|
|
|
local_group_root,
|
|
|
|
(handle == RTLD_NEXT) ? caller : nullptr,
|
|
|
|
found,
|
|
|
|
symbol_name,
|
|
|
|
vi);
|
2015-04-01 23:45:10 +02:00
|
|
|
}
|
|
|
|
|
2014-08-29 21:02:36 +02:00
|
|
|
if (s != nullptr) {
|
2013-10-05 02:01:33 +02:00
|
|
|
TRACE_TYPE(LOOKUP, "%s s->st_value = %p, found->base = %p",
|
|
|
|
name, reinterpret_cast<void*>(s->st_value), reinterpret_cast<void*>((*found)->base));
|
2012-12-20 23:42:14 +01:00
|
|
|
}
|
2009-03-04 04:28:35 +01:00
|
|
|
|
2012-12-20 23:42:14 +01:00
|
|
|
return s;
|
2009-03-04 04:28:35 +01:00
|
|
|
}
|
|
|
|
|
2013-03-12 07:58:06 +01:00
|
|
|
soinfo* find_containing_library(const void* p) {
|
2014-02-11 02:46:57 +01:00
|
|
|
ElfW(Addr) address = reinterpret_cast<ElfW(Addr)>(p);
|
2016-09-09 19:00:39 +02:00
|
|
|
for (soinfo* si = solist_get_head(); si != nullptr; si = si->next) {
|
2013-03-12 07:58:06 +01:00
|
|
|
if (address >= si->base && address - si->base < si->size) {
|
|
|
|
return si;
|
2009-12-31 19:17:40 +01:00
|
|
|
}
|
2013-03-12 07:58:06 +01:00
|
|
|
}
|
2014-08-29 21:02:36 +02:00
|
|
|
return nullptr;
|
2009-12-31 19:17:40 +01:00
|
|
|
}
|
|
|
|
|
2015-09-29 01:38:31 +02:00
|
|
|
class ZipArchiveCache {
|
|
|
|
public:
|
|
|
|
ZipArchiveCache() {}
|
|
|
|
~ZipArchiveCache();
|
|
|
|
|
|
|
|
bool get_or_open(const char* zip_path, ZipArchiveHandle* handle);
|
|
|
|
private:
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(ZipArchiveCache);
|
|
|
|
|
|
|
|
std::unordered_map<std::string, ZipArchiveHandle> cache_;
|
|
|
|
};
|
|
|
|
|
|
|
|
bool ZipArchiveCache::get_or_open(const char* zip_path, ZipArchiveHandle* handle) {
|
|
|
|
std::string key(zip_path);
|
|
|
|
|
|
|
|
auto it = cache_.find(key);
|
|
|
|
if (it != cache_.end()) {
|
|
|
|
*handle = it->second;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
int fd = TEMP_FAILURE_RETRY(open(zip_path, O_RDONLY | O_CLOEXEC));
|
|
|
|
if (fd == -1) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (OpenArchiveFd(fd, "", handle) != 0) {
|
|
|
|
// invalid zip-file (?)
|
2016-03-22 01:10:12 +01:00
|
|
|
CloseArchive(handle);
|
2015-09-29 01:38:31 +02:00
|
|
|
close(fd);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
cache_[key] = *handle;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
ZipArchiveCache::~ZipArchiveCache() {
|
2015-10-13 21:14:16 +02:00
|
|
|
for (const auto& it : cache_) {
|
2015-09-29 01:38:31 +02:00
|
|
|
CloseArchive(it.second);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int open_library_in_zipfile(ZipArchiveCache* zip_archive_cache,
|
2015-10-02 03:41:57 +02:00
|
|
|
const char* const input_path,
|
|
|
|
off64_t* file_offset, std::string* realpath) {
|
|
|
|
std::string normalized_path;
|
|
|
|
if (!normalize_path(input_path, &normalized_path)) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* const path = normalized_path.c_str();
|
2016-07-21 20:33:40 +02:00
|
|
|
TRACE("Trying zip file open from path \"%s\" -> normalized \"%s\"", input_path, path);
|
2015-01-16 14:22:54 +01:00
|
|
|
|
2015-06-09 22:46:51 +02:00
|
|
|
// Treat an '!/' separator inside a path as the separator between the name
|
2015-01-16 14:22:54 +01:00
|
|
|
// of the zip file on disk and the subdirectory to search within it.
|
2015-06-09 22:46:51 +02:00
|
|
|
// For example, if path is "foo.zip!/bar/bas/x.so", then we search for
|
2015-01-16 14:22:54 +01:00
|
|
|
// "bar/bas/x.so" within "foo.zip".
|
2015-10-02 03:41:57 +02:00
|
|
|
const char* const separator = strstr(path, kZipFileSeparator);
|
2015-01-16 14:22:54 +01:00
|
|
|
if (separator == nullptr) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
char buf[512];
|
|
|
|
if (strlcpy(buf, path, sizeof(buf)) >= sizeof(buf)) {
|
|
|
|
PRINT("Warning: ignoring very long library path: %s", path);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
buf[separator - path] = '\0';
|
|
|
|
|
|
|
|
const char* zip_path = buf;
|
2015-06-09 22:46:51 +02:00
|
|
|
const char* file_path = &buf[separator - path + 2];
|
2015-01-16 14:22:54 +01:00
|
|
|
int fd = TEMP_FAILURE_RETRY(open(zip_path, O_RDONLY | O_CLOEXEC));
|
|
|
|
if (fd == -1) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
ZipArchiveHandle handle;
|
2015-09-29 01:38:31 +02:00
|
|
|
if (!zip_archive_cache->get_or_open(zip_path, &handle)) {
|
2015-01-16 14:22:54 +01:00
|
|
|
// invalid zip-file (?)
|
|
|
|
close(fd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
ZipEntry entry;
|
|
|
|
|
2015-06-25 23:56:07 +02:00
|
|
|
if (FindEntry(handle, ZipString(file_path), &entry) != 0) {
|
2015-01-16 14:22:54 +01:00
|
|
|
// Entry was not found.
|
|
|
|
close(fd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if it is properly stored
|
|
|
|
if (entry.method != kCompressStored || (entry.offset % PAGE_SIZE) != 0) {
|
|
|
|
close(fd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
*file_offset = entry.offset;
|
2015-10-02 03:41:57 +02:00
|
|
|
|
|
|
|
if (realpath_fd(fd, realpath)) {
|
|
|
|
*realpath += separator;
|
|
|
|
} else {
|
|
|
|
PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.",
|
|
|
|
normalized_path.c_str());
|
|
|
|
*realpath = normalized_path;
|
|
|
|
}
|
|
|
|
|
2015-01-16 14:22:54 +01:00
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
2015-03-24 02:43:02 +01:00
|
|
|
static bool format_path(char* buf, size_t buf_size, const char* path, const char* name) {
|
|
|
|
int n = __libc_format_buffer(buf, buf_size, "%s/%s", path, name);
|
|
|
|
if (n < 0 || n >= static_cast<int>(buf_size)) {
|
|
|
|
PRINT("Warning: ignoring very long library path: %s/%s", path, name);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2015-01-16 14:22:54 +01:00
|
|
|
|
2015-09-29 01:38:31 +02:00
|
|
|
static int open_library_on_paths(ZipArchiveCache* zip_archive_cache,
|
|
|
|
const char* name, off64_t* file_offset,
|
2015-10-02 03:41:57 +02:00
|
|
|
const std::vector<std::string>& paths,
|
|
|
|
std::string* realpath) {
|
2015-10-30 01:01:24 +01:00
|
|
|
for (const auto& path : paths) {
|
2015-03-24 02:43:02 +01:00
|
|
|
char buf[512];
|
2015-10-30 01:01:24 +01:00
|
|
|
if (!format_path(buf, sizeof(buf), path.c_str(), name)) {
|
2015-03-24 02:43:02 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
int fd = -1;
|
2015-07-16 13:52:06 +02:00
|
|
|
if (strstr(buf, kZipFileSeparator) != nullptr) {
|
2015-10-02 03:41:57 +02:00
|
|
|
fd = open_library_in_zipfile(zip_archive_cache, buf, file_offset, realpath);
|
2015-01-16 14:22:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (fd == -1) {
|
|
|
|
fd = TEMP_FAILURE_RETRY(open(buf, O_RDONLY | O_CLOEXEC));
|
|
|
|
if (fd != -1) {
|
|
|
|
*file_offset = 0;
|
2015-10-02 03:41:57 +02:00
|
|
|
if (!realpath_fd(fd, realpath)) {
|
|
|
|
PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.", buf);
|
|
|
|
*realpath = buf;
|
|
|
|
}
|
2015-01-16 14:22:54 +01:00
|
|
|
}
|
2012-10-31 22:20:03 +01:00
|
|
|
}
|
2015-03-24 02:43:02 +01:00
|
|
|
|
|
|
|
if (fd != -1) {
|
|
|
|
return fd;
|
|
|
|
}
|
2012-10-31 22:20:03 +01:00
|
|
|
}
|
2015-01-16 14:22:54 +01:00
|
|
|
|
2015-03-24 02:43:02 +01:00
|
|
|
return -1;
|
2009-03-04 04:28:35 +01:00
|
|
|
}
|
|
|
|
|
2015-10-30 01:01:24 +01:00
|
|
|
static int open_library(android_namespace_t* ns,
|
|
|
|
ZipArchiveCache* zip_archive_cache,
|
2015-09-29 01:38:31 +02:00
|
|
|
const char* name, soinfo *needed_by,
|
2015-10-02 03:41:57 +02:00
|
|
|
off64_t* file_offset, std::string* realpath) {
|
2013-03-12 18:40:45 +01:00
|
|
|
TRACE("[ opening %s ]", name);
|
2009-03-04 04:28:35 +01:00
|
|
|
|
2012-10-31 22:20:03 +01:00
|
|
|
// If the name contains a slash, we should attempt to open it directly and not search the paths.
|
2014-08-29 21:02:36 +02:00
|
|
|
if (strchr(name, '/') != nullptr) {
|
2015-10-30 01:01:24 +01:00
|
|
|
int fd = -1;
|
|
|
|
|
2015-07-16 13:52:06 +02:00
|
|
|
if (strstr(name, kZipFileSeparator) != nullptr) {
|
2015-10-30 01:01:24 +01:00
|
|
|
fd = open_library_in_zipfile(zip_archive_cache, name, file_offset, realpath);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fd == -1) {
|
|
|
|
fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_CLOEXEC));
|
2015-01-16 14:22:54 +01:00
|
|
|
if (fd != -1) {
|
2015-10-30 01:01:24 +01:00
|
|
|
*file_offset = 0;
|
|
|
|
if (!realpath_fd(fd, realpath)) {
|
|
|
|
PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.", name);
|
|
|
|
*realpath = name;
|
|
|
|
}
|
2015-01-16 14:22:54 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-18 01:12:18 +01:00
|
|
|
return fd;
|
2012-10-31 22:20:03 +01:00
|
|
|
}
|
2009-03-04 04:28:35 +01:00
|
|
|
|
2015-10-30 01:01:24 +01:00
|
|
|
// Otherwise we try LD_LIBRARY_PATH first, and fall back to the default library path
|
|
|
|
int fd = open_library_on_paths(zip_archive_cache, name, file_offset, ns->get_ld_library_paths(), realpath);
|
2015-10-15 21:07:25 +02:00
|
|
|
if (fd == -1 && needed_by != nullptr) {
|
2015-10-02 03:41:57 +02:00
|
|
|
fd = open_library_on_paths(zip_archive_cache, name, file_offset, needed_by->get_dt_runpath(), realpath);
|
2015-10-30 01:01:24 +01:00
|
|
|
// Check if the library is accessible
|
|
|
|
if (fd != -1 && !ns->is_accessible(*realpath)) {
|
|
|
|
fd = -1;
|
|
|
|
}
|
2015-06-10 22:38:39 +02:00
|
|
|
}
|
2015-09-29 01:38:31 +02:00
|
|
|
|
2012-10-31 22:20:03 +01:00
|
|
|
if (fd == -1) {
|
2015-10-30 01:01:24 +01:00
|
|
|
fd = open_library_on_paths(zip_archive_cache, name, file_offset, ns->get_default_library_paths(), realpath);
|
2012-10-31 22:20:03 +01:00
|
|
|
}
|
2015-09-29 01:38:31 +02:00
|
|
|
|
2016-07-21 20:33:40 +02:00
|
|
|
// TODO(dimitry): workaround for http://b/26394120 (the grey-list)
|
2017-02-27 21:17:47 +01:00
|
|
|
if (fd == -1 && ns != &g_default_namespace && is_greylisted(ns, name, needed_by)) {
|
2016-07-21 20:33:40 +02:00
|
|
|
// try searching for it on default_namespace default_library_path
|
|
|
|
fd = open_library_on_paths(zip_archive_cache, name, file_offset,
|
|
|
|
g_default_namespace.get_default_library_paths(), realpath);
|
|
|
|
}
|
|
|
|
// END OF WORKAROUND
|
|
|
|
|
2012-10-31 22:20:03 +01:00
|
|
|
return fd;
|
2009-03-04 04:28:35 +01:00
|
|
|
}
|
|
|
|
|
2016-09-09 19:00:39 +02:00
|
|
|
const char* fix_dt_needed(const char* dt_needed, const char* sopath __unused) {
|
2015-05-28 03:29:41 +02:00
|
|
|
#if !defined(__LP64__)
|
|
|
|
// Work around incorrect DT_NEEDED entries for old apps: http://b/21364029
|
2016-11-16 20:35:43 +01:00
|
|
|
if (get_application_target_sdk_version() < __ANDROID_API_M__) {
|
2015-05-28 03:29:41 +02:00
|
|
|
const char* bname = basename(dt_needed);
|
|
|
|
if (bname != dt_needed) {
|
2016-07-21 20:33:40 +02:00
|
|
|
DL_WARN("library \"%s\" has invalid DT_NEEDED entry \"%s\"", sopath, dt_needed);
|
|
|
|
add_dlwarning(sopath, "invalid DT_NEEDED entry", dt_needed);
|
2015-05-28 03:29:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return bname;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return dt_needed;
|
|
|
|
}
|
|
|
|
|
2015-10-15 21:07:25 +02:00
|
|
|
template<typename F>
|
|
|
|
static void for_each_dt_needed(const ElfReader& elf_reader, F action) {
|
|
|
|
for (const ElfW(Dyn)* d = elf_reader.dynamic(); d->d_tag != DT_NULL; ++d) {
|
|
|
|
if (d->d_tag == DT_NEEDED) {
|
|
|
|
action(fix_dt_needed(elf_reader.get_string(d->d_un.d_val), elf_reader.name()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-27 23:11:02 +02:00
|
|
|
static bool find_loaded_library_by_inode(android_namespace_t* ns,
|
|
|
|
const struct stat& file_stat,
|
|
|
|
off64_t file_offset,
|
|
|
|
bool search_linked_namespaces,
|
|
|
|
soinfo** candidate) {
|
|
|
|
|
|
|
|
auto predicate = [&](soinfo* si) {
|
|
|
|
return si->get_st_dev() != 0 &&
|
|
|
|
si->get_st_ino() != 0 &&
|
|
|
|
si->get_st_dev() == file_stat.st_dev &&
|
|
|
|
si->get_st_ino() == file_stat.st_ino &&
|
|
|
|
si->get_file_offset() == file_offset;
|
|
|
|
};
|
|
|
|
|
|
|
|
*candidate = ns->soinfo_list().find_if(predicate);
|
|
|
|
|
|
|
|
if (*candidate == nullptr && search_linked_namespaces) {
|
|
|
|
for (auto& link : ns->linked_namespaces()) {
|
|
|
|
android_namespace_t* linked_ns = link.linked_namespace();
|
|
|
|
soinfo* si = linked_ns->soinfo_list().find_if(predicate);
|
|
|
|
|
|
|
|
if (si != nullptr && link.is_accessible(si->get_soname())) {
|
|
|
|
*candidate = si;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return *candidate != nullptr;
|
|
|
|
}
|
|
|
|
|
2015-10-30 01:01:24 +01:00
|
|
|
static bool load_library(android_namespace_t* ns,
|
|
|
|
LoadTask* task,
|
2015-10-15 21:07:25 +02:00
|
|
|
LoadTaskList* load_tasks,
|
|
|
|
int rtld_flags,
|
2017-03-27 23:11:02 +02:00
|
|
|
const std::string& realpath,
|
|
|
|
bool search_linked_namespaces) {
|
2015-10-15 21:07:25 +02:00
|
|
|
off64_t file_offset = task->get_file_offset();
|
|
|
|
const char* name = task->get_name();
|
|
|
|
const android_dlextinfo* extinfo = task->get_extinfo();
|
|
|
|
|
2014-10-04 02:52:44 +02:00
|
|
|
if ((file_offset % PAGE_SIZE) != 0) {
|
2014-10-21 21:09:18 +02:00
|
|
|
DL_ERR("file offset for the library \"%s\" is not page-aligned: %" PRId64, name, file_offset);
|
2015-10-15 21:07:25 +02:00
|
|
|
return false;
|
2014-10-04 02:52:44 +02:00
|
|
|
}
|
2014-11-04 20:08:05 +01:00
|
|
|
if (file_offset < 0) {
|
|
|
|
DL_ERR("file offset for the library \"%s\" is negative: %" PRId64, name, file_offset);
|
2015-10-15 21:07:25 +02:00
|
|
|
return false;
|
2014-11-04 20:08:05 +01:00
|
|
|
}
|
2014-10-04 02:52:44 +02:00
|
|
|
|
2014-09-06 01:42:53 +02:00
|
|
|
struct stat file_stat;
|
2015-10-15 21:07:25 +02:00
|
|
|
if (TEMP_FAILURE_RETRY(fstat(task->get_fd(), &file_stat)) != 0) {
|
2014-10-21 21:09:18 +02:00
|
|
|
DL_ERR("unable to stat file for the library \"%s\": %s", name, strerror(errno));
|
2015-10-15 21:07:25 +02:00
|
|
|
return false;
|
2014-09-06 01:42:53 +02:00
|
|
|
}
|
2014-11-04 20:08:05 +01:00
|
|
|
if (file_offset >= file_stat.st_size) {
|
2015-03-31 03:43:38 +02:00
|
|
|
DL_ERR("file offset for the library \"%s\" >= file size: %" PRId64 " >= %" PRId64,
|
|
|
|
name, file_offset, file_stat.st_size);
|
2015-10-15 21:07:25 +02:00
|
|
|
return false;
|
2014-11-04 20:08:05 +01:00
|
|
|
}
|
2014-05-09 18:10:14 +02:00
|
|
|
|
2014-09-06 01:42:53 +02:00
|
|
|
// Check for symlink and other situations where
|
2015-04-03 01:03:56 +02:00
|
|
|
// file can have different names, unless ANDROID_DLEXT_FORCE_LOAD is set
|
|
|
|
if (extinfo == nullptr || (extinfo->flags & ANDROID_DLEXT_FORCE_LOAD) == 0) {
|
2017-03-27 23:11:02 +02:00
|
|
|
soinfo* si = nullptr;
|
|
|
|
if (find_loaded_library_by_inode(ns, file_stat, file_offset, search_linked_namespaces, &si)) {
|
2015-10-30 01:01:24 +01:00
|
|
|
TRACE("library \"%s\" is already loaded under different name/path \"%s\" - "
|
|
|
|
"will return existing soinfo", name, si->get_realpath());
|
|
|
|
task->set_soinfo(si);
|
|
|
|
return true;
|
|
|
|
}
|
2014-09-06 01:42:53 +02:00
|
|
|
}
|
2014-05-09 18:10:14 +02:00
|
|
|
|
2014-09-16 02:00:10 +02:00
|
|
|
if ((rtld_flags & RTLD_NOLOAD) != 0) {
|
2014-09-09 19:21:42 +02:00
|
|
|
DL_ERR("library \"%s\" wasn't loaded and RTLD_NOLOAD prevented it", name);
|
2015-10-15 21:07:25 +02:00
|
|
|
return false;
|
2014-09-06 01:42:53 +02:00
|
|
|
}
|
2014-05-09 18:10:14 +02:00
|
|
|
|
2015-12-05 03:28:49 +01:00
|
|
|
if (!ns->is_accessible(realpath)) {
|
2016-07-21 20:33:40 +02:00
|
|
|
// TODO(dimitry): workaround for http://b/26394120 - the grey-list
|
2017-02-02 00:28:52 +01:00
|
|
|
|
|
|
|
// TODO(dimitry) before O release: add a namespace attribute to have this enabled
|
|
|
|
// only for classloader-namespaces
|
2016-07-21 20:33:40 +02:00
|
|
|
const soinfo* needed_by = task->is_dt_needed() ? task->get_needed_by() : nullptr;
|
2017-02-27 21:17:47 +01:00
|
|
|
if (is_greylisted(ns, name, needed_by)) {
|
2016-07-21 20:33:40 +02:00
|
|
|
// print warning only if needed by non-system library
|
|
|
|
if (needed_by == nullptr || !is_system_library(needed_by->get_realpath())) {
|
|
|
|
const soinfo* needed_or_dlopened_by = task->get_needed_by();
|
|
|
|
const char* sopath = needed_or_dlopened_by == nullptr ? "(unknown)" :
|
|
|
|
needed_or_dlopened_by->get_realpath();
|
|
|
|
DL_WARN("library \"%s\" (\"%s\") needed or dlopened by \"%s\" is not accessible for the namespace \"%s\""
|
|
|
|
" - the access is temporarily granted as a workaround for http://b/26394120, note that the access"
|
|
|
|
" will be removed in future releases of Android.",
|
|
|
|
name, realpath.c_str(), sopath, ns->get_name());
|
|
|
|
add_dlwarning(sopath, "unauthorized access to", name);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// do not load libraries if they are not accessible for the specified namespace.
|
|
|
|
const char* needed_or_dlopened_by = task->get_needed_by() == nullptr ?
|
|
|
|
"(unknown)" :
|
|
|
|
task->get_needed_by()->get_realpath();
|
|
|
|
|
|
|
|
DL_ERR("library \"%s\" needed or dlopened by \"%s\" is not accessible for the namespace \"%s\"",
|
|
|
|
name, needed_or_dlopened_by, ns->get_name());
|
|
|
|
|
2017-02-27 21:17:47 +01:00
|
|
|
// do not print this if a library is in the list of shared libraries for linked namespaces
|
|
|
|
if (!maybe_accessible_via_namespace_links(ns, name)) {
|
|
|
|
PRINT("library \"%s\" (\"%s\") needed or dlopened by \"%s\" is not accessible for the"
|
|
|
|
" namespace: [name=\"%s\", ld_library_paths=\"%s\", default_library_paths=\"%s\","
|
|
|
|
" permitted_paths=\"%s\"]",
|
|
|
|
name, realpath.c_str(),
|
|
|
|
needed_or_dlopened_by,
|
|
|
|
ns->get_name(),
|
|
|
|
android::base::Join(ns->get_ld_library_paths(), ':').c_str(),
|
|
|
|
android::base::Join(ns->get_default_library_paths(), ':').c_str(),
|
|
|
|
android::base::Join(ns->get_permitted_paths(), ':').c_str());
|
|
|
|
}
|
2016-07-21 20:33:40 +02:00
|
|
|
return false;
|
|
|
|
}
|
2015-12-05 03:28:49 +01:00
|
|
|
}
|
|
|
|
|
2015-10-30 01:01:24 +01:00
|
|
|
soinfo* si = soinfo_alloc(ns, realpath.c_str(), &file_stat, file_offset, rtld_flags);
|
2014-09-06 01:42:53 +02:00
|
|
|
if (si == nullptr) {
|
2015-10-15 21:07:25 +02:00
|
|
|
return false;
|
2014-09-06 01:42:53 +02:00
|
|
|
}
|
|
|
|
|
2015-10-15 21:07:25 +02:00
|
|
|
task->set_soinfo(si);
|
|
|
|
|
|
|
|
// Read the ELF header and some of the segments.
|
|
|
|
if (!task->read(realpath.c_str(), file_stat.st_size)) {
|
2015-11-06 19:44:37 +01:00
|
|
|
soinfo_free(si);
|
|
|
|
task->set_soinfo(nullptr);
|
2015-10-15 21:07:25 +02:00
|
|
|
return false;
|
2014-09-06 01:42:53 +02:00
|
|
|
}
|
2014-07-29 23:21:45 +02:00
|
|
|
|
2015-10-15 21:07:25 +02:00
|
|
|
// find and set DT_RUNPATH and dt_soname
|
|
|
|
// Note that these field values are temporary and are
|
|
|
|
// going to be overwritten on soinfo::prelink_image
|
|
|
|
// with values from PT_LOAD segments.
|
|
|
|
const ElfReader& elf_reader = task->get_elf_reader();
|
|
|
|
for (const ElfW(Dyn)* d = elf_reader.dynamic(); d->d_tag != DT_NULL; ++d) {
|
|
|
|
if (d->d_tag == DT_RUNPATH) {
|
|
|
|
si->set_dt_runpath(elf_reader.get_string(d->d_un.d_val));
|
|
|
|
}
|
|
|
|
if (d->d_tag == DT_SONAME) {
|
|
|
|
si->set_soname(elf_reader.get_string(d->d_un.d_val));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for_each_dt_needed(task->get_elf_reader(), [&](const char* name) {
|
|
|
|
load_tasks->push_back(LoadTask::create(name, si, task->get_readers_map()));
|
2014-09-06 01:42:53 +02:00
|
|
|
});
|
|
|
|
|
2015-10-15 21:07:25 +02:00
|
|
|
return true;
|
2009-03-04 04:28:35 +01:00
|
|
|
}
|
|
|
|
|
2015-10-30 01:01:24 +01:00
|
|
|
static bool load_library(android_namespace_t* ns,
|
|
|
|
LoadTask* task,
|
2015-10-15 21:07:25 +02:00
|
|
|
ZipArchiveCache* zip_archive_cache,
|
|
|
|
LoadTaskList* load_tasks,
|
2017-03-27 23:11:02 +02:00
|
|
|
int rtld_flags,
|
|
|
|
bool search_linked_namespaces) {
|
2015-10-15 21:07:25 +02:00
|
|
|
const char* name = task->get_name();
|
|
|
|
soinfo* needed_by = task->get_needed_by();
|
|
|
|
const android_dlextinfo* extinfo = task->get_extinfo();
|
|
|
|
|
2015-10-02 03:41:57 +02:00
|
|
|
off64_t file_offset;
|
|
|
|
std::string realpath;
|
2015-04-23 03:06:51 +02:00
|
|
|
if (extinfo != nullptr && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) {
|
2015-10-02 03:41:57 +02:00
|
|
|
file_offset = 0;
|
2015-04-23 03:06:51 +02:00
|
|
|
if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
|
|
|
|
file_offset = extinfo->library_fd_offset;
|
|
|
|
}
|
2015-10-02 03:41:57 +02:00
|
|
|
|
|
|
|
if (!realpath_fd(extinfo->library_fd, &realpath)) {
|
|
|
|
PRINT("warning: unable to get realpath for the library \"%s\" by extinfo->library_fd. "
|
|
|
|
"Will use given name.", name);
|
|
|
|
realpath = name;
|
|
|
|
}
|
2015-10-15 21:07:25 +02:00
|
|
|
|
|
|
|
task->set_fd(extinfo->library_fd, false);
|
|
|
|
task->set_file_offset(file_offset);
|
2017-03-27 23:11:02 +02:00
|
|
|
return load_library(ns, task, load_tasks, rtld_flags, realpath, search_linked_namespaces);
|
2015-04-23 03:06:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Open the file.
|
2015-10-30 01:01:24 +01:00
|
|
|
int fd = open_library(ns, zip_archive_cache, name, needed_by, &file_offset, &realpath);
|
2015-04-23 03:06:51 +02:00
|
|
|
if (fd == -1) {
|
|
|
|
DL_ERR("library \"%s\" not found", name);
|
2015-10-15 21:07:25 +02:00
|
|
|
return false;
|
2015-04-23 03:06:51 +02:00
|
|
|
}
|
2015-10-15 21:07:25 +02:00
|
|
|
|
|
|
|
task->set_fd(fd, true);
|
|
|
|
task->set_file_offset(file_offset);
|
|
|
|
|
2017-03-27 23:11:02 +02:00
|
|
|
return load_library(ns, task, load_tasks, rtld_flags, realpath, search_linked_namespaces);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool find_loaded_library_by_soname(android_namespace_t* ns,
|
|
|
|
const char* name,
|
|
|
|
soinfo** candidate) {
|
|
|
|
return !ns->soinfo_list().visit([&](soinfo* si) {
|
|
|
|
const char* soname = si->get_soname();
|
|
|
|
if (soname != nullptr && (strcmp(name, soname) == 0)) {
|
|
|
|
*candidate = si;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
});
|
2015-04-23 03:06:51 +02:00
|
|
|
}
|
|
|
|
|
2017-02-01 17:54:43 +01:00
|
|
|
// Returns true if library was found and false otherwise
|
2015-10-30 01:01:24 +01:00
|
|
|
static bool find_loaded_library_by_soname(android_namespace_t* ns,
|
2017-03-27 23:11:02 +02:00
|
|
|
const char* name,
|
|
|
|
bool search_linked_namespaces,
|
|
|
|
soinfo** candidate) {
|
2015-06-17 00:38:21 +02:00
|
|
|
*candidate = nullptr;
|
|
|
|
|
2015-03-18 04:06:36 +01:00
|
|
|
// Ignore filename with path.
|
|
|
|
if (strchr(name, '/') != nullptr) {
|
2015-06-17 00:38:21 +02:00
|
|
|
return false;
|
2015-03-18 04:06:36 +01:00
|
|
|
}
|
|
|
|
|
2017-03-27 23:11:02 +02:00
|
|
|
bool found = find_loaded_library_by_soname(ns, name, candidate);
|
|
|
|
|
|
|
|
if (!found && search_linked_namespaces) {
|
|
|
|
// if a library was not found - look into linked namespaces
|
|
|
|
for (auto& link : ns->linked_namespaces()) {
|
|
|
|
if (!link.is_accessible(name)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
android_namespace_t* linked_ns = link.linked_namespace();
|
|
|
|
|
|
|
|
if (find_loaded_library_by_soname(linked_ns, name, candidate)) {
|
|
|
|
return true;
|
|
|
|
}
|
linker: avoid clobbering the .dynamic section of shared libs
This patch removes the DT_NEEDED hack which stores pointers
to soinfo structs in the .dynamic section of the library
being loaded.
Instead, it caches the soinfo struct pointers on the stack
during relocation time. After relocation time, i.e. when
calling constructors and destructors of the shared library
and its dependencies, uncached access is used instead,
doing lookups using the string table entries pointed to by
the DT_NEEDED entries.
By removing this hack, it is no longer needed to undo the
PT_GNURELRO protection, i.e., all non-writable mappings
can remain non-writable during their entire lifespan.
Even though, strictly speaking, the algorithmic complexity
has increased somewhat, the real-world adverse effect
is negligible on the systems I have tested.
Change-Id: I2361502560b96b5878f7f94a8e8a215350d70d64
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@gmail.com>
2012-08-14 12:30:09 +02:00
|
|
|
}
|
2017-03-27 23:11:02 +02:00
|
|
|
}
|
2015-06-17 00:38:21 +02:00
|
|
|
|
2017-03-27 23:11:02 +02:00
|
|
|
return found;
|
linker: avoid clobbering the .dynamic section of shared libs
This patch removes the DT_NEEDED hack which stores pointers
to soinfo structs in the .dynamic section of the library
being loaded.
Instead, it caches the soinfo struct pointers on the stack
during relocation time. After relocation time, i.e. when
calling constructors and destructors of the shared library
and its dependencies, uncached access is used instead,
doing lookups using the string table entries pointed to by
the DT_NEEDED entries.
By removing this hack, it is no longer needed to undo the
PT_GNURELRO protection, i.e., all non-writable mappings
can remain non-writable during their entire lifespan.
Even though, strictly speaking, the algorithmic complexity
has increased somewhat, the real-world adverse effect
is negligible on the systems I have tested.
Change-Id: I2361502560b96b5878f7f94a8e8a215350d70d64
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@gmail.com>
2012-08-14 12:30:09 +02:00
|
|
|
}
|
|
|
|
|
2017-02-02 00:28:52 +01:00
|
|
|
static bool find_library_in_linked_namespace(const android_namespace_link_t& namespace_link,
|
|
|
|
LoadTask* task,
|
|
|
|
int rtld_flags) {
|
|
|
|
android_namespace_t* ns = namespace_link.linked_namespace();
|
|
|
|
|
|
|
|
soinfo* candidate;
|
|
|
|
bool loaded = false;
|
|
|
|
|
|
|
|
std::string soname;
|
2017-03-27 23:11:02 +02:00
|
|
|
if (find_loaded_library_by_soname(ns, task->get_name(), false, &candidate)) {
|
2017-02-02 00:28:52 +01:00
|
|
|
loaded = true;
|
|
|
|
soname = candidate->get_soname();
|
|
|
|
} else {
|
|
|
|
soname = resolve_soname(task->get_name());
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!namespace_link.is_accessible(soname.c_str())) {
|
|
|
|
// the library is not accessible via namespace_link
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if library is already loaded - return it
|
|
|
|
if (loaded) {
|
|
|
|
task->set_soinfo(candidate);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// try to load the library - once namespace boundary is crossed
|
|
|
|
// we need to load a library within separate load_group
|
|
|
|
// to avoid using symbols from foreign namespace while.
|
|
|
|
//
|
|
|
|
// All symbols during relocation should be resolved within a
|
|
|
|
// namespace to preserve library locality to a namespace.
|
|
|
|
const char* name = task->get_name();
|
|
|
|
if (find_libraries(ns,
|
|
|
|
task->get_needed_by(),
|
|
|
|
&name,
|
|
|
|
1,
|
|
|
|
&candidate,
|
|
|
|
nullptr /* ld_preloads */,
|
|
|
|
0 /* ld_preload_count*/,
|
|
|
|
rtld_flags,
|
|
|
|
nullptr /* extinfo*/,
|
|
|
|
false /* add_as_children */,
|
|
|
|
false /* search_linked_namespaces */)) {
|
|
|
|
task->set_soinfo(candidate);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-10-30 01:01:24 +01:00
|
|
|
static bool find_library_internal(android_namespace_t* ns,
|
|
|
|
LoadTask* task,
|
2015-10-15 21:07:25 +02:00
|
|
|
ZipArchiveCache* zip_archive_cache,
|
|
|
|
LoadTaskList* load_tasks,
|
2017-02-02 00:28:52 +01:00
|
|
|
int rtld_flags,
|
|
|
|
bool search_linked_namespaces) {
|
2015-06-17 00:38:21 +02:00
|
|
|
soinfo* candidate;
|
|
|
|
|
2017-03-27 23:11:02 +02:00
|
|
|
if (find_loaded_library_by_soname(ns, task->get_name(), search_linked_namespaces, &candidate)) {
|
2015-10-15 21:07:25 +02:00
|
|
|
task->set_soinfo(candidate);
|
|
|
|
return true;
|
2015-06-17 00:38:21 +02:00
|
|
|
}
|
2014-05-20 00:06:58 +02:00
|
|
|
|
|
|
|
// Library might still be loaded, the accurate detection
|
2014-09-06 01:42:53 +02:00
|
|
|
// of this fact is done by load_library.
|
2016-07-21 20:33:40 +02:00
|
|
|
TRACE("[ \"%s\" find_loaded_library_by_soname failed (*candidate=%s@%p). Trying harder...]",
|
2015-10-15 21:07:25 +02:00
|
|
|
task->get_name(), candidate == nullptr ? "n/a" : candidate->get_realpath(), candidate);
|
2015-06-17 00:38:21 +02:00
|
|
|
|
2017-03-27 23:11:02 +02:00
|
|
|
if (load_library(ns, task, zip_archive_cache, load_tasks, rtld_flags, search_linked_namespaces)) {
|
2017-02-02 00:28:52 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (search_linked_namespaces) {
|
|
|
|
// if a library was not found - look into linked namespaces
|
|
|
|
for (auto& linked_namespace : ns->linked_namespaces()) {
|
|
|
|
if (find_library_in_linked_namespace(linked_namespace,
|
|
|
|
task,
|
|
|
|
rtld_flags)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2014-09-06 01:42:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void soinfo_unload(soinfo* si);
|
2016-05-05 02:19:14 +02:00
|
|
|
static void soinfo_unload(soinfo* soinfos[], size_t count);
|
2014-09-06 01:42:53 +02:00
|
|
|
|
2014-08-28 23:12:12 +02:00
|
|
|
// TODO: this is slightly unusual way to construct
|
|
|
|
// the global group for relocation. Not every RTLD_GLOBAL
|
|
|
|
// library is included in this group for backwards-compatibility
|
|
|
|
// reasons.
|
|
|
|
//
|
|
|
|
// This group consists of the main executable, LD_PRELOADs
|
|
|
|
// and libraries with the DF_1_GLOBAL flag set.
|
2016-08-04 01:00:10 +02:00
|
|
|
static soinfo_list_t make_global_group(android_namespace_t* ns) {
|
|
|
|
soinfo_list_t global_group;
|
2015-10-30 01:01:24 +01:00
|
|
|
ns->soinfo_list().for_each([&](soinfo* si) {
|
2014-08-28 23:12:12 +02:00
|
|
|
if ((si->get_dt_flags_1() & DF_1_GLOBAL) != 0) {
|
|
|
|
global_group.push_back(si);
|
|
|
|
}
|
2015-10-30 01:01:24 +01:00
|
|
|
});
|
2014-08-28 23:12:12 +02:00
|
|
|
|
|
|
|
return global_group;
|
|
|
|
}
|
|
|
|
|
2016-05-13 00:20:21 +02:00
|
|
|
// This function provides a list of libraries to be shared
|
|
|
|
// by the namespace. For the default namespace this is the global
|
|
|
|
// group (see make_global_group). For all others this is a group
|
|
|
|
// of RTLD_GLOBAL libraries (which includes the global group from
|
|
|
|
// the default namespace).
|
2016-08-04 01:00:10 +02:00
|
|
|
static soinfo_list_t get_shared_group(android_namespace_t* ns) {
|
2016-05-13 00:20:21 +02:00
|
|
|
if (ns == &g_default_namespace) {
|
|
|
|
return make_global_group(ns);
|
|
|
|
}
|
|
|
|
|
2016-08-04 01:00:10 +02:00
|
|
|
soinfo_list_t shared_group;
|
2016-05-13 00:20:21 +02:00
|
|
|
ns->soinfo_list().for_each([&](soinfo* si) {
|
|
|
|
if ((si->get_rtld_flags() & RTLD_GLOBAL) != 0) {
|
|
|
|
shared_group.push_back(si);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
return shared_group;
|
|
|
|
}
|
|
|
|
|
2015-10-15 21:07:25 +02:00
|
|
|
static void shuffle(std::vector<LoadTask*>* v) {
|
|
|
|
for (size_t i = 0, size = v->size(); i < size; ++i) {
|
|
|
|
size_t n = size - i;
|
|
|
|
size_t r = arc4random_uniform(n);
|
|
|
|
std::swap((*v)[n-1], (*v)[r]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-07 02:56:31 +02:00
|
|
|
// add_as_children - add first-level loaded libraries (i.e. library_names[], but
|
|
|
|
// not their transitive dependencies) as children of the start_with library.
|
|
|
|
// This is false when find_libraries is called for dlopen(), when newly loaded
|
|
|
|
// libraries must form a disjoint tree.
|
2016-09-09 19:00:39 +02:00
|
|
|
bool find_libraries(android_namespace_t* ns,
|
|
|
|
soinfo* start_with,
|
|
|
|
const char* const library_names[],
|
|
|
|
size_t library_names_count,
|
|
|
|
soinfo* soinfos[],
|
|
|
|
std::vector<soinfo*>* ld_preloads,
|
|
|
|
size_t ld_preloads_count,
|
|
|
|
int rtld_flags,
|
|
|
|
const android_dlextinfo* extinfo,
|
2017-02-02 00:28:52 +01:00
|
|
|
bool add_as_children,
|
|
|
|
bool search_linked_namespaces) {
|
2014-09-06 01:42:53 +02:00
|
|
|
// Step 0: prepare.
|
|
|
|
LoadTaskList load_tasks;
|
2015-10-15 21:07:25 +02:00
|
|
|
std::unordered_map<const soinfo*, ElfReader> readers_map;
|
|
|
|
|
2014-10-21 18:23:18 +02:00
|
|
|
for (size_t i = 0; i < library_names_count; ++i) {
|
2014-09-06 01:42:53 +02:00
|
|
|
const char* name = library_names[i];
|
2015-10-15 21:07:25 +02:00
|
|
|
load_tasks.push_back(LoadTask::create(name, start_with, &readers_map));
|
2014-10-21 18:23:18 +02:00
|
|
|
}
|
|
|
|
|
2014-08-28 23:12:12 +02:00
|
|
|
// Construct global_group.
|
2016-08-04 01:00:10 +02:00
|
|
|
soinfo_list_t global_group = make_global_group(ns);
|
2014-08-28 23:12:12 +02:00
|
|
|
|
2014-10-21 18:23:18 +02:00
|
|
|
// If soinfos array is null allocate one on stack.
|
|
|
|
// The array is needed in case of failure; for example
|
|
|
|
// when library_names[] = {libone.so, libtwo.so} and libone.so
|
|
|
|
// is loaded correctly but libtwo.so failed for some reason.
|
|
|
|
// In this case libone.so should be unloaded on return.
|
|
|
|
// See also implementation of failure_guard below.
|
|
|
|
|
|
|
|
if (soinfos == nullptr) {
|
|
|
|
size_t soinfos_size = sizeof(soinfo*)*library_names_count;
|
|
|
|
soinfos = reinterpret_cast<soinfo**>(alloca(soinfos_size));
|
|
|
|
memset(soinfos, 0, soinfos_size);
|
2014-09-06 01:42:53 +02:00
|
|
|
}
|
|
|
|
|
2014-10-21 18:23:18 +02:00
|
|
|
// list of libraries to link - see step 2.
|
|
|
|
size_t soinfos_count = 0;
|
2014-09-06 01:42:53 +02:00
|
|
|
|
2015-10-15 21:07:25 +02:00
|
|
|
auto scope_guard = make_scope_guard([&]() {
|
|
|
|
for (LoadTask* t : load_tasks) {
|
2014-09-06 01:42:53 +02:00
|
|
|
LoadTask::deleter(t);
|
2015-10-15 21:07:25 +02:00
|
|
|
}
|
|
|
|
});
|
2014-09-06 01:42:53 +02:00
|
|
|
|
2015-10-15 21:07:25 +02:00
|
|
|
auto failure_guard = make_scope_guard([&]() {
|
|
|
|
// Housekeeping
|
2016-05-05 02:19:14 +02:00
|
|
|
soinfo_unload(soinfos, soinfos_count);
|
2014-09-06 01:42:53 +02:00
|
|
|
});
|
|
|
|
|
2015-09-29 01:38:31 +02:00
|
|
|
ZipArchiveCache zip_archive_cache;
|
|
|
|
|
2015-10-15 21:07:25 +02:00
|
|
|
// Step 1: expand the list of load_tasks to include
|
|
|
|
// all DT_NEEDED libraries (do not load them just yet)
|
|
|
|
for (size_t i = 0; i<load_tasks.size(); ++i) {
|
|
|
|
LoadTask* task = load_tasks[i];
|
2015-06-10 22:38:39 +02:00
|
|
|
soinfo* needed_by = task->get_needed_by();
|
2015-09-03 01:32:02 +02:00
|
|
|
|
2015-10-15 21:07:25 +02:00
|
|
|
bool is_dt_needed = needed_by != nullptr && (needed_by != start_with || add_as_children);
|
|
|
|
task->set_extinfo(is_dt_needed ? nullptr : extinfo);
|
2016-07-21 20:33:40 +02:00
|
|
|
task->set_dt_needed(is_dt_needed);
|
2015-09-29 01:38:31 +02:00
|
|
|
|
2017-02-02 00:28:52 +01:00
|
|
|
if (!find_library_internal(ns,
|
|
|
|
task,
|
|
|
|
&zip_archive_cache,
|
|
|
|
&load_tasks,
|
|
|
|
rtld_flags,
|
|
|
|
search_linked_namespaces || is_dt_needed)) {
|
2014-09-06 01:42:53 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-10-15 21:07:25 +02:00
|
|
|
soinfo* si = task->get_soinfo();
|
|
|
|
|
2015-09-03 01:32:02 +02:00
|
|
|
if (is_dt_needed) {
|
2014-09-06 01:42:53 +02:00
|
|
|
needed_by->add_child(si);
|
|
|
|
|
2017-02-02 00:28:52 +01:00
|
|
|
if (si->is_linked()) {
|
|
|
|
si->increment_ref_count();
|
|
|
|
}
|
2014-11-29 22:57:41 +01:00
|
|
|
}
|
|
|
|
|
2014-10-21 18:23:18 +02:00
|
|
|
// When ld_preloads is not null, the first
|
|
|
|
// ld_preloads_count libs are in fact ld_preloads.
|
|
|
|
if (ld_preloads != nullptr && soinfos_count < ld_preloads_count) {
|
2015-03-24 02:43:02 +01:00
|
|
|
ld_preloads->push_back(si);
|
2014-09-06 01:42:53 +02:00
|
|
|
}
|
|
|
|
|
2014-10-21 18:23:18 +02:00
|
|
|
if (soinfos_count < library_names_count) {
|
|
|
|
soinfos[soinfos_count++] = si;
|
2014-09-06 01:42:53 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-15 21:07:25 +02:00
|
|
|
// Step 2: Load libraries in random order (see b/24047022)
|
|
|
|
LoadTaskList load_list;
|
|
|
|
for (auto&& task : load_tasks) {
|
|
|
|
soinfo* si = task->get_soinfo();
|
|
|
|
auto pred = [&](const LoadTask* t) {
|
|
|
|
return t->get_soinfo() == si;
|
|
|
|
};
|
|
|
|
|
|
|
|
if (!si->is_linked() &&
|
|
|
|
std::find_if(load_list.begin(), load_list.end(), pred) == load_list.end() ) {
|
|
|
|
load_list.push_back(task);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
shuffle(&load_list);
|
|
|
|
|
|
|
|
for (auto&& task : load_list) {
|
|
|
|
if (!task->load()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Step 3: pre-link all DT_NEEDED libraries in breadth first order.
|
|
|
|
for (auto&& task : load_tasks) {
|
|
|
|
soinfo* si = task->get_soinfo();
|
|
|
|
if (!si->is_linked() && !si->prelink_image()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Step 4: Add LD_PRELOADed libraries to the global group for
|
|
|
|
// future runs. There is no need to explicitly add them to
|
|
|
|
// the global group for this run because they are going to
|
|
|
|
// appear in the local group in the correct order.
|
|
|
|
if (ld_preloads != nullptr) {
|
|
|
|
for (auto&& si : *ld_preloads) {
|
|
|
|
si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Step 5: link libraries.
|
2016-08-04 01:00:10 +02:00
|
|
|
soinfo_list_t local_group;
|
2014-10-21 18:23:18 +02:00
|
|
|
walk_dependencies_tree(
|
2015-07-07 02:56:31 +02:00
|
|
|
(start_with != nullptr && add_as_children) ? &start_with : soinfos,
|
|
|
|
(start_with != nullptr && add_as_children) ? 1 : soinfos_count,
|
2014-10-21 18:23:18 +02:00
|
|
|
[&] (soinfo* si) {
|
2017-02-03 23:07:34 +01:00
|
|
|
if (ns->is_accessible(si)) {
|
|
|
|
local_group.push_back(si);
|
|
|
|
return kWalkContinue;
|
|
|
|
} else {
|
|
|
|
return kWalkSkip;
|
|
|
|
}
|
2014-10-21 18:23:18 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
bool linked = local_group.visit([&](soinfo* si) {
|
2014-11-29 22:57:41 +01:00
|
|
|
if (!si->is_linked()) {
|
2016-07-06 22:20:59 +02:00
|
|
|
if (!si->link_image(global_group, local_group, extinfo) ||
|
|
|
|
!get_cfi_shadow()->AfterLoad(si, solist_get_head())) {
|
2014-09-06 01:42:53 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2014-10-21 18:23:18 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
|
|
|
|
if (linked) {
|
2016-05-05 02:19:14 +02:00
|
|
|
local_group.for_each([](soinfo* si) {
|
|
|
|
if (!si->is_linked()) {
|
|
|
|
si->set_linked();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2014-10-21 18:23:18 +02:00
|
|
|
failure_guard.disable();
|
2014-07-29 23:21:45 +02:00
|
|
|
}
|
2014-09-06 01:42:53 +02:00
|
|
|
|
2014-10-21 18:23:18 +02:00
|
|
|
return linked;
|
2014-09-06 01:42:53 +02:00
|
|
|
}
|
|
|
|
|
2015-10-30 01:01:24 +01:00
|
|
|
static soinfo* find_library(android_namespace_t* ns,
|
|
|
|
const char* name, int rtld_flags,
|
2015-07-07 02:56:31 +02:00
|
|
|
const android_dlextinfo* extinfo,
|
|
|
|
soinfo* needed_by) {
|
2014-09-06 01:42:53 +02:00
|
|
|
soinfo* si;
|
|
|
|
|
2014-11-29 22:57:41 +01:00
|
|
|
if (name == nullptr) {
|
2016-09-09 19:00:39 +02:00
|
|
|
si = solist_get_somain();
|
2017-02-02 00:28:52 +01:00
|
|
|
} else if (!find_libraries(ns,
|
|
|
|
needed_by,
|
|
|
|
&name,
|
|
|
|
1,
|
|
|
|
&si,
|
|
|
|
nullptr,
|
|
|
|
0,
|
|
|
|
rtld_flags,
|
|
|
|
extinfo,
|
|
|
|
false /* add_as_children */,
|
|
|
|
true /* search_linked_namespaces */)) {
|
2014-09-06 01:42:53 +02:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2017-02-02 00:28:52 +01:00
|
|
|
si->increment_ref_count();
|
|
|
|
|
2012-11-01 23:16:56 +01:00
|
|
|
return si;
|
|
|
|
}
|
|
|
|
|
2014-11-29 22:57:41 +01:00
|
|
|
static void soinfo_unload(soinfo* root) {
|
|
|
|
if (root->is_linked()) {
|
|
|
|
root = root->get_local_group_root();
|
2014-05-20 00:06:58 +02:00
|
|
|
}
|
|
|
|
|
2017-03-21 18:29:06 +01:00
|
|
|
ScopedTrace trace((std::string("unload ") + root->get_realpath()).c_str());
|
|
|
|
|
2014-11-29 22:57:41 +01:00
|
|
|
if (!root->can_unload()) {
|
2016-07-21 20:33:40 +02:00
|
|
|
TRACE("not unloading \"%s\" - the binary is flagged with NODELETE", root->get_realpath());
|
2014-11-29 22:57:41 +01:00
|
|
|
return;
|
|
|
|
}
|
2012-11-01 23:16:56 +01:00
|
|
|
|
2016-05-05 02:19:14 +02:00
|
|
|
soinfo_unload(&root, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void soinfo_unload(soinfo* soinfos[], size_t count) {
|
|
|
|
// Note that the library can be loaded but not linked;
|
|
|
|
// in which case there is no root but we still need
|
|
|
|
// to walk the tree and unload soinfos involved.
|
|
|
|
//
|
|
|
|
// This happens on unsuccessful dlopen, when one of
|
|
|
|
// the DT_NEEDED libraries could not be linked/found.
|
|
|
|
if (count == 0) {
|
|
|
|
return;
|
|
|
|
}
|
2014-11-29 22:57:41 +01:00
|
|
|
|
2016-08-04 01:00:10 +02:00
|
|
|
soinfo_list_t unload_list;
|
2016-05-05 02:19:14 +02:00
|
|
|
for (size_t i = 0; i < count; ++i) {
|
|
|
|
soinfo* si = soinfos[i];
|
2014-11-29 22:57:41 +01:00
|
|
|
|
2016-05-05 02:19:14 +02:00
|
|
|
if (si->can_unload()) {
|
|
|
|
size_t ref_count = si->is_linked() ? si->decrement_ref_count() : 0;
|
|
|
|
if (ref_count == 0) {
|
|
|
|
unload_list.push_back(si);
|
|
|
|
} else {
|
|
|
|
TRACE("not unloading '%s' group, decrementing ref_count to %zd",
|
|
|
|
si->get_realpath(), ref_count);
|
2014-12-03 02:08:42 +01:00
|
|
|
}
|
2016-05-05 02:19:14 +02:00
|
|
|
} else {
|
|
|
|
TRACE("not unloading '%s' - the binary is flagged with NODELETE", si->get_realpath());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2014-12-03 02:08:42 +01:00
|
|
|
|
2016-05-05 02:19:14 +02:00
|
|
|
// This is used to identify soinfos outside of the load-group
|
|
|
|
// note that we cannot have > 1 in the array and have any of them
|
|
|
|
// linked. This is why we can safely use the first one.
|
|
|
|
soinfo* root = soinfos[0];
|
2014-12-03 02:08:42 +01:00
|
|
|
|
2016-08-04 01:00:10 +02:00
|
|
|
soinfo_list_t local_unload_list;
|
|
|
|
soinfo_list_t external_unload_list;
|
2016-05-05 02:19:14 +02:00
|
|
|
soinfo* si = nullptr;
|
2015-05-07 19:48:00 +02:00
|
|
|
|
2016-05-05 02:19:14 +02:00
|
|
|
while ((si = unload_list.pop_front()) != nullptr) {
|
|
|
|
if (local_unload_list.contains(si)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
local_unload_list.push_back(si);
|
|
|
|
|
|
|
|
if (si->has_min_version(0)) {
|
|
|
|
soinfo* child = nullptr;
|
|
|
|
while ((child = si->get_children().pop_front()) != nullptr) {
|
|
|
|
TRACE("%s@%p needs to unload %s@%p", si->get_realpath(), si,
|
|
|
|
child->get_realpath(), child);
|
|
|
|
|
2017-02-10 20:04:20 +01:00
|
|
|
child->get_parents().remove(si);
|
|
|
|
|
2016-05-05 02:19:14 +02:00
|
|
|
if (local_unload_list.contains(child)) {
|
|
|
|
continue;
|
|
|
|
} else if (child->is_linked() && child->get_local_group_root() != root) {
|
|
|
|
external_unload_list.push_back(child);
|
2017-02-10 20:04:20 +01:00
|
|
|
} else if (child->get_parents().empty()) {
|
|
|
|
unload_list.push_back(child);
|
2014-05-09 18:10:14 +02:00
|
|
|
}
|
2016-05-05 02:19:14 +02:00
|
|
|
}
|
|
|
|
} else {
|
2015-09-28 19:14:17 +02:00
|
|
|
#if !defined(__work_around_b_24465209__)
|
2016-05-05 02:19:14 +02:00
|
|
|
__libc_fatal("soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
|
2014-12-03 02:08:42 +01:00
|
|
|
#else
|
2016-05-05 02:19:14 +02:00
|
|
|
PRINT("warning: soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
|
|
|
|
for_each_dt_needed(si, [&] (const char* library_name) {
|
|
|
|
TRACE("deprecated (old format of soinfo): %s needs to unload %s",
|
|
|
|
si->get_realpath(), library_name);
|
|
|
|
|
|
|
|
soinfo* needed = find_library(si->get_primary_namespace(),
|
|
|
|
library_name, RTLD_NOLOAD, nullptr, nullptr);
|
|
|
|
|
|
|
|
if (needed != nullptr) {
|
|
|
|
// Not found: for example if symlink was deleted between dlopen and dlclose
|
|
|
|
// Since we cannot really handle errors at this point - print and continue.
|
|
|
|
PRINT("warning: couldn't find %s needed by %s on unload.",
|
|
|
|
library_name, si->get_realpath());
|
|
|
|
return;
|
|
|
|
} else if (local_unload_list.contains(needed)) {
|
|
|
|
// already visited
|
|
|
|
return;
|
|
|
|
} else if (needed->is_linked() && needed->get_local_group_root() != root) {
|
|
|
|
// external group
|
|
|
|
external_unload_list.push_back(needed);
|
|
|
|
} else {
|
|
|
|
// local group
|
|
|
|
unload_list.push_front(needed);
|
|
|
|
}
|
|
|
|
});
|
2014-12-03 02:08:42 +01:00
|
|
|
#endif
|
2009-03-04 04:28:35 +01:00
|
|
|
}
|
2016-05-05 02:19:14 +02:00
|
|
|
}
|
2009-03-04 04:28:35 +01:00
|
|
|
|
2016-05-05 02:19:14 +02:00
|
|
|
local_unload_list.for_each([](soinfo* si) {
|
|
|
|
si->call_destructors();
|
|
|
|
});
|
2009-03-04 04:28:35 +01:00
|
|
|
|
2016-05-05 02:19:14 +02:00
|
|
|
while ((si = local_unload_list.pop_front()) != nullptr) {
|
|
|
|
notify_gdb_of_unload(si);
|
2016-07-06 22:20:59 +02:00
|
|
|
get_cfi_shadow()->BeforeUnload(si);
|
2016-05-05 02:19:14 +02:00
|
|
|
soinfo_free(si);
|
|
|
|
}
|
2014-11-18 21:03:09 +01:00
|
|
|
|
2016-05-05 02:19:14 +02:00
|
|
|
while ((si = external_unload_list.pop_front()) != nullptr) {
|
|
|
|
soinfo_unload(si);
|
2014-11-18 21:03:09 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-11 01:08:14 +01:00
|
|
|
static std::string symbol_display_name(const char* sym_name, const char* sym_ver) {
|
|
|
|
if (sym_ver == nullptr) {
|
|
|
|
return sym_name;
|
|
|
|
}
|
|
|
|
|
2015-12-11 23:22:24 +01:00
|
|
|
return std::string(sym_name) + ", version " + sym_ver;
|
2015-12-11 01:08:14 +01:00
|
|
|
}
|
|
|
|
|
2016-04-11 21:42:58 +02:00
|
|
|
static android_namespace_t* get_caller_namespace(soinfo* caller) {
|
|
|
|
return caller != nullptr ? caller->get_primary_namespace() : g_anonymous_namespace;
|
|
|
|
}
|
|
|
|
|
2014-01-14 01:37:47 +01:00
|
|
|
void do_android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size) {
|
2014-08-27 05:48:11 +02:00
|
|
|
// Use basic string manipulation calls to avoid snprintf.
|
|
|
|
// snprintf indirectly calls pthread_getspecific to get the size of a buffer.
|
|
|
|
// When debug malloc is enabled, this call returns 0. This in turn causes
|
|
|
|
// snprintf to do nothing, which causes libraries to fail to load.
|
|
|
|
// See b/17302493 for further details.
|
|
|
|
// Once the above bug is fixed, this code can be modified to use
|
|
|
|
// snprintf again.
|
2017-03-06 22:02:29 +01:00
|
|
|
const auto& default_ld_paths = g_default_namespace.get_default_library_paths();
|
|
|
|
|
|
|
|
size_t required_size = 0;
|
|
|
|
for (const auto& path : default_ld_paths) {
|
|
|
|
required_size += path.size() + 1;
|
2015-07-11 02:54:01 +02:00
|
|
|
}
|
2017-03-06 22:02:29 +01:00
|
|
|
|
|
|
|
if (buffer_size < required_size) {
|
2015-03-31 03:43:38 +02:00
|
|
|
__libc_fatal("android_get_LD_LIBRARY_PATH failed, buffer too small: "
|
2017-03-06 22:02:29 +01:00
|
|
|
"buffer len %zu, required len %zu", buffer_size, required_size);
|
2014-08-27 05:48:11 +02:00
|
|
|
}
|
2017-03-06 22:02:29 +01:00
|
|
|
|
2015-07-11 02:54:01 +02:00
|
|
|
char* end = buffer;
|
2017-03-06 22:02:29 +01:00
|
|
|
for (size_t i = 0; i < default_ld_paths.size(); ++i) {
|
2015-07-11 02:54:01 +02:00
|
|
|
if (i > 0) *end++ = ':';
|
2017-03-06 22:02:29 +01:00
|
|
|
end = stpcpy(end, default_ld_paths[i].c_str());
|
2015-07-11 02:54:01 +02:00
|
|
|
}
|
2014-01-14 01:37:47 +01:00
|
|
|
}
|
|
|
|
|
2012-12-20 23:42:14 +01:00
|
|
|
void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path) {
|
linker: Allow an app to update it's own LD_LIBRARY_PATH
When the kernel executes a program which is setuid, setgid, has
file capabilities, or causes an SELinux domain transition, the
AT_SECURE flag is set. This flag instructs the dynamic linker to
prune any dangerous environment variables passed across security
boundaries.
For SELinux in particular, whether this flag is set depends on the
the "noatsecure" process permission. If that permission does not
exist, then AT_SECURE=1 whenever a domain transition occurs.
In https://android-review.googlesource.com/129971 , Android stopped
using noatsecure when executing init services. In
https://android-review.googlesource.com/130610 , init was flipped
back into SELinux enforcing mode, making ag/129971 active. The
combination of those two changes ensured that AT_SECURE=1 was
set when executing init spawned services.
In particular, AT_SECURE=1 is set when init executes zygote. Due to
the forking nature of zygote, AT_SECURE remains untouched when
executing zygote's children.
This causes problems for the code added in
https://android-review.googlesource.com/48409 . Specifically, if
AT_SECURE=1, an attempt to call android_update_LD_LIBRARY_PATH()
is silently ignored. This causes problems when art tries to adjust
the LD_LIBRARY_PATH for Android apps. Ultimately, apps are unable
to find shared libraries they depend on.
As discussed in bug 7896159, there's no security reason for
preventing an application from updating it's own LD_LIBRARY_PATH.
We only need to prune LD_LIBRARY_PATH when transitioning across
security boundaries, but not when we're entirely within a security
boundary.
Remove the AT_SECURE check within do_android_update_LD_LIBRARY_PATH().
It's unneeded and prevents an application from modifying it's own
LD_LIBRARY_PATH. This allows an application to specify a location
where it's dlopen()ed shared libraries should be loaded from.
There is no change to AT_SECURE handling in
__sanitize_environment_variables(). We continue to honor it there
to prevent using security sensitive environment variables across
an exec boundary.
Bug: 19559835
Change-Id: If4af2ee8e84265aaa0c93de8b281208b20d7942a
2015-03-07 22:37:05 +01:00
|
|
|
parse_LD_LIBRARY_PATH(ld_library_path);
|
2012-12-20 23:42:14 +01:00
|
|
|
}
|
|
|
|
|
2016-07-12 03:11:39 +02:00
|
|
|
static std::string android_dlextinfo_to_string(const android_dlextinfo* info) {
|
|
|
|
if (info == nullptr) {
|
|
|
|
return "(null)";
|
|
|
|
}
|
|
|
|
|
|
|
|
return android::base::StringPrintf("[flags=0x%" PRIx64 ","
|
|
|
|
" reserved_addr=%p,"
|
|
|
|
" reserved_size=0x%zx,"
|
|
|
|
" relro_fd=%d,"
|
|
|
|
" library_fd=%d,"
|
|
|
|
" library_fd_offset=0x%" PRIx64 ","
|
|
|
|
" library_namespace=%s@%p]",
|
|
|
|
info->flags,
|
|
|
|
info->reserved_addr,
|
|
|
|
info->reserved_size,
|
|
|
|
info->relro_fd,
|
|
|
|
info->library_fd,
|
|
|
|
info->library_fd_offset,
|
|
|
|
(info->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0 ?
|
|
|
|
(info->library_namespace != nullptr ?
|
|
|
|
info->library_namespace->get_name() : "(null)") : "(n/a)",
|
|
|
|
(info->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0 ?
|
|
|
|
info->library_namespace : nullptr);
|
|
|
|
}
|
|
|
|
|
2016-11-23 01:55:25 +01:00
|
|
|
void* do_dlopen(const char* name, int flags,
|
|
|
|
const android_dlextinfo* extinfo,
|
|
|
|
const void* caller_addr) {
|
2017-03-18 00:41:34 +01:00
|
|
|
std::string trace_prefix = std::string("dlopen: ") + (name == nullptr ? "(nullptr)" : name);
|
|
|
|
ScopedTrace trace(trace_prefix.c_str());
|
|
|
|
ScopedTrace loading_trace((trace_prefix + " - loading and linking").c_str());
|
2015-12-11 01:08:14 +01:00
|
|
|
soinfo* const caller = find_containing_library(caller_addr);
|
2016-07-12 03:11:39 +02:00
|
|
|
android_namespace_t* ns = get_caller_namespace(caller);
|
|
|
|
|
|
|
|
LD_LOG(kLogDlopen,
|
|
|
|
"dlopen(name=\"%s\", flags=0x%x, extinfo=%s, caller=\"%s\", caller_ns=%s@%p) ...",
|
|
|
|
name,
|
|
|
|
flags,
|
|
|
|
android_dlextinfo_to_string(extinfo).c_str(),
|
|
|
|
caller == nullptr ? "(null)" : caller->get_realpath(),
|
|
|
|
ns == nullptr ? "(null)" : ns->get_name(),
|
|
|
|
ns);
|
|
|
|
|
|
|
|
auto failure_guard = make_scope_guard([&]() {
|
|
|
|
LD_LOG(kLogDlopen, "... dlopen failed: %s", linker_get_error_buffer());
|
|
|
|
});
|
2015-12-11 01:08:14 +01:00
|
|
|
|
2014-05-20 00:06:58 +02:00
|
|
|
if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL|RTLD_NODELETE|RTLD_NOLOAD)) != 0) {
|
2012-12-19 00:57:55 +01:00
|
|
|
DL_ERR("invalid flags to dlopen: %x", flags);
|
2014-08-29 21:02:36 +02:00
|
|
|
return nullptr;
|
2012-12-19 00:57:55 +01:00
|
|
|
}
|
2015-10-30 01:01:24 +01:00
|
|
|
|
2014-10-04 02:52:44 +02:00
|
|
|
if (extinfo != nullptr) {
|
|
|
|
if ((extinfo->flags & ~(ANDROID_DLEXT_VALID_FLAG_BITS)) != 0) {
|
|
|
|
DL_ERR("invalid extended flags to android_dlopen_ext: 0x%" PRIx64, extinfo->flags);
|
|
|
|
return nullptr;
|
|
|
|
}
|
2015-10-08 01:34:20 +02:00
|
|
|
|
2014-10-04 02:52:44 +02:00
|
|
|
if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) == 0 &&
|
2014-10-21 21:09:18 +02:00
|
|
|
(extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
|
2015-03-31 03:43:38 +02:00
|
|
|
DL_ERR("invalid extended flag combination (ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET without "
|
|
|
|
"ANDROID_DLEXT_USE_LIBRARY_FD): 0x%" PRIx64, extinfo->flags);
|
2014-10-04 02:52:44 +02:00
|
|
|
return nullptr;
|
|
|
|
}
|
2015-10-08 01:34:20 +02:00
|
|
|
|
|
|
|
if ((extinfo->flags & ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS) != 0 &&
|
|
|
|
(extinfo->flags & (ANDROID_DLEXT_RESERVED_ADDRESS | ANDROID_DLEXT_RESERVED_ADDRESS_HINT)) != 0) {
|
|
|
|
DL_ERR("invalid extended flag combination: ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS is not "
|
|
|
|
"compatible with ANDROID_DLEXT_RESERVED_ADDRESS/ANDROID_DLEXT_RESERVED_ADDRESS_HINT");
|
|
|
|
return nullptr;
|
|
|
|
}
|
2015-10-30 01:01:24 +01:00
|
|
|
|
|
|
|
if ((extinfo->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0) {
|
|
|
|
if (extinfo->library_namespace == nullptr) {
|
|
|
|
DL_ERR("ANDROID_DLEXT_USE_NAMESPACE is set but extinfo->library_namespace is null");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
ns = extinfo->library_namespace;
|
|
|
|
}
|
2014-02-06 15:34:21 +01:00
|
|
|
}
|
2015-01-23 21:03:53 +01:00
|
|
|
|
2016-08-10 04:38:43 +02:00
|
|
|
std::string asan_name_holder;
|
|
|
|
|
|
|
|
const char* translated_name = name;
|
2016-12-05 22:35:47 +01:00
|
|
|
if (g_is_asan && translated_name != nullptr && translated_name[0] == '/') {
|
|
|
|
char translated_path[PATH_MAX];
|
|
|
|
if (realpath(translated_name, translated_path) != nullptr) {
|
2017-03-30 00:31:34 +02:00
|
|
|
asan_name_holder = std::string(kAsanLibDirPrefix) + translated_path;
|
|
|
|
if (file_exists(asan_name_holder.c_str())) {
|
|
|
|
translated_name = asan_name_holder.c_str();
|
|
|
|
PRINT("linker_asan dlopen translating \"%s\" -> \"%s\"", name, translated_name);
|
2016-08-10 04:38:43 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-23 21:03:53 +01:00
|
|
|
ProtectedDataGuard guard;
|
2016-08-10 04:38:43 +02:00
|
|
|
soinfo* si = find_library(ns, translated_name, flags, extinfo, caller);
|
2017-03-18 00:41:34 +01:00
|
|
|
loading_trace.End();
|
|
|
|
|
2014-08-29 21:02:36 +02:00
|
|
|
if (si != nullptr) {
|
2016-07-12 03:11:39 +02:00
|
|
|
void* handle = si->to_handle();
|
2016-11-21 19:44:35 +01:00
|
|
|
LD_LOG(kLogDlopen,
|
|
|
|
"... dlopen calling constructors: realpath=\"%s\", soname=\"%s\", handle=%p",
|
|
|
|
si->get_realpath(), si->get_soname(), handle);
|
|
|
|
si->call_constructors();
|
|
|
|
failure_guard.disable();
|
2016-07-12 03:11:39 +02:00
|
|
|
LD_LOG(kLogDlopen,
|
|
|
|
"... dlopen successful: realpath=\"%s\", soname=\"%s\", handle=%p",
|
|
|
|
si->get_realpath(), si->get_soname(), handle);
|
|
|
|
return handle;
|
2012-11-01 23:16:56 +01:00
|
|
|
}
|
2015-10-30 01:01:24 +01:00
|
|
|
|
2016-03-24 23:30:30 +01:00
|
|
|
return nullptr;
|
2012-11-01 23:16:56 +01:00
|
|
|
}
|
2009-03-04 04:28:35 +01:00
|
|
|
|
2015-12-11 01:08:14 +01:00
|
|
|
int do_dladdr(const void* addr, Dl_info* info) {
|
|
|
|
// Determine if this address can be found in any library currently mapped.
|
|
|
|
soinfo* si = find_containing_library(addr);
|
|
|
|
if (si == nullptr) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(info, 0, sizeof(Dl_info));
|
|
|
|
|
|
|
|
info->dli_fname = si->get_realpath();
|
|
|
|
// Address at which the shared object is loaded.
|
|
|
|
info->dli_fbase = reinterpret_cast<void*>(si->base);
|
|
|
|
|
|
|
|
// Determine if any symbol in the library contains the specified address.
|
|
|
|
ElfW(Sym)* sym = si->find_symbol_by_address(addr);
|
|
|
|
if (sym != nullptr) {
|
|
|
|
info->dli_sname = si->get_string(sym->st_name);
|
|
|
|
info->dli_saddr = reinterpret_cast<void*>(si->resolve_symbol_address(sym));
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2016-03-24 23:30:30 +01:00
|
|
|
static soinfo* soinfo_from_handle(void* handle) {
|
|
|
|
if ((reinterpret_cast<uintptr_t>(handle) & 1) != 0) {
|
|
|
|
auto it = g_soinfo_handles_map.find(reinterpret_cast<uintptr_t>(handle));
|
|
|
|
if (it == g_soinfo_handles_map.end()) {
|
|
|
|
return nullptr;
|
|
|
|
} else {
|
|
|
|
return it->second;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return static_cast<soinfo*>(handle);
|
|
|
|
}
|
|
|
|
|
2016-11-23 01:55:25 +01:00
|
|
|
bool do_dlsym(void* handle,
|
|
|
|
const char* sym_name,
|
|
|
|
const char* sym_ver,
|
|
|
|
const void* caller_addr,
|
|
|
|
void** symbol) {
|
2017-03-21 18:29:06 +01:00
|
|
|
ScopedTrace trace("dlsym");
|
2015-12-11 01:08:14 +01:00
|
|
|
#if !defined(__LP64__)
|
|
|
|
if (handle == nullptr) {
|
|
|
|
DL_ERR("dlsym failed: library handle is null");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
soinfo* found = nullptr;
|
|
|
|
const ElfW(Sym)* sym = nullptr;
|
|
|
|
soinfo* caller = find_containing_library(caller_addr);
|
2016-04-11 21:42:58 +02:00
|
|
|
android_namespace_t* ns = get_caller_namespace(caller);
|
2016-12-13 01:30:15 +01:00
|
|
|
soinfo* si = nullptr;
|
|
|
|
if (handle != RTLD_DEFAULT && handle != RTLD_NEXT) {
|
|
|
|
si = soinfo_from_handle(handle);
|
|
|
|
}
|
|
|
|
|
|
|
|
LD_LOG(kLogDlsym,
|
|
|
|
"dlsym(handle=%p(\"%s\"), sym_name=\"%s\", sym_ver=\"%s\", caller=\"%s\", caller_ns=%s@%p) ...",
|
|
|
|
handle,
|
|
|
|
si != nullptr ? si->get_realpath() : "n/a",
|
|
|
|
sym_name,
|
|
|
|
sym_ver,
|
|
|
|
caller == nullptr ? "(null)" : caller->get_realpath(),
|
|
|
|
ns == nullptr ? "(null)" : ns->get_name(),
|
|
|
|
ns);
|
|
|
|
|
|
|
|
auto failure_guard = make_scope_guard([&]() {
|
|
|
|
LD_LOG(kLogDlsym, "... dlsym failed: %s", linker_get_error_buffer());
|
|
|
|
});
|
|
|
|
|
|
|
|
if (sym_name == nullptr) {
|
|
|
|
DL_ERR("dlsym failed: symbol name is null");
|
|
|
|
return false;
|
|
|
|
}
|
2015-12-11 01:08:14 +01:00
|
|
|
|
|
|
|
version_info vi_instance;
|
|
|
|
version_info* vi = nullptr;
|
|
|
|
|
|
|
|
if (sym_ver != nullptr) {
|
2015-12-11 23:22:24 +01:00
|
|
|
vi_instance.name = sym_ver;
|
|
|
|
vi_instance.elf_hash = calculate_elf_hash(sym_ver);
|
2015-12-11 01:08:14 +01:00
|
|
|
vi = &vi_instance;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (handle == RTLD_DEFAULT || handle == RTLD_NEXT) {
|
|
|
|
sym = dlsym_linear_lookup(ns, sym_name, vi, &found, caller, handle);
|
|
|
|
} else {
|
2016-03-24 23:30:30 +01:00
|
|
|
if (si == nullptr) {
|
|
|
|
DL_ERR("dlsym failed: invalid handle: %p", handle);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
sym = dlsym_handle_lookup(si, &found, sym_name, vi);
|
2015-12-11 01:08:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (sym != nullptr) {
|
|
|
|
uint32_t bind = ELF_ST_BIND(sym->st_info);
|
|
|
|
|
|
|
|
if ((bind == STB_GLOBAL || bind == STB_WEAK) && sym->st_shndx != 0) {
|
|
|
|
*symbol = reinterpret_cast<void*>(found->resolve_symbol_address(sym));
|
2016-12-13 01:30:15 +01:00
|
|
|
failure_guard.disable();
|
|
|
|
LD_LOG(kLogDlsym,
|
|
|
|
"... dlsym successful: sym_name=\"%s\", sym_ver=\"%s\", found in=\"%s\", address=%p",
|
|
|
|
sym_name, sym_ver, found->get_soname(), *symbol);
|
2015-12-11 01:08:14 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
DL_ERR("symbol \"%s\" found but not global", symbol_display_name(sym_name, sym_ver).c_str());
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
DL_ERR("undefined symbol: %s", symbol_display_name(sym_name, sym_ver).c_str());
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-03-24 23:30:30 +01:00
|
|
|
int do_dlclose(void* handle) {
|
2017-03-21 18:29:06 +01:00
|
|
|
ScopedTrace trace("dlclose");
|
2015-01-23 21:03:53 +01:00
|
|
|
ProtectedDataGuard guard;
|
2016-03-24 23:30:30 +01:00
|
|
|
soinfo* si = soinfo_from_handle(handle);
|
|
|
|
if (si == nullptr) {
|
|
|
|
DL_ERR("invalid handle: %p", handle);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-05-20 00:06:58 +02:00
|
|
|
soinfo_unload(si);
|
2016-03-24 23:30:30 +01:00
|
|
|
return 0;
|
2009-03-04 04:28:35 +01:00
|
|
|
}
|
|
|
|
|
2017-02-03 23:07:34 +01:00
|
|
|
bool init_anonymous_namespace(const char* shared_lib_sonames, const char* library_search_path) {
|
|
|
|
if (g_anonymous_namespace_initialized) {
|
|
|
|
DL_ERR("anonymous namespace has already been initialized.");
|
2016-04-21 23:57:38 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-10-30 01:01:24 +01:00
|
|
|
ProtectedDataGuard guard;
|
|
|
|
|
2015-11-23 20:26:35 +01:00
|
|
|
// create anonymous namespace
|
2015-12-14 23:11:17 +01:00
|
|
|
// When the caller is nullptr - create_namespace will take global group
|
|
|
|
// from the anonymous namespace, which is fine because anonymous namespace
|
|
|
|
// is still pointing to the default one.
|
2015-11-23 20:26:35 +01:00
|
|
|
android_namespace_t* anon_ns =
|
2017-02-03 23:07:34 +01:00
|
|
|
create_namespace(nullptr,
|
|
|
|
"(anonymous)",
|
|
|
|
nullptr,
|
|
|
|
library_search_path,
|
2017-03-28 00:42:17 +02:00
|
|
|
ANDROID_NAMESPACE_TYPE_ISOLATED,
|
2017-02-03 23:07:34 +01:00
|
|
|
nullptr,
|
|
|
|
&g_default_namespace);
|
2015-11-23 20:26:35 +01:00
|
|
|
|
|
|
|
if (anon_ns == nullptr) {
|
2017-02-03 23:07:34 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!link_namespaces(anon_ns, &g_default_namespace, shared_lib_sonames)) {
|
2015-11-23 20:26:35 +01:00
|
|
|
return false;
|
|
|
|
}
|
2017-02-02 00:28:52 +01:00
|
|
|
|
2015-11-23 20:26:35 +01:00
|
|
|
g_anonymous_namespace = anon_ns;
|
2017-03-07 20:02:10 +01:00
|
|
|
g_anonymous_namespace_initialized = true;
|
2017-02-03 23:07:34 +01:00
|
|
|
|
2015-10-30 01:01:24 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-08-04 01:00:10 +02:00
|
|
|
static void add_soinfos_to_namespace(const soinfo_list_t& soinfos, android_namespace_t* ns) {
|
|
|
|
ns->add_soinfos(soinfos);
|
|
|
|
for (auto si : soinfos) {
|
|
|
|
si->add_secondary_namespace(ns);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-14 23:11:17 +01:00
|
|
|
android_namespace_t* create_namespace(const void* caller_addr,
|
|
|
|
const char* name,
|
2015-10-30 01:01:24 +01:00
|
|
|
const char* ld_library_path,
|
|
|
|
const char* default_library_path,
|
2015-12-14 23:11:17 +01:00
|
|
|
uint64_t type,
|
2016-05-13 00:20:21 +02:00
|
|
|
const char* permitted_when_isolated_path,
|
|
|
|
android_namespace_t* parent_namespace) {
|
|
|
|
if (parent_namespace == nullptr) {
|
2016-05-23 19:31:11 +02:00
|
|
|
// if parent_namespace is nullptr -> set it to the caller namespace
|
|
|
|
soinfo* caller_soinfo = find_containing_library(caller_addr);
|
|
|
|
|
|
|
|
parent_namespace = caller_soinfo != nullptr ?
|
|
|
|
caller_soinfo->get_primary_namespace() :
|
|
|
|
g_anonymous_namespace;
|
2016-05-13 00:20:21 +02:00
|
|
|
}
|
|
|
|
|
2015-10-30 01:01:24 +01:00
|
|
|
ProtectedDataGuard guard;
|
|
|
|
std::vector<std::string> ld_library_paths;
|
|
|
|
std::vector<std::string> default_library_paths;
|
2015-12-08 19:47:13 +01:00
|
|
|
std::vector<std::string> permitted_paths;
|
2015-10-30 01:01:24 +01:00
|
|
|
|
|
|
|
parse_path(ld_library_path, ":", &ld_library_paths);
|
|
|
|
parse_path(default_library_path, ":", &default_library_paths);
|
2015-12-08 19:47:13 +01:00
|
|
|
parse_path(permitted_when_isolated_path, ":", &permitted_paths);
|
2015-10-30 01:01:24 +01:00
|
|
|
|
|
|
|
android_namespace_t* ns = new (g_namespace_allocator.alloc()) android_namespace_t();
|
|
|
|
ns->set_name(name);
|
2015-12-14 23:11:17 +01:00
|
|
|
ns->set_isolated((type & ANDROID_NAMESPACE_TYPE_ISOLATED) != 0);
|
2015-10-30 01:01:24 +01:00
|
|
|
ns->set_ld_library_paths(std::move(ld_library_paths));
|
|
|
|
ns->set_default_library_paths(std::move(default_library_paths));
|
2015-12-08 19:47:13 +01:00
|
|
|
ns->set_permitted_paths(std::move(permitted_paths));
|
2015-10-30 01:01:24 +01:00
|
|
|
|
2015-12-14 23:11:17 +01:00
|
|
|
if ((type & ANDROID_NAMESPACE_TYPE_SHARED) != 0) {
|
2016-05-13 00:20:21 +02:00
|
|
|
// If shared - clone the parent namespace
|
2016-08-04 01:00:10 +02:00
|
|
|
add_soinfos_to_namespace(parent_namespace->soinfo_list(), ns);
|
2015-12-14 23:11:17 +01:00
|
|
|
} else {
|
2016-05-13 00:20:21 +02:00
|
|
|
// If not shared - copy only the shared group
|
2016-08-04 01:00:10 +02:00
|
|
|
add_soinfos_to_namespace(get_shared_group(parent_namespace), ns);
|
2015-12-14 23:11:17 +01:00
|
|
|
}
|
2015-10-30 01:01:24 +01:00
|
|
|
|
|
|
|
return ns;
|
|
|
|
}
|
|
|
|
|
2017-02-03 23:07:34 +01:00
|
|
|
bool link_namespaces(android_namespace_t* namespace_from,
|
|
|
|
android_namespace_t* namespace_to,
|
|
|
|
const char* shared_lib_sonames) {
|
|
|
|
if (namespace_to == nullptr) {
|
|
|
|
namespace_to = &g_default_namespace;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (namespace_from == nullptr) {
|
|
|
|
DL_ERR("error linking namespaces: namespace_from is null.");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (shared_lib_sonames == nullptr || shared_lib_sonames[0] == '\0') {
|
|
|
|
DL_ERR("error linking namespaces \"%s\"->\"%s\": the list of shared libraries is empty.",
|
|
|
|
namespace_from->get_name(), namespace_to->get_name());
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto sonames = android::base::Split(shared_lib_sonames, ":");
|
|
|
|
std::unordered_set<std::string> sonames_set(sonames.begin(), sonames.end());
|
|
|
|
|
|
|
|
ProtectedDataGuard guard;
|
|
|
|
namespace_from->add_linked_namespace(namespace_to, sonames_set);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-08-04 20:50:36 +02:00
|
|
|
ElfW(Addr) call_ifunc_resolver(ElfW(Addr) resolver_addr) {
|
2014-09-12 00:16:03 +02:00
|
|
|
typedef ElfW(Addr) (*ifunc_resolver_t)(void);
|
|
|
|
ifunc_resolver_t ifunc_resolver = reinterpret_cast<ifunc_resolver_t>(resolver_addr);
|
|
|
|
ElfW(Addr) ifunc_addr = ifunc_resolver();
|
2015-03-31 03:43:38 +02:00
|
|
|
TRACE_TYPE(RELO, "Called ifunc_resolver@%p. The result is %p",
|
|
|
|
ifunc_resolver, reinterpret_cast<void*>(ifunc_addr));
|
2014-07-23 20:22:25 +02:00
|
|
|
|
2014-09-12 00:16:03 +02:00
|
|
|
return ifunc_addr;
|
2014-07-23 20:22:25 +02:00
|
|
|
}
|
|
|
|
|
2015-04-09 22:42:33 +02:00
|
|
|
const version_info* VersionTracker::get_version_info(ElfW(Versym) source_symver) const {
|
|
|
|
if (source_symver < 2 ||
|
|
|
|
source_symver >= version_infos.size() ||
|
|
|
|
version_infos[source_symver].name == nullptr) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
return &version_infos[source_symver];
|
|
|
|
}
|
|
|
|
|
|
|
|
void VersionTracker::add_version_info(size_t source_index,
|
|
|
|
ElfW(Word) elf_hash,
|
|
|
|
const char* ver_name,
|
|
|
|
const soinfo* target_si) {
|
|
|
|
if (source_index >= version_infos.size()) {
|
|
|
|
version_infos.resize(source_index+1);
|
|
|
|
}
|
|
|
|
|
|
|
|
version_infos[source_index].elf_hash = elf_hash;
|
|
|
|
version_infos[source_index].name = ver_name;
|
|
|
|
version_infos[source_index].target_si = target_si;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool VersionTracker::init_verneed(const soinfo* si_from) {
|
|
|
|
uintptr_t verneed_ptr = si_from->get_verneed_ptr();
|
|
|
|
|
|
|
|
if (verneed_ptr == 0) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t verneed_cnt = si_from->get_verneed_cnt();
|
|
|
|
|
|
|
|
for (size_t i = 0, offset = 0; i<verneed_cnt; ++i) {
|
|
|
|
const ElfW(Verneed)* verneed = reinterpret_cast<ElfW(Verneed)*>(verneed_ptr + offset);
|
|
|
|
size_t vernaux_offset = offset + verneed->vn_aux;
|
|
|
|
offset += verneed->vn_next;
|
|
|
|
|
|
|
|
if (verneed->vn_version != 1) {
|
|
|
|
DL_ERR("unsupported verneed[%zd] vn_version: %d (expected 1)", i, verneed->vn_version);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* target_soname = si_from->get_string(verneed->vn_file);
|
|
|
|
// find it in dependencies
|
|
|
|
soinfo* target_si = si_from->get_children().find_if([&](const soinfo* si) {
|
2015-05-06 20:05:27 +02:00
|
|
|
return si->get_soname() != nullptr && strcmp(si->get_soname(), target_soname) == 0;
|
2015-04-09 22:42:33 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
if (target_si == nullptr) {
|
|
|
|
DL_ERR("cannot find \"%s\" from verneed[%zd] in DT_NEEDED list for \"%s\"",
|
2015-05-07 19:48:00 +02:00
|
|
|
target_soname, i, si_from->get_realpath());
|
2015-04-09 22:42:33 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (size_t j = 0; j<verneed->vn_cnt; ++j) {
|
|
|
|
const ElfW(Vernaux)* vernaux = reinterpret_cast<ElfW(Vernaux)*>(verneed_ptr + vernaux_offset);
|
|
|
|
vernaux_offset += vernaux->vna_next;
|
|
|
|
|
|
|
|
const ElfW(Word) elf_hash = vernaux->vna_hash;
|
|
|
|
const char* ver_name = si_from->get_string(vernaux->vna_name);
|
|
|
|
ElfW(Half) source_index = vernaux->vna_other;
|
|
|
|
|
|
|
|
add_version_info(source_index, elf_hash, ver_name, target_si);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-08-04 20:50:36 +02:00
|
|
|
template <typename F>
|
|
|
|
static bool for_each_verdef(const soinfo* si, F functor) {
|
|
|
|
if (!si->has_min_version(2)) {
|
|
|
|
return true;
|
|
|
|
}
|
2015-04-09 22:42:33 +02:00
|
|
|
|
2016-08-04 20:50:36 +02:00
|
|
|
uintptr_t verdef_ptr = si->get_verdef_ptr();
|
|
|
|
if (verdef_ptr == 0) {
|
2015-04-09 22:42:33 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-08-04 20:50:36 +02:00
|
|
|
size_t offset = 0;
|
2015-04-09 22:42:33 +02:00
|
|
|
|
2016-08-04 20:50:36 +02:00
|
|
|
size_t verdef_cnt = si->get_verdef_cnt();
|
|
|
|
for (size_t i = 0; i<verdef_cnt; ++i) {
|
|
|
|
const ElfW(Verdef)* verdef = reinterpret_cast<ElfW(Verdef)*>(verdef_ptr + offset);
|
|
|
|
size_t verdaux_offset = offset + verdef->vd_aux;
|
|
|
|
offset += verdef->vd_next;
|
2015-05-01 01:11:48 +02:00
|
|
|
|
2016-08-04 20:50:36 +02:00
|
|
|
if (verdef->vd_version != 1) {
|
|
|
|
DL_ERR("unsupported verdef[%zd] vd_version: %d (expected 1) library: %s",
|
|
|
|
i, verdef->vd_version, si->get_realpath());
|
|
|
|
return false;
|
|
|
|
}
|
2015-05-01 01:11:48 +02:00
|
|
|
|
2016-08-04 20:50:36 +02:00
|
|
|
if ((verdef->vd_flags & VER_FLG_BASE) != 0) {
|
|
|
|
// "this is the version of the file itself. It must not be used for
|
|
|
|
// matching a symbol. It can be used to match references."
|
|
|
|
//
|
|
|
|
// http://www.akkadia.org/drepper/symbol-versioning
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (verdef->vd_cnt == 0) {
|
|
|
|
DL_ERR("invalid verdef[%zd] vd_cnt == 0 (version without a name)", i);
|
2015-05-01 01:11:48 +02:00
|
|
|
return false;
|
|
|
|
}
|
2016-08-04 20:50:36 +02:00
|
|
|
|
|
|
|
const ElfW(Verdaux)* verdaux = reinterpret_cast<ElfW(Verdaux)*>(verdef_ptr + verdaux_offset);
|
|
|
|
|
|
|
|
if (functor(i, verdef, verdaux) == true) {
|
|
|
|
break;
|
|
|
|
}
|
2015-05-01 01:11:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-08-04 20:50:36 +02:00
|
|
|
bool find_verdef_version_index(const soinfo* si, const version_info* vi, ElfW(Versym)* versym) {
|
|
|
|
if (vi == nullptr) {
|
|
|
|
*versym = kVersymNotNeeded;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
*versym = kVersymGlobal;
|
|
|
|
|
|
|
|
return for_each_verdef(si,
|
|
|
|
[&](size_t, const ElfW(Verdef)* verdef, const ElfW(Verdaux)* verdaux) {
|
|
|
|
if (verdef->vd_hash == vi->elf_hash &&
|
|
|
|
strcmp(vi->name, si->get_string(verdaux->vda_name)) == 0) {
|
|
|
|
*versym = verdef->vd_ndx;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool VersionTracker::init_verdef(const soinfo* si_from) {
|
|
|
|
return for_each_verdef(si_from,
|
|
|
|
[&](size_t, const ElfW(Verdef)* verdef, const ElfW(Verdaux)* verdaux) {
|
|
|
|
add_version_info(verdef->vd_ndx, verdef->vd_hash,
|
|
|
|
si_from->get_string(verdaux->vda_name), si_from);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool VersionTracker::init(const soinfo* si_from) {
|
|
|
|
if (!si_from->has_min_version(2)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return init_verneed(si_from) && init_verdef(si_from);
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO (dimitry): Methods below need to be moved out of soinfo
|
|
|
|
// and in more isolated file in order minimize dependencies on
|
|
|
|
// unnecessary object in the linker binary. Consider making them
|
|
|
|
// independent from soinfo (?).
|
|
|
|
bool soinfo::lookup_version_info(const VersionTracker& version_tracker, ElfW(Word) sym,
|
|
|
|
const char* sym_name, const version_info** vi) {
|
|
|
|
const ElfW(Versym)* sym_ver_ptr = get_versym(sym);
|
|
|
|
ElfW(Versym) sym_ver = sym_ver_ptr == nullptr ? 0 : *sym_ver_ptr;
|
|
|
|
|
|
|
|
if (sym_ver != VER_NDX_LOCAL && sym_ver != VER_NDX_GLOBAL) {
|
|
|
|
*vi = version_tracker.get_version_info(sym_ver);
|
|
|
|
|
|
|
|
if (*vi == nullptr) {
|
|
|
|
DL_ERR("cannot find verneed/verdef for version index=%d "
|
|
|
|
"referenced by symbol \"%s\" at \"%s\"", sym_ver, sym_name, get_realpath());
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// there is no version info
|
|
|
|
*vi = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-08-09 15:58:55 +02:00
|
|
|
#if !defined(__mips__)
|
|
|
|
#if defined(USE_RELA)
|
|
|
|
static ElfW(Addr) get_addend(ElfW(Rela)* rela, ElfW(Addr) reloc_addr __unused) {
|
|
|
|
return rela->r_addend;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
static ElfW(Addr) get_addend(ElfW(Rel)* rel, ElfW(Addr) reloc_addr) {
|
|
|
|
if (ELFW(R_TYPE)(rel->r_info) == R_GENERIC_RELATIVE ||
|
|
|
|
ELFW(R_TYPE)(rel->r_info) == R_GENERIC_IRELATIVE) {
|
|
|
|
return *reinterpret_cast<ElfW(Addr)*>(reloc_addr);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2015-02-04 01:06:47 +01:00
|
|
|
template<typename ElfRelIteratorT>
|
2015-05-01 04:49:19 +02:00
|
|
|
bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& rel_iterator,
|
|
|
|
const soinfo_list_t& global_group, const soinfo_list_t& local_group) {
|
2015-02-04 01:06:47 +01:00
|
|
|
for (size_t idx = 0; rel_iterator.has_next(); ++idx) {
|
|
|
|
const auto rel = rel_iterator.next();
|
2015-02-05 01:05:30 +01:00
|
|
|
if (rel == nullptr) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-01-13 21:12:38 +01:00
|
|
|
ElfW(Word) type = ELFW(R_TYPE)(rel->r_info);
|
|
|
|
ElfW(Word) sym = ELFW(R_SYM)(rel->r_info);
|
|
|
|
|
|
|
|
ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rel->r_offset + load_bias);
|
2014-02-11 02:46:57 +01:00
|
|
|
ElfW(Addr) sym_addr = 0;
|
2014-08-29 21:02:36 +02:00
|
|
|
const char* sym_name = nullptr;
|
2015-01-13 21:12:38 +01:00
|
|
|
ElfW(Addr) addend = get_addend(rel, reloc);
|
2013-10-05 02:01:33 +02:00
|
|
|
|
2016-07-21 20:33:40 +02:00
|
|
|
DEBUG("Processing \"%s\" relocation at index %zd", get_realpath(), idx);
|
2015-01-09 08:30:15 +01:00
|
|
|
if (type == R_GENERIC_NONE) {
|
2013-10-05 02:01:33 +02:00
|
|
|
continue;
|
|
|
|
}
|
2014-09-06 01:42:53 +02:00
|
|
|
|
2015-04-09 22:42:33 +02:00
|
|
|
const ElfW(Sym)* s = nullptr;
|
2014-09-06 01:42:53 +02:00
|
|
|
soinfo* lsi = nullptr;
|
|
|
|
|
2013-10-05 02:01:33 +02:00
|
|
|
if (sym != 0) {
|
2014-11-13 18:39:20 +01:00
|
|
|
sym_name = get_string(symtab_[sym].st_name);
|
2015-05-01 01:11:48 +02:00
|
|
|
const version_info* vi = nullptr;
|
2015-04-09 22:42:33 +02:00
|
|
|
|
2015-05-01 01:11:48 +02:00
|
|
|
if (!lookup_version_info(version_tracker, sym, sym_name, &vi)) {
|
|
|
|
return false;
|
|
|
|
}
|
2015-04-09 22:42:33 +02:00
|
|
|
|
2015-05-01 01:11:48 +02:00
|
|
|
if (!soinfo_do_lookup(this, sym_name, vi, &lsi, global_group, local_group, &s)) {
|
|
|
|
return false;
|
2015-04-09 22:42:33 +02:00
|
|
|
}
|
2015-05-01 01:11:48 +02:00
|
|
|
|
2014-08-29 21:02:36 +02:00
|
|
|
if (s == nullptr) {
|
2013-10-05 02:01:33 +02:00
|
|
|
// We only allow an undefined symbol if this is a weak reference...
|
2014-11-13 18:39:20 +01:00
|
|
|
s = &symtab_[sym];
|
2013-10-05 02:01:33 +02:00
|
|
|
if (ELF_ST_BIND(s->st_info) != STB_WEAK) {
|
2015-05-07 19:48:00 +02:00
|
|
|
DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, get_realpath());
|
2015-01-14 20:36:38 +01:00
|
|
|
return false;
|
2013-10-05 02:01:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* IHI0044C AAELF 4.5.1.1:
|
|
|
|
|
|
|
|
Libraries are not searched to resolve weak references.
|
|
|
|
It is not an error for a weak reference to remain unsatisfied.
|
|
|
|
|
|
|
|
During linking, the value of an undefined weak reference is:
|
|
|
|
- Zero if the relocation type is absolute
|
|
|
|
- The address of the place if the relocation is pc-relative
|
|
|
|
- The address of nominal base address if the relocation
|
|
|
|
type is base-relative.
|
|
|
|
*/
|
|
|
|
|
|
|
|
switch (type) {
|
2015-01-13 21:17:31 +01:00
|
|
|
case R_GENERIC_JUMP_SLOT:
|
|
|
|
case R_GENERIC_GLOB_DAT:
|
|
|
|
case R_GENERIC_RELATIVE:
|
|
|
|
case R_GENERIC_IRELATIVE:
|
2013-10-10 16:19:31 +02:00
|
|
|
#if defined(__aarch64__)
|
2014-09-12 18:43:13 +02:00
|
|
|
case R_AARCH64_ABS64:
|
|
|
|
case R_AARCH64_ABS32:
|
|
|
|
case R_AARCH64_ABS16:
|
2015-01-13 21:17:31 +01:00
|
|
|
#elif defined(__x86_64__)
|
|
|
|
case R_X86_64_32:
|
|
|
|
case R_X86_64_64:
|
2015-01-13 21:12:38 +01:00
|
|
|
#elif defined(__arm__)
|
|
|
|
case R_ARM_ABS32:
|
|
|
|
#elif defined(__i386__)
|
|
|
|
case R_386_32:
|
2015-01-13 21:17:31 +01:00
|
|
|
#endif
|
2014-09-12 18:43:13 +02:00
|
|
|
/*
|
|
|
|
* The sym_addr was initialized to be zero above, or the relocation
|
|
|
|
* code below does not care about value of sym_addr.
|
|
|
|
* No need to do anything.
|
|
|
|
*/
|
|
|
|
break;
|
2015-01-13 21:17:31 +01:00
|
|
|
#if defined(__x86_64__)
|
2015-01-13 23:31:54 +01:00
|
|
|
case R_X86_64_PC32:
|
|
|
|
sym_addr = reloc;
|
|
|
|
break;
|
2015-01-13 21:12:38 +01:00
|
|
|
#elif defined(__i386__)
|
|
|
|
case R_386_PC32:
|
|
|
|
sym_addr = reloc;
|
|
|
|
break;
|
2015-01-13 23:31:54 +01:00
|
|
|
#endif
|
2014-09-12 18:43:13 +02:00
|
|
|
default:
|
2015-01-13 21:12:38 +01:00
|
|
|
DL_ERR("unknown weak reloc type %d @ %p (%zu)", type, rel, idx);
|
2015-01-14 20:36:38 +01:00
|
|
|
return false;
|
2013-10-05 02:01:33 +02:00
|
|
|
}
|
2015-07-26 16:37:09 +02:00
|
|
|
} else { // We got a definition.
|
|
|
|
#if !defined(__LP64__)
|
|
|
|
// When relocating dso with text_relocation .text segment is
|
|
|
|
// not executable. We need to restore elf flags before resolving
|
|
|
|
// STT_GNU_IFUNC symbol.
|
|
|
|
bool protect_segments = has_text_relocations &&
|
|
|
|
lsi == this &&
|
|
|
|
ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC;
|
|
|
|
if (protect_segments) {
|
|
|
|
if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
|
|
|
|
DL_ERR("can't protect segments for \"%s\": %s",
|
|
|
|
get_realpath(), strerror(errno));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2014-09-12 00:16:03 +02:00
|
|
|
sym_addr = lsi->resolve_symbol_address(s);
|
2015-07-26 16:37:09 +02:00
|
|
|
#if !defined(__LP64__)
|
|
|
|
if (protect_segments) {
|
|
|
|
if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
|
|
|
|
DL_ERR("can't unprotect loadable segments for \"%s\": %s",
|
|
|
|
get_realpath(), strerror(errno));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2013-10-05 02:01:33 +02:00
|
|
|
}
|
|
|
|
count_relocation(kRelocSymbol);
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (type) {
|
2015-01-09 08:30:15 +01:00
|
|
|
case R_GENERIC_JUMP_SLOT:
|
2013-10-10 16:19:31 +02:00
|
|
|
count_relocation(kRelocAbsolute);
|
2015-01-13 21:12:38 +01:00
|
|
|
MARK(rel->r_offset);
|
|
|
|
TRACE_TYPE(RELO, "RELO JMP_SLOT %16p <- %16p %s\n",
|
|
|
|
reinterpret_cast<void*>(reloc),
|
|
|
|
reinterpret_cast<void*>(sym_addr + addend), sym_name);
|
|
|
|
|
|
|
|
*reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
|
2013-10-10 16:19:31 +02:00
|
|
|
break;
|
2015-01-09 08:30:15 +01:00
|
|
|
case R_GENERIC_GLOB_DAT:
|
2013-10-10 16:19:31 +02:00
|
|
|
count_relocation(kRelocAbsolute);
|
2015-01-13 21:12:38 +01:00
|
|
|
MARK(rel->r_offset);
|
|
|
|
TRACE_TYPE(RELO, "RELO GLOB_DAT %16p <- %16p %s\n",
|
|
|
|
reinterpret_cast<void*>(reloc),
|
|
|
|
reinterpret_cast<void*>(sym_addr + addend), sym_name);
|
|
|
|
*reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
|
2013-10-10 16:19:31 +02:00
|
|
|
break;
|
2015-01-09 08:30:15 +01:00
|
|
|
case R_GENERIC_RELATIVE:
|
|
|
|
count_relocation(kRelocRelative);
|
2015-01-13 21:12:38 +01:00
|
|
|
MARK(rel->r_offset);
|
|
|
|
TRACE_TYPE(RELO, "RELO RELATIVE %16p <- %16p\n",
|
|
|
|
reinterpret_cast<void*>(reloc),
|
2015-02-05 01:05:30 +01:00
|
|
|
reinterpret_cast<void*>(load_bias + addend));
|
|
|
|
*reinterpret_cast<ElfW(Addr)*>(reloc) = (load_bias + addend);
|
2015-01-09 08:30:15 +01:00
|
|
|
break;
|
|
|
|
case R_GENERIC_IRELATIVE:
|
|
|
|
count_relocation(kRelocRelative);
|
2015-01-13 21:12:38 +01:00
|
|
|
MARK(rel->r_offset);
|
|
|
|
TRACE_TYPE(RELO, "RELO IRELATIVE %16p <- %16p\n",
|
|
|
|
reinterpret_cast<void*>(reloc),
|
2015-02-05 01:05:30 +01:00
|
|
|
reinterpret_cast<void*>(load_bias + addend));
|
2015-07-26 16:37:09 +02:00
|
|
|
{
|
|
|
|
#if !defined(__LP64__)
|
|
|
|
// When relocating dso with text_relocation .text segment is
|
|
|
|
// not executable. We need to restore elf flags for this
|
|
|
|
// particular call.
|
|
|
|
if (has_text_relocations) {
|
|
|
|
if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
|
|
|
|
DL_ERR("can't protect segments for \"%s\": %s",
|
|
|
|
get_realpath(), strerror(errno));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
ElfW(Addr) ifunc_addr = call_ifunc_resolver(load_bias + addend);
|
|
|
|
#if !defined(__LP64__)
|
|
|
|
// Unprotect it afterwards...
|
|
|
|
if (has_text_relocations) {
|
|
|
|
if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
|
|
|
|
DL_ERR("can't unprotect loadable segments for \"%s\": %s",
|
|
|
|
get_realpath(), strerror(errno));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
*reinterpret_cast<ElfW(Addr)*>(reloc) = ifunc_addr;
|
|
|
|
}
|
2015-01-09 08:30:15 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
#if defined(__aarch64__)
|
2014-09-12 18:43:13 +02:00
|
|
|
case R_AARCH64_ABS64:
|
2013-10-10 16:19:31 +02:00
|
|
|
count_relocation(kRelocAbsolute);
|
2015-01-13 21:12:38 +01:00
|
|
|
MARK(rel->r_offset);
|
2014-02-11 02:46:57 +01:00
|
|
|
TRACE_TYPE(RELO, "RELO ABS64 %16llx <- %16llx %s\n",
|
2015-10-15 22:26:03 +02:00
|
|
|
reloc, sym_addr + addend, sym_name);
|
|
|
|
*reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend;
|
2013-10-10 16:19:31 +02:00
|
|
|
break;
|
2014-09-12 18:43:13 +02:00
|
|
|
case R_AARCH64_ABS32:
|
2013-10-10 16:19:31 +02:00
|
|
|
count_relocation(kRelocAbsolute);
|
2015-01-13 21:12:38 +01:00
|
|
|
MARK(rel->r_offset);
|
2014-02-11 02:46:57 +01:00
|
|
|
TRACE_TYPE(RELO, "RELO ABS32 %16llx <- %16llx %s\n",
|
2015-10-15 22:26:03 +02:00
|
|
|
reloc, sym_addr + addend, sym_name);
|
2015-03-31 03:43:38 +02:00
|
|
|
{
|
|
|
|
const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT32_MIN);
|
|
|
|
const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT32_MAX);
|
2015-10-15 22:26:03 +02:00
|
|
|
if ((min_value <= (sym_addr + addend)) &&
|
|
|
|
((sym_addr + addend) <= max_value)) {
|
|
|
|
*reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend;
|
2015-03-31 03:43:38 +02:00
|
|
|
} else {
|
|
|
|
DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
|
2015-10-15 22:26:03 +02:00
|
|
|
sym_addr + addend, min_value, max_value);
|
2015-03-31 03:43:38 +02:00
|
|
|
return false;
|
|
|
|
}
|
2013-10-10 16:19:31 +02:00
|
|
|
}
|
|
|
|
break;
|
2014-09-12 18:43:13 +02:00
|
|
|
case R_AARCH64_ABS16:
|
2013-10-10 16:19:31 +02:00
|
|
|
count_relocation(kRelocAbsolute);
|
2015-01-13 21:12:38 +01:00
|
|
|
MARK(rel->r_offset);
|
2014-02-11 02:46:57 +01:00
|
|
|
TRACE_TYPE(RELO, "RELO ABS16 %16llx <- %16llx %s\n",
|
2015-10-15 22:26:03 +02:00
|
|
|
reloc, sym_addr + addend, sym_name);
|
2015-03-31 03:43:38 +02:00
|
|
|
{
|
|
|
|
const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN);
|
|
|
|
const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT16_MAX);
|
2015-10-15 22:26:03 +02:00
|
|
|
if ((min_value <= (sym_addr + addend)) &&
|
|
|
|
((sym_addr + addend) <= max_value)) {
|
|
|
|
*reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
|
2015-03-31 03:43:38 +02:00
|
|
|
} else {
|
|
|
|
DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
|
2015-10-15 22:26:03 +02:00
|
|
|
sym_addr + addend, min_value, max_value);
|
2015-03-31 03:43:38 +02:00
|
|
|
return false;
|
|
|
|
}
|
2013-10-10 16:19:31 +02:00
|
|
|
}
|
|
|
|
break;
|
2014-09-12 18:43:13 +02:00
|
|
|
case R_AARCH64_PREL64:
|
2013-10-10 16:19:31 +02:00
|
|
|
count_relocation(kRelocRelative);
|
2015-01-13 21:12:38 +01:00
|
|
|
MARK(rel->r_offset);
|
2014-02-11 02:46:57 +01:00
|
|
|
TRACE_TYPE(RELO, "RELO REL64 %16llx <- %16llx - %16llx %s\n",
|
2015-10-15 22:26:03 +02:00
|
|
|
reloc, sym_addr + addend, rel->r_offset, sym_name);
|
|
|
|
*reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset;
|
2013-10-10 16:19:31 +02:00
|
|
|
break;
|
2014-09-12 18:43:13 +02:00
|
|
|
case R_AARCH64_PREL32:
|
2013-10-10 16:19:31 +02:00
|
|
|
count_relocation(kRelocRelative);
|
2015-01-13 21:12:38 +01:00
|
|
|
MARK(rel->r_offset);
|
2014-02-11 02:46:57 +01:00
|
|
|
TRACE_TYPE(RELO, "RELO REL32 %16llx <- %16llx - %16llx %s\n",
|
2015-10-15 22:26:03 +02:00
|
|
|
reloc, sym_addr + addend, rel->r_offset, sym_name);
|
2015-03-31 03:43:38 +02:00
|
|
|
{
|
|
|
|
const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT32_MIN);
|
|
|
|
const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT32_MAX);
|
2015-10-15 22:26:03 +02:00
|
|
|
if ((min_value <= (sym_addr + addend - rel->r_offset)) &&
|
|
|
|
((sym_addr + addend - rel->r_offset) <= max_value)) {
|
|
|
|
*reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset;
|
2015-03-31 03:43:38 +02:00
|
|
|
} else {
|
|
|
|
DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
|
2015-10-15 22:26:03 +02:00
|
|
|
sym_addr + addend - rel->r_offset, min_value, max_value);
|
2015-03-31 03:43:38 +02:00
|
|
|
return false;
|
|
|
|
}
|
2013-10-10 16:19:31 +02:00
|
|
|
}
|
|
|
|
break;
|
2014-09-12 18:43:13 +02:00
|
|
|
case R_AARCH64_PREL16:
|
2013-10-10 16:19:31 +02:00
|
|
|
count_relocation(kRelocRelative);
|
2015-01-13 21:12:38 +01:00
|
|
|
MARK(rel->r_offset);
|
2014-02-11 02:46:57 +01:00
|
|
|
TRACE_TYPE(RELO, "RELO REL16 %16llx <- %16llx - %16llx %s\n",
|
2015-10-15 22:26:03 +02:00
|
|
|
reloc, sym_addr + addend, rel->r_offset, sym_name);
|
2015-03-31 03:43:38 +02:00
|
|
|
{
|
|
|
|
const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN);
|
|
|
|
const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT16_MAX);
|
2015-10-15 22:26:03 +02:00
|
|
|
if ((min_value <= (sym_addr + addend - rel->r_offset)) &&
|
|
|
|
((sym_addr + addend - rel->r_offset) <= max_value)) {
|
|
|
|
*reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset;
|
2015-03-31 03:43:38 +02:00
|
|
|
} else {
|
|
|
|
DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
|
2015-10-15 22:26:03 +02:00
|
|
|
sym_addr + addend - rel->r_offset, min_value, max_value);
|
2015-03-31 03:43:38 +02:00
|
|
|
return false;
|
|
|
|
}
|
2013-10-10 16:19:31 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2014-09-12 18:43:13 +02:00
|
|
|
case R_AARCH64_COPY:
|
2014-07-03 21:04:31 +02:00
|
|
|
/*
|
|
|
|
* ET_EXEC is not supported so this should not happen.
|
|
|
|
*
|
2015-03-31 20:14:03 +02:00
|
|
|
* http://infocenter.arm.com/help/topic/com.arm.doc.ihi0056b/IHI0056B_aaelf64.pdf
|
2014-07-03 21:04:31 +02:00
|
|
|
*
|
2015-03-31 20:14:03 +02:00
|
|
|
* Section 4.6.11 "Dynamic relocations"
|
2014-07-03 21:04:31 +02:00
|
|
|
* R_AARCH64_COPY may only appear in executable objects where e_type is
|
|
|
|
* set to ET_EXEC.
|
|
|
|
*/
|
2015-05-07 19:48:00 +02:00
|
|
|
DL_ERR("%s R_AARCH64_COPY relocations are not supported", get_realpath());
|
2015-01-14 20:36:38 +01:00
|
|
|
return false;
|
2014-09-12 18:43:13 +02:00
|
|
|
case R_AARCH64_TLS_TPREL64:
|
2014-02-11 02:46:57 +01:00
|
|
|
TRACE_TYPE(RELO, "RELO TLS_TPREL64 *** %16llx <- %16llx - %16llx\n",
|
2015-01-13 21:12:38 +01:00
|
|
|
reloc, (sym_addr + addend), rel->r_offset);
|
2013-10-10 16:19:31 +02:00
|
|
|
break;
|
2014-09-12 18:43:13 +02:00
|
|
|
case R_AARCH64_TLS_DTPREL32:
|
2014-02-11 02:46:57 +01:00
|
|
|
TRACE_TYPE(RELO, "RELO TLS_DTPREL32 *** %16llx <- %16llx - %16llx\n",
|
2015-01-13 21:12:38 +01:00
|
|
|
reloc, (sym_addr + addend), rel->r_offset);
|
2013-10-10 16:19:31 +02:00
|
|
|
break;
|
|
|
|
#elif defined(__x86_64__)
|
2014-09-12 18:43:13 +02:00
|
|
|
case R_X86_64_32:
|
|
|
|
count_relocation(kRelocRelative);
|
2015-01-13 21:12:38 +01:00
|
|
|
MARK(rel->r_offset);
|
2014-09-12 18:43:13 +02:00
|
|
|
TRACE_TYPE(RELO, "RELO R_X86_64_32 %08zx <- +%08zx %s", static_cast<size_t>(reloc),
|
|
|
|
static_cast<size_t>(sym_addr), sym_name);
|
2015-11-18 02:18:59 +01:00
|
|
|
*reinterpret_cast<Elf32_Addr*>(reloc) = sym_addr + addend;
|
2014-09-12 18:43:13 +02:00
|
|
|
break;
|
|
|
|
case R_X86_64_64:
|
|
|
|
count_relocation(kRelocRelative);
|
2015-01-13 21:12:38 +01:00
|
|
|
MARK(rel->r_offset);
|
2014-09-12 18:43:13 +02:00
|
|
|
TRACE_TYPE(RELO, "RELO R_X86_64_64 %08zx <- +%08zx %s", static_cast<size_t>(reloc),
|
|
|
|
static_cast<size_t>(sym_addr), sym_name);
|
2015-11-18 02:18:59 +01:00
|
|
|
*reinterpret_cast<Elf64_Addr*>(reloc) = sym_addr + addend;
|
2014-09-12 18:43:13 +02:00
|
|
|
break;
|
|
|
|
case R_X86_64_PC32:
|
|
|
|
count_relocation(kRelocRelative);
|
2015-01-13 21:12:38 +01:00
|
|
|
MARK(rel->r_offset);
|
2014-09-12 18:43:13 +02:00
|
|
|
TRACE_TYPE(RELO, "RELO R_X86_64_PC32 %08zx <- +%08zx (%08zx - %08zx) %s",
|
|
|
|
static_cast<size_t>(reloc), static_cast<size_t>(sym_addr - reloc),
|
|
|
|
static_cast<size_t>(sym_addr), static_cast<size_t>(reloc), sym_name);
|
2015-11-18 02:18:59 +01:00
|
|
|
*reinterpret_cast<Elf32_Addr*>(reloc) = sym_addr + addend - reloc;
|
2014-09-12 18:43:13 +02:00
|
|
|
break;
|
2015-01-13 21:12:38 +01:00
|
|
|
#elif defined(__arm__)
|
2014-09-12 18:43:13 +02:00
|
|
|
case R_ARM_ABS32:
|
|
|
|
count_relocation(kRelocAbsolute);
|
|
|
|
MARK(rel->r_offset);
|
|
|
|
TRACE_TYPE(RELO, "RELO ABS %08x <- %08x %s", reloc, sym_addr, sym_name);
|
|
|
|
*reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
|
|
|
|
break;
|
|
|
|
case R_ARM_REL32:
|
|
|
|
count_relocation(kRelocRelative);
|
|
|
|
MARK(rel->r_offset);
|
|
|
|
TRACE_TYPE(RELO, "RELO REL32 %08x <- %08x - %08x %s",
|
|
|
|
reloc, sym_addr, rel->r_offset, sym_name);
|
|
|
|
*reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr - rel->r_offset;
|
|
|
|
break;
|
|
|
|
case R_ARM_COPY:
|
|
|
|
/*
|
|
|
|
* ET_EXEC is not supported so this should not happen.
|
|
|
|
*
|
|
|
|
* http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044d/IHI0044D_aaelf.pdf
|
|
|
|
*
|
2015-03-31 20:14:03 +02:00
|
|
|
* Section 4.6.1.10 "Dynamic relocations"
|
2014-09-12 18:43:13 +02:00
|
|
|
* R_ARM_COPY may only appear in executable objects where e_type is
|
|
|
|
* set to ET_EXEC.
|
|
|
|
*/
|
2015-05-07 19:48:00 +02:00
|
|
|
DL_ERR("%s R_ARM_COPY relocations are not supported", get_realpath());
|
2015-01-14 20:36:38 +01:00
|
|
|
return false;
|
2013-10-26 02:38:02 +02:00
|
|
|
#elif defined(__i386__)
|
2014-09-12 18:43:13 +02:00
|
|
|
case R_386_32:
|
|
|
|
count_relocation(kRelocRelative);
|
|
|
|
MARK(rel->r_offset);
|
|
|
|
TRACE_TYPE(RELO, "RELO R_386_32 %08x <- +%08x %s", reloc, sym_addr, sym_name);
|
|
|
|
*reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
|
|
|
|
break;
|
|
|
|
case R_386_PC32:
|
|
|
|
count_relocation(kRelocRelative);
|
|
|
|
MARK(rel->r_offset);
|
|
|
|
TRACE_TYPE(RELO, "RELO R_386_PC32 %08x <- +%08x (%08x - %08x) %s",
|
|
|
|
reloc, (sym_addr - reloc), sym_addr, reloc, sym_name);
|
|
|
|
*reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr - reloc);
|
|
|
|
break;
|
2013-10-26 02:38:02 +02:00
|
|
|
#endif
|
2014-09-12 18:43:13 +02:00
|
|
|
default:
|
|
|
|
DL_ERR("unknown reloc type %d @ %p (%zu)", type, rel, idx);
|
|
|
|
return false;
|
2012-07-31 21:07:22 +02:00
|
|
|
}
|
2014-09-12 18:43:13 +02:00
|
|
|
}
|
|
|
|
return true;
|
2012-07-31 21:07:22 +02:00
|
|
|
}
|
2015-01-14 20:36:38 +01:00
|
|
|
#endif // !defined(__mips__)
|
2012-07-31 21:07:22 +02:00
|
|
|
|
2016-08-04 20:50:36 +02:00
|
|
|
// An empty list of soinfos
|
2016-08-04 01:00:10 +02:00
|
|
|
static soinfo_list_t g_empty_list;
|
2014-05-09 18:10:14 +02:00
|
|
|
|
2014-11-13 18:39:20 +01:00
|
|
|
bool soinfo::prelink_image() {
|
2014-09-16 09:22:10 +02:00
|
|
|
/* Extract dynamic section */
|
|
|
|
ElfW(Word) dynamic_flags = 0;
|
|
|
|
phdr_table_get_dynamic_section(phdr, phnum, load_bias, &dynamic, &dynamic_flags);
|
2014-09-05 23:57:59 +02:00
|
|
|
|
2014-09-12 18:43:13 +02:00
|
|
|
/* We can't log anything until the linker is relocated */
|
2014-11-29 22:57:41 +01:00
|
|
|
bool relocating_linker = (flags_ & FLAG_LINKER) != 0;
|
2014-09-12 18:43:13 +02:00
|
|
|
if (!relocating_linker) {
|
2016-07-21 20:33:40 +02:00
|
|
|
INFO("[ Linking \"%s\" ]", get_realpath());
|
2014-11-29 22:57:41 +01:00
|
|
|
DEBUG("si->base = %p si->flags = 0x%08x", reinterpret_cast<void*>(base), flags_);
|
2014-09-12 18:43:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (dynamic == nullptr) {
|
2012-06-19 01:24:17 +02:00
|
|
|
if (!relocating_linker) {
|
2015-05-07 19:48:00 +02:00
|
|
|
DL_ERR("missing PT_DYNAMIC in \"%s\"", get_realpath());
|
2012-06-19 01:24:17 +02:00
|
|
|
}
|
2014-09-12 18:43:13 +02:00
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
if (!relocating_linker) {
|
|
|
|
DEBUG("dynamic = %p", dynamic);
|
2012-06-19 00:08:39 +02:00
|
|
|
}
|
2014-09-12 18:43:13 +02:00
|
|
|
}
|
2012-06-19 00:08:39 +02:00
|
|
|
|
2013-10-26 02:38:02 +02:00
|
|
|
#if defined(__arm__)
|
2014-09-12 18:43:13 +02:00
|
|
|
(void) phdr_table_get_arm_exidx(phdr, phnum, load_bias,
|
|
|
|
&ARM_exidx, &ARM_exidx_count);
|
2012-06-19 00:08:39 +02:00
|
|
|
#endif
|
|
|
|
|
2014-09-12 18:43:13 +02:00
|
|
|
// Extract useful information from dynamic section.
|
2015-03-18 04:06:36 +01:00
|
|
|
// Note that: "Except for the DT_NULL element at the end of the array,
|
|
|
|
// and the relative order of DT_NEEDED elements, entries may appear in any order."
|
|
|
|
//
|
|
|
|
// source: http://www.sco.com/developers/gabi/1998-04-29/ch5.dynamic.html
|
2014-09-12 18:43:13 +02:00
|
|
|
uint32_t needed_count = 0;
|
|
|
|
for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
|
|
|
|
DEBUG("d = %p, d[0](tag) = %p d[1](val) = %p",
|
|
|
|
d, reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
|
|
|
|
switch (d->d_tag) {
|
2014-09-17 00:51:25 +02:00
|
|
|
case DT_SONAME:
|
2015-03-18 04:06:36 +01:00
|
|
|
// this is parsed after we have strtab initialized (see below).
|
2014-09-17 00:51:25 +02:00
|
|
|
break;
|
2014-10-15 23:59:01 +02:00
|
|
|
|
2014-09-12 18:43:13 +02:00
|
|
|
case DT_HASH:
|
2014-11-13 18:39:20 +01:00
|
|
|
nbucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0];
|
|
|
|
nchain_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
|
|
|
|
bucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8);
|
|
|
|
chain_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8 + nbucket_ * 4);
|
2014-09-12 18:43:13 +02:00
|
|
|
break;
|
2014-10-15 23:59:01 +02:00
|
|
|
|
2014-11-10 04:27:20 +01:00
|
|
|
case DT_GNU_HASH:
|
2015-03-09 20:02:02 +01:00
|
|
|
gnu_nbucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0];
|
2014-11-10 04:27:20 +01:00
|
|
|
// skip symndx
|
2014-11-13 18:39:20 +01:00
|
|
|
gnu_maskwords_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[2];
|
|
|
|
gnu_shift2_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[3];
|
2014-11-10 04:27:20 +01:00
|
|
|
|
2014-11-13 18:39:20 +01:00
|
|
|
gnu_bloom_filter_ = reinterpret_cast<ElfW(Addr)*>(load_bias + d->d_un.d_ptr + 16);
|
2015-03-09 20:02:02 +01:00
|
|
|
gnu_bucket_ = reinterpret_cast<uint32_t*>(gnu_bloom_filter_ + gnu_maskwords_);
|
2014-11-10 04:27:20 +01:00
|
|
|
// amend chain for symndx = header[1]
|
2015-03-31 03:43:38 +02:00
|
|
|
gnu_chain_ = gnu_bucket_ + gnu_nbucket_ -
|
|
|
|
reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
|
2014-11-10 04:27:20 +01:00
|
|
|
|
2014-11-13 18:39:20 +01:00
|
|
|
if (!powerof2(gnu_maskwords_)) {
|
2015-03-31 03:43:38 +02:00
|
|
|
DL_ERR("invalid maskwords for gnu_hash = 0x%x, in \"%s\" expecting power to two",
|
2015-03-31 20:14:03 +02:00
|
|
|
gnu_maskwords_, get_realpath());
|
2014-11-10 04:27:20 +01:00
|
|
|
return false;
|
|
|
|
}
|
2014-11-13 18:39:20 +01:00
|
|
|
--gnu_maskwords_;
|
2014-11-10 04:27:20 +01:00
|
|
|
|
2014-11-29 22:57:41 +01:00
|
|
|
flags_ |= FLAG_GNU_HASH;
|
2014-11-10 04:27:20 +01:00
|
|
|
break;
|
|
|
|
|
2014-09-12 18:43:13 +02:00
|
|
|
case DT_STRTAB:
|
2014-11-13 18:39:20 +01:00
|
|
|
strtab_ = reinterpret_cast<const char*>(load_bias + d->d_un.d_ptr);
|
2014-09-12 18:43:13 +02:00
|
|
|
break;
|
2014-10-15 23:59:01 +02:00
|
|
|
|
2014-09-30 04:14:45 +02:00
|
|
|
case DT_STRSZ:
|
2014-11-13 18:39:20 +01:00
|
|
|
strtab_size_ = d->d_un.d_val;
|
2014-09-30 04:14:45 +02:00
|
|
|
break;
|
2014-10-15 23:59:01 +02:00
|
|
|
|
2014-09-12 18:43:13 +02:00
|
|
|
case DT_SYMTAB:
|
2014-11-13 18:39:20 +01:00
|
|
|
symtab_ = reinterpret_cast<ElfW(Sym)*>(load_bias + d->d_un.d_ptr);
|
2014-09-12 18:43:13 +02:00
|
|
|
break;
|
2014-10-15 23:59:01 +02:00
|
|
|
|
2014-09-17 00:51:25 +02:00
|
|
|
case DT_SYMENT:
|
|
|
|
if (d->d_un.d_val != sizeof(ElfW(Sym))) {
|
2015-03-31 20:14:03 +02:00
|
|
|
DL_ERR("invalid DT_SYMENT: %zd in \"%s\"",
|
|
|
|
static_cast<size_t>(d->d_un.d_val), get_realpath());
|
2014-09-17 00:51:25 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
break;
|
2014-10-15 23:59:01 +02:00
|
|
|
|
2014-09-12 18:43:13 +02:00
|
|
|
case DT_PLTREL:
|
2014-10-06 20:30:43 +02:00
|
|
|
#if defined(USE_RELA)
|
|
|
|
if (d->d_un.d_val != DT_RELA) {
|
2015-03-31 20:14:03 +02:00
|
|
|
DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_RELA", get_realpath());
|
2014-10-06 20:30:43 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
#else
|
2014-09-12 18:43:13 +02:00
|
|
|
if (d->d_un.d_val != DT_REL) {
|
2015-03-31 20:14:03 +02:00
|
|
|
DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_REL", get_realpath());
|
2014-09-12 18:43:13 +02:00
|
|
|
return false;
|
|
|
|
}
|
2013-10-05 02:01:33 +02:00
|
|
|
#endif
|
2014-10-06 20:30:43 +02:00
|
|
|
break;
|
2014-10-15 23:59:01 +02:00
|
|
|
|
2014-09-12 18:43:13 +02:00
|
|
|
case DT_JMPREL:
|
2013-10-26 02:38:02 +02:00
|
|
|
#if defined(USE_RELA)
|
2014-11-13 18:39:20 +01:00
|
|
|
plt_rela_ = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr);
|
2013-10-05 02:01:33 +02:00
|
|
|
#else
|
2014-11-13 18:39:20 +01:00
|
|
|
plt_rel_ = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
|
2013-10-05 02:01:33 +02:00
|
|
|
#endif
|
2014-09-12 18:43:13 +02:00
|
|
|
break;
|
2014-10-15 23:59:01 +02:00
|
|
|
|
2014-09-12 18:43:13 +02:00
|
|
|
case DT_PLTRELSZ:
|
2013-10-26 02:38:02 +02:00
|
|
|
#if defined(USE_RELA)
|
2014-11-13 18:39:20 +01:00
|
|
|
plt_rela_count_ = d->d_un.d_val / sizeof(ElfW(Rela));
|
2013-10-05 02:01:33 +02:00
|
|
|
#else
|
2014-11-13 18:39:20 +01:00
|
|
|
plt_rel_count_ = d->d_un.d_val / sizeof(ElfW(Rel));
|
2013-10-05 02:01:33 +02:00
|
|
|
#endif
|
2014-09-12 18:43:13 +02:00
|
|
|
break;
|
2014-10-15 23:59:01 +02:00
|
|
|
|
2014-09-12 18:43:13 +02:00
|
|
|
case DT_PLTGOT:
|
2014-09-17 00:51:25 +02:00
|
|
|
#if defined(__mips__)
|
2014-09-12 18:43:13 +02:00
|
|
|
// Used by mips and mips64.
|
2014-11-13 18:39:20 +01:00
|
|
|
plt_got_ = reinterpret_cast<ElfW(Addr)**>(load_bias + d->d_un.d_ptr);
|
2013-10-05 02:01:33 +02:00
|
|
|
#endif
|
2014-09-17 00:51:25 +02:00
|
|
|
// Ignore for other platforms... (because RTLD_LAZY is not supported)
|
|
|
|
break;
|
2014-10-15 23:59:01 +02:00
|
|
|
|
2014-09-12 18:43:13 +02:00
|
|
|
case DT_DEBUG:
|
|
|
|
// Set the DT_DEBUG entry to the address of _r_debug for GDB
|
|
|
|
// if the dynamic table is writable
|
2014-02-07 05:36:51 +01:00
|
|
|
// FIXME: not working currently for N64
|
|
|
|
// The flags for the LOAD and DYNAMIC program headers do not agree.
|
2014-09-06 01:42:53 +02:00
|
|
|
// The LOAD section containing the dynamic table has been mapped as
|
2014-02-07 05:36:51 +01:00
|
|
|
// read-only, but the DYNAMIC header claims it is writable.
|
|
|
|
#if !(defined(__mips__) && defined(__LP64__))
|
2014-09-12 18:43:13 +02:00
|
|
|
if ((dynamic_flags & PF_W) != 0) {
|
|
|
|
d->d_un.d_val = reinterpret_cast<uintptr_t>(&_r_debug);
|
|
|
|
}
|
2014-02-07 05:36:51 +01:00
|
|
|
#endif
|
2015-02-14 01:29:50 +01:00
|
|
|
break;
|
2013-10-26 02:38:02 +02:00
|
|
|
#if defined(USE_RELA)
|
2014-09-12 18:43:13 +02:00
|
|
|
case DT_RELA:
|
2014-11-13 18:39:20 +01:00
|
|
|
rela_ = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr);
|
2014-09-12 18:43:13 +02:00
|
|
|
break;
|
2014-10-15 23:59:01 +02:00
|
|
|
|
2014-09-12 18:43:13 +02:00
|
|
|
case DT_RELASZ:
|
2014-11-13 18:39:20 +01:00
|
|
|
rela_count_ = d->d_un.d_val / sizeof(ElfW(Rela));
|
2014-09-12 18:43:13 +02:00
|
|
|
break;
|
2014-10-15 23:59:01 +02:00
|
|
|
|
2015-02-05 01:05:30 +01:00
|
|
|
case DT_ANDROID_RELA:
|
|
|
|
android_relocs_ = reinterpret_cast<uint8_t*>(load_bias + d->d_un.d_ptr);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DT_ANDROID_RELASZ:
|
|
|
|
android_relocs_size_ = d->d_un.d_val;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DT_ANDROID_REL:
|
2015-03-31 20:14:03 +02:00
|
|
|
DL_ERR("unsupported DT_ANDROID_REL in \"%s\"", get_realpath());
|
2015-02-05 01:05:30 +01:00
|
|
|
return false;
|
|
|
|
|
|
|
|
case DT_ANDROID_RELSZ:
|
2015-03-31 20:14:03 +02:00
|
|
|
DL_ERR("unsupported DT_ANDROID_RELSZ in \"%s\"", get_realpath());
|
2015-02-05 01:05:30 +01:00
|
|
|
return false;
|
|
|
|
|
2014-09-17 00:51:25 +02:00
|
|
|
case DT_RELAENT:
|
|
|
|
if (d->d_un.d_val != sizeof(ElfW(Rela))) {
|
2014-09-17 08:34:20 +02:00
|
|
|
DL_ERR("invalid DT_RELAENT: %zd", static_cast<size_t>(d->d_un.d_val));
|
2014-09-17 00:51:25 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
break;
|
2014-10-15 23:59:01 +02:00
|
|
|
|
|
|
|
// ignored (see DT_RELCOUNT comments for details)
|
2014-09-17 00:51:25 +02:00
|
|
|
case DT_RELACOUNT:
|
|
|
|
break;
|
2014-10-15 23:59:01 +02:00
|
|
|
|
2014-09-12 18:43:13 +02:00
|
|
|
case DT_REL:
|
2015-03-31 20:14:03 +02:00
|
|
|
DL_ERR("unsupported DT_REL in \"%s\"", get_realpath());
|
2014-09-12 18:43:13 +02:00
|
|
|
return false;
|
2014-10-15 23:59:01 +02:00
|
|
|
|
2014-09-12 18:43:13 +02:00
|
|
|
case DT_RELSZ:
|
2015-03-31 20:14:03 +02:00
|
|
|
DL_ERR("unsupported DT_RELSZ in \"%s\"", get_realpath());
|
2014-09-12 18:43:13 +02:00
|
|
|
return false;
|
2015-02-05 01:05:30 +01:00
|
|
|
|
2013-10-05 02:01:33 +02:00
|
|
|
#else
|
2014-09-12 18:43:13 +02:00
|
|
|
case DT_REL:
|
2014-11-13 18:39:20 +01:00
|
|
|
rel_ = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
|
2014-09-12 18:43:13 +02:00
|
|
|
break;
|
2014-10-15 23:59:01 +02:00
|
|
|
|
2014-09-12 18:43:13 +02:00
|
|
|
case DT_RELSZ:
|
2014-11-13 18:39:20 +01:00
|
|
|
rel_count_ = d->d_un.d_val / sizeof(ElfW(Rel));
|
2014-09-12 18:43:13 +02:00
|
|
|
break;
|
2014-10-15 23:59:01 +02:00
|
|
|
|
2014-09-17 00:51:25 +02:00
|
|
|
case DT_RELENT:
|
|
|
|
if (d->d_un.d_val != sizeof(ElfW(Rel))) {
|
2014-09-17 08:34:20 +02:00
|
|
|
DL_ERR("invalid DT_RELENT: %zd", static_cast<size_t>(d->d_un.d_val));
|
2014-09-17 00:51:25 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
break;
|
2014-10-15 23:59:01 +02:00
|
|
|
|
2015-02-05 01:05:30 +01:00
|
|
|
case DT_ANDROID_REL:
|
|
|
|
android_relocs_ = reinterpret_cast<uint8_t*>(load_bias + d->d_un.d_ptr);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DT_ANDROID_RELSZ:
|
|
|
|
android_relocs_size_ = d->d_un.d_val;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DT_ANDROID_RELA:
|
2015-03-31 20:14:03 +02:00
|
|
|
DL_ERR("unsupported DT_ANDROID_RELA in \"%s\"", get_realpath());
|
2015-02-05 01:05:30 +01:00
|
|
|
return false;
|
|
|
|
|
|
|
|
case DT_ANDROID_RELASZ:
|
2015-03-31 20:14:03 +02:00
|
|
|
DL_ERR("unsupported DT_ANDROID_RELASZ in \"%s\"", get_realpath());
|
2015-02-05 01:05:30 +01:00
|
|
|
return false;
|
|
|
|
|
2014-10-15 23:59:01 +02:00
|
|
|
// "Indicates that all RELATIVE relocations have been concatenated together,
|
|
|
|
// and specifies the RELATIVE relocation count."
|
|
|
|
//
|
|
|
|
// TODO: Spec also mentions that this can be used to optimize relocation process;
|
|
|
|
// Not currently used by bionic linker - ignored.
|
2014-09-17 00:51:25 +02:00
|
|
|
case DT_RELCOUNT:
|
|
|
|
break;
|
2015-02-05 01:05:30 +01:00
|
|
|
|
2014-09-12 18:43:13 +02:00
|
|
|
case DT_RELA:
|
2015-03-31 20:14:03 +02:00
|
|
|
DL_ERR("unsupported DT_RELA in \"%s\"", get_realpath());
|
2014-09-12 18:43:13 +02:00
|
|
|
return false;
|
2015-02-05 01:05:30 +01:00
|
|
|
|
|
|
|
case DT_RELASZ:
|
2015-03-31 20:14:03 +02:00
|
|
|
DL_ERR("unsupported DT_RELASZ in \"%s\"", get_realpath());
|
2015-02-05 01:05:30 +01:00
|
|
|
return false;
|
|
|
|
|
2013-10-05 02:01:33 +02:00
|
|
|
#endif
|
2014-09-12 18:43:13 +02:00
|
|
|
case DT_INIT:
|
2016-07-21 00:33:07 +02:00
|
|
|
init_func_ = reinterpret_cast<linker_ctor_function_t>(load_bias + d->d_un.d_ptr);
|
2015-03-31 20:14:03 +02:00
|
|
|
DEBUG("%s constructors (DT_INIT) found at %p", get_realpath(), init_func_);
|
2014-09-12 18:43:13 +02:00
|
|
|
break;
|
2014-10-15 23:59:01 +02:00
|
|
|
|
2014-09-12 18:43:13 +02:00
|
|
|
case DT_FINI:
|
2016-07-21 00:33:07 +02:00
|
|
|
fini_func_ = reinterpret_cast<linker_dtor_function_t>(load_bias + d->d_un.d_ptr);
|
2015-03-31 20:14:03 +02:00
|
|
|
DEBUG("%s destructors (DT_FINI) found at %p", get_realpath(), fini_func_);
|
2014-09-12 18:43:13 +02:00
|
|
|
break;
|
2014-10-15 23:59:01 +02:00
|
|
|
|
2014-09-12 18:43:13 +02:00
|
|
|
case DT_INIT_ARRAY:
|
2016-07-21 00:33:07 +02:00
|
|
|
init_array_ = reinterpret_cast<linker_ctor_function_t*>(load_bias + d->d_un.d_ptr);
|
2015-03-31 20:14:03 +02:00
|
|
|
DEBUG("%s constructors (DT_INIT_ARRAY) found at %p", get_realpath(), init_array_);
|
2014-09-12 18:43:13 +02:00
|
|
|
break;
|
2014-10-15 23:59:01 +02:00
|
|
|
|
2014-09-12 18:43:13 +02:00
|
|
|
case DT_INIT_ARRAYSZ:
|
2015-01-23 01:04:25 +01:00
|
|
|
init_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
|
2014-09-12 18:43:13 +02:00
|
|
|
break;
|
2014-10-15 23:59:01 +02:00
|
|
|
|
2014-09-12 18:43:13 +02:00
|
|
|
case DT_FINI_ARRAY:
|
2016-07-21 00:33:07 +02:00
|
|
|
fini_array_ = reinterpret_cast<linker_dtor_function_t*>(load_bias + d->d_un.d_ptr);
|
2015-03-31 20:14:03 +02:00
|
|
|
DEBUG("%s destructors (DT_FINI_ARRAY) found at %p", get_realpath(), fini_array_);
|
2014-09-12 18:43:13 +02:00
|
|
|
break;
|
2014-10-15 23:59:01 +02:00
|
|
|
|
2014-09-12 18:43:13 +02:00
|
|
|
case DT_FINI_ARRAYSZ:
|
2015-01-23 01:04:25 +01:00
|
|
|
fini_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
|
2014-09-12 18:43:13 +02:00
|
|
|
break;
|
2014-10-15 23:59:01 +02:00
|
|
|
|
2014-09-12 18:43:13 +02:00
|
|
|
case DT_PREINIT_ARRAY:
|
2016-07-21 00:33:07 +02:00
|
|
|
preinit_array_ = reinterpret_cast<linker_ctor_function_t*>(load_bias + d->d_un.d_ptr);
|
2015-03-31 20:14:03 +02:00
|
|
|
DEBUG("%s constructors (DT_PREINIT_ARRAY) found at %p", get_realpath(), preinit_array_);
|
2014-09-12 18:43:13 +02:00
|
|
|
break;
|
2014-10-15 23:59:01 +02:00
|
|
|
|
2014-09-12 18:43:13 +02:00
|
|
|
case DT_PREINIT_ARRAYSZ:
|
2015-01-23 01:04:25 +01:00
|
|
|
preinit_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
|
2014-09-12 18:43:13 +02:00
|
|
|
break;
|
2014-10-15 23:59:01 +02:00
|
|
|
|
2014-09-12 18:43:13 +02:00
|
|
|
case DT_TEXTREL:
|
2015-04-01 23:18:48 +02:00
|
|
|
#if defined(__LP64__)
|
2016-10-19 20:00:28 +02:00
|
|
|
DL_ERR("\"%s\" has text relocations", get_realpath());
|
2014-09-12 18:43:13 +02:00
|
|
|
return false;
|
2015-04-01 23:18:48 +02:00
|
|
|
#else
|
|
|
|
has_text_relocations = true;
|
|
|
|
break;
|
|
|
|
#endif
|
2014-10-15 23:59:01 +02:00
|
|
|
|
2014-09-12 18:43:13 +02:00
|
|
|
case DT_SYMBOLIC:
|
2014-09-29 21:10:36 +02:00
|
|
|
has_DT_SYMBOLIC = true;
|
2014-09-12 18:43:13 +02:00
|
|
|
break;
|
2014-10-15 23:59:01 +02:00
|
|
|
|
2014-09-12 18:43:13 +02:00
|
|
|
case DT_NEEDED:
|
|
|
|
++needed_count;
|
|
|
|
break;
|
2014-10-15 23:59:01 +02:00
|
|
|
|
2014-09-12 18:43:13 +02:00
|
|
|
case DT_FLAGS:
|
|
|
|
if (d->d_un.d_val & DF_TEXTREL) {
|
2015-04-01 23:18:48 +02:00
|
|
|
#if defined(__LP64__)
|
2016-10-19 20:00:28 +02:00
|
|
|
DL_ERR("\"%s\" has text relocations", get_realpath());
|
2014-09-12 18:43:13 +02:00
|
|
|
return false;
|
2015-04-01 23:18:48 +02:00
|
|
|
#else
|
|
|
|
has_text_relocations = true;
|
|
|
|
#endif
|
2014-09-12 18:43:13 +02:00
|
|
|
}
|
2014-09-29 21:10:36 +02:00
|
|
|
if (d->d_un.d_val & DF_SYMBOLIC) {
|
|
|
|
has_DT_SYMBOLIC = true;
|
|
|
|
}
|
2014-09-12 18:43:13 +02:00
|
|
|
break;
|
2014-10-15 23:59:01 +02:00
|
|
|
|
2014-09-30 04:14:45 +02:00
|
|
|
case DT_FLAGS_1:
|
2014-08-28 23:12:12 +02:00
|
|
|
set_dt_flags_1(d->d_un.d_val);
|
2014-09-30 04:14:45 +02:00
|
|
|
|
2014-08-28 23:12:12 +02:00
|
|
|
if ((d->d_un.d_val & ~SUPPORTED_DT_FLAGS_1) != 0) {
|
2016-10-19 20:00:28 +02:00
|
|
|
DL_WARN("\"%s\" has unsupported flags DT_FLAGS_1=%p", get_realpath(), reinterpret_cast<void*>(d->d_un.d_val));
|
2014-09-30 04:14:45 +02:00
|
|
|
}
|
|
|
|
break;
|
2013-10-26 02:38:02 +02:00
|
|
|
#if defined(__mips__)
|
2014-09-12 18:43:13 +02:00
|
|
|
case DT_MIPS_RLD_MAP:
|
|
|
|
// Set the DT_MIPS_RLD_MAP entry to the address of _r_debug for GDB.
|
|
|
|
{
|
|
|
|
r_debug** dp = reinterpret_cast<r_debug**>(load_bias + d->d_un.d_ptr);
|
|
|
|
*dp = &_r_debug;
|
|
|
|
}
|
|
|
|
break;
|
2016-04-06 13:39:17 +02:00
|
|
|
case DT_MIPS_RLD_MAP_REL:
|
|
|
|
// Set the DT_MIPS_RLD_MAP_REL entry to the address of _r_debug for GDB.
|
2014-12-19 04:12:19 +01:00
|
|
|
{
|
2015-03-31 03:43:38 +02:00
|
|
|
r_debug** dp = reinterpret_cast<r_debug**>(
|
|
|
|
reinterpret_cast<ElfW(Addr)>(d) + d->d_un.d_val);
|
2014-12-19 04:12:19 +01:00
|
|
|
*dp = &_r_debug;
|
|
|
|
}
|
|
|
|
break;
|
2014-10-15 23:59:01 +02:00
|
|
|
|
2014-09-12 18:43:13 +02:00
|
|
|
case DT_MIPS_RLD_VERSION:
|
|
|
|
case DT_MIPS_FLAGS:
|
|
|
|
case DT_MIPS_BASE_ADDRESS:
|
|
|
|
case DT_MIPS_UNREFEXTNO:
|
|
|
|
break;
|
2012-07-31 21:07:22 +02:00
|
|
|
|
2014-09-12 18:43:13 +02:00
|
|
|
case DT_MIPS_SYMTABNO:
|
2014-11-13 18:39:20 +01:00
|
|
|
mips_symtabno_ = d->d_un.d_val;
|
2014-09-12 18:43:13 +02:00
|
|
|
break;
|
2012-07-31 21:07:22 +02:00
|
|
|
|
2014-09-12 18:43:13 +02:00
|
|
|
case DT_MIPS_LOCAL_GOTNO:
|
2014-11-13 18:39:20 +01:00
|
|
|
mips_local_gotno_ = d->d_un.d_val;
|
2014-09-12 18:43:13 +02:00
|
|
|
break;
|
2012-07-31 21:07:22 +02:00
|
|
|
|
2014-09-12 18:43:13 +02:00
|
|
|
case DT_MIPS_GOTSYM:
|
2014-11-13 18:39:20 +01:00
|
|
|
mips_gotsym_ = d->d_un.d_val;
|
2014-09-12 18:43:13 +02:00
|
|
|
break;
|
2013-10-26 02:38:02 +02:00
|
|
|
#endif
|
2014-10-15 23:59:01 +02:00
|
|
|
// Ignored: "Its use has been superseded by the DF_BIND_NOW flag"
|
|
|
|
case DT_BIND_NOW:
|
|
|
|
break;
|
|
|
|
|
2014-10-06 20:30:43 +02:00
|
|
|
case DT_VERSYM:
|
2015-04-09 22:42:33 +02:00
|
|
|
versym_ = reinterpret_cast<ElfW(Versym)*>(load_bias + d->d_un.d_ptr);
|
|
|
|
break;
|
|
|
|
|
2014-10-06 20:30:43 +02:00
|
|
|
case DT_VERDEF:
|
2015-04-09 22:42:33 +02:00
|
|
|
verdef_ptr_ = load_bias + d->d_un.d_ptr;
|
|
|
|
break;
|
2014-10-06 20:30:43 +02:00
|
|
|
case DT_VERDEFNUM:
|
2015-04-09 22:42:33 +02:00
|
|
|
verdef_cnt_ = d->d_un.d_val;
|
|
|
|
break;
|
|
|
|
|
2014-12-02 13:32:25 +01:00
|
|
|
case DT_VERNEED:
|
2015-04-09 22:42:33 +02:00
|
|
|
verneed_ptr_ = load_bias + d->d_un.d_ptr;
|
|
|
|
break;
|
|
|
|
|
2014-12-02 13:32:25 +01:00
|
|
|
case DT_VERNEEDNUM:
|
2015-04-09 22:42:33 +02:00
|
|
|
verneed_cnt_ = d->d_un.d_val;
|
2014-10-06 20:30:43 +02:00
|
|
|
break;
|
2012-07-31 21:07:22 +02:00
|
|
|
|
2015-06-10 22:38:39 +02:00
|
|
|
case DT_RUNPATH:
|
|
|
|
// this is parsed after we have strtab initialized (see below).
|
|
|
|
break;
|
|
|
|
|
2014-09-12 18:43:13 +02:00
|
|
|
default:
|
2014-09-16 23:31:06 +02:00
|
|
|
if (!relocating_linker) {
|
2016-10-19 20:00:28 +02:00
|
|
|
DL_WARN("\"%s\" unused DT entry: type %p arg %p", get_realpath(),
|
2014-09-16 23:31:06 +02:00
|
|
|
reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
|
|
|
|
}
|
2014-09-12 18:43:13 +02:00
|
|
|
break;
|
2009-03-04 04:28:35 +01:00
|
|
|
}
|
2014-09-12 18:43:13 +02:00
|
|
|
}
|
2009-03-04 04:28:35 +01:00
|
|
|
|
2015-06-02 01:29:14 +02:00
|
|
|
#if defined(__mips__) && !defined(__LP64__)
|
|
|
|
if (!mips_check_and_adjust_fp_modes()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-09-12 18:43:13 +02:00
|
|
|
DEBUG("si->base = %p, si->strtab = %p, si->symtab = %p",
|
2014-11-13 18:39:20 +01:00
|
|
|
reinterpret_cast<void*>(base), strtab_, symtab_);
|
2009-03-04 04:28:35 +01:00
|
|
|
|
2014-09-12 18:43:13 +02:00
|
|
|
// Sanity checks.
|
|
|
|
if (relocating_linker && needed_count != 0) {
|
|
|
|
DL_ERR("linker cannot have DT_NEEDED dependencies on other libraries");
|
|
|
|
return false;
|
|
|
|
}
|
2015-03-09 20:02:02 +01:00
|
|
|
if (nbucket_ == 0 && gnu_nbucket_ == 0) {
|
2015-03-31 20:14:03 +02:00
|
|
|
DL_ERR("empty/missing DT_HASH/DT_GNU_HASH in \"%s\" "
|
2015-05-07 19:48:00 +02:00
|
|
|
"(new hash type from the future?)", get_realpath());
|
2014-09-12 18:43:13 +02:00
|
|
|
return false;
|
|
|
|
}
|
2014-11-13 18:39:20 +01:00
|
|
|
if (strtab_ == 0) {
|
2015-05-07 19:48:00 +02:00
|
|
|
DL_ERR("empty/missing DT_STRTAB in \"%s\"", get_realpath());
|
2014-09-12 18:43:13 +02:00
|
|
|
return false;
|
|
|
|
}
|
2014-11-13 18:39:20 +01:00
|
|
|
if (symtab_ == 0) {
|
2015-05-07 19:48:00 +02:00
|
|
|
DL_ERR("empty/missing DT_SYMTAB in \"%s\"", get_realpath());
|
2014-09-12 18:43:13 +02:00
|
|
|
return false;
|
|
|
|
}
|
2015-06-02 22:28:06 +02:00
|
|
|
|
2015-06-08 19:41:33 +02:00
|
|
|
// second pass - parse entries relying on strtab
|
|
|
|
for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
|
2015-06-10 22:38:39 +02:00
|
|
|
switch (d->d_tag) {
|
|
|
|
case DT_SONAME:
|
2015-10-15 21:07:25 +02:00
|
|
|
set_soname(get_string(d->d_un.d_val));
|
2015-06-10 22:38:39 +02:00
|
|
|
break;
|
|
|
|
case DT_RUNPATH:
|
|
|
|
set_dt_runpath(get_string(d->d_un.d_val));
|
|
|
|
break;
|
2015-06-08 19:41:33 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-02 22:28:06 +02:00
|
|
|
// Before M release linker was using basename in place of soname.
|
2015-06-03 02:36:54 +02:00
|
|
|
// In the case when dt_soname is absent some apps stop working
|
2015-06-02 22:28:06 +02:00
|
|
|
// because they can't find dt_needed library by soname.
|
|
|
|
// This workaround should keep them working. (applies only
|
2016-11-16 20:35:43 +01:00
|
|
|
// for apps targeting sdk version < M). Make an exception for
|
2015-06-03 02:36:54 +02:00
|
|
|
// the main executable and linker; they do not need to have dt_soname
|
2016-09-09 19:00:39 +02:00
|
|
|
if (soname_ == nullptr &&
|
|
|
|
this != solist_get_somain() &&
|
|
|
|
(flags_ & FLAG_LINKER) == 0 &&
|
2016-11-16 20:35:43 +01:00
|
|
|
get_application_target_sdk_version() < __ANDROID_API_M__) {
|
2015-06-02 22:28:06 +02:00
|
|
|
soname_ = basename(realpath_.c_str());
|
|
|
|
DL_WARN("%s: is missing DT_SONAME will use basename as a replacement: \"%s\"",
|
|
|
|
get_realpath(), soname_);
|
2016-07-21 20:33:40 +02:00
|
|
|
// Don't call add_dlwarning because a missing DT_SONAME isn't important enough to show in the UI
|
2015-06-02 22:28:06 +02:00
|
|
|
}
|
2014-09-12 18:43:13 +02:00
|
|
|
return true;
|
2014-09-06 01:42:53 +02:00
|
|
|
}
|
2009-03-04 04:28:35 +01:00
|
|
|
|
2015-02-05 01:05:30 +01:00
|
|
|
bool soinfo::link_image(const soinfo_list_t& global_group, const soinfo_list_t& local_group,
|
|
|
|
const android_dlextinfo* extinfo) {
|
2009-03-04 04:28:35 +01:00
|
|
|
|
2014-11-29 22:57:41 +01:00
|
|
|
local_group_root_ = local_group.front();
|
|
|
|
if (local_group_root_ == nullptr) {
|
|
|
|
local_group_root_ = this;
|
|
|
|
}
|
|
|
|
|
2015-06-03 02:36:54 +02:00
|
|
|
if ((flags_ & FLAG_LINKER) == 0 && local_group_root_ == this) {
|
|
|
|
target_sdk_version_ = get_application_target_sdk_version();
|
|
|
|
}
|
|
|
|
|
2015-05-01 04:49:19 +02:00
|
|
|
VersionTracker version_tracker;
|
|
|
|
|
|
|
|
if (!version_tracker.init(this)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-04-01 23:18:48 +02:00
|
|
|
#if !defined(__LP64__)
|
|
|
|
if (has_text_relocations) {
|
2016-11-16 20:35:43 +01:00
|
|
|
// Fail if app is targeting M or above.
|
|
|
|
if (get_application_target_sdk_version() >= __ANDROID_API_M__) {
|
2016-10-19 20:00:28 +02:00
|
|
|
DL_ERR_AND_LOG("\"%s\" has text relocations", get_realpath());
|
2015-06-13 00:00:31 +02:00
|
|
|
return false;
|
|
|
|
}
|
2015-04-01 23:18:48 +02:00
|
|
|
// Make segments writable to allow text relocations to work properly. We will later call
|
2015-10-01 23:02:19 +02:00
|
|
|
// phdr_table_protect_segments() after all of them are applied.
|
2016-10-19 20:00:28 +02:00
|
|
|
DL_WARN("\"%s\" has text relocations. This is wasting memory and prevents "
|
2015-05-07 19:48:00 +02:00
|
|
|
"security hardening. Please fix.", get_realpath());
|
2016-07-21 20:33:40 +02:00
|
|
|
add_dlwarning(get_realpath(), "text relocations");
|
2015-04-01 23:18:48 +02:00
|
|
|
if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
|
|
|
|
DL_ERR("can't unprotect loadable segments for \"%s\": %s",
|
2015-05-07 19:48:00 +02:00
|
|
|
get_realpath(), strerror(errno));
|
2015-04-01 23:18:48 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2015-02-05 01:05:30 +01:00
|
|
|
if (android_relocs_ != nullptr) {
|
|
|
|
// check signature
|
|
|
|
if (android_relocs_size_ > 3 &&
|
|
|
|
android_relocs_[0] == 'A' &&
|
|
|
|
android_relocs_[1] == 'P' &&
|
2015-04-22 22:10:04 +02:00
|
|
|
android_relocs_[2] == 'S' &&
|
2015-02-05 01:05:30 +01:00
|
|
|
android_relocs_[3] == '2') {
|
2015-05-07 19:48:00 +02:00
|
|
|
DEBUG("[ android relocating %s ]", get_realpath());
|
2015-02-05 01:05:30 +01:00
|
|
|
|
|
|
|
bool relocated = false;
|
|
|
|
const uint8_t* packed_relocs = android_relocs_ + 4;
|
|
|
|
const size_t packed_relocs_size = android_relocs_size_ - 4;
|
|
|
|
|
2015-04-22 22:10:04 +02:00
|
|
|
relocated = relocate(
|
2015-05-01 04:49:19 +02:00
|
|
|
version_tracker,
|
2015-04-22 22:10:04 +02:00
|
|
|
packed_reloc_iterator<sleb128_decoder>(
|
|
|
|
sleb128_decoder(packed_relocs, packed_relocs_size)),
|
|
|
|
global_group, local_group);
|
2015-02-05 01:05:30 +01:00
|
|
|
|
|
|
|
if (!relocated) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
DL_ERR("bad android relocation header.");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-26 02:38:02 +02:00
|
|
|
#if defined(USE_RELA)
|
2014-11-13 18:39:20 +01:00
|
|
|
if (rela_ != nullptr) {
|
2015-05-07 19:48:00 +02:00
|
|
|
DEBUG("[ relocating %s ]", get_realpath());
|
2015-05-01 04:49:19 +02:00
|
|
|
if (!relocate(version_tracker,
|
|
|
|
plain_reloc_iterator(rela_, rela_count_), global_group, local_group)) {
|
2014-09-12 18:43:13 +02:00
|
|
|
return false;
|
2013-10-05 02:01:33 +02:00
|
|
|
}
|
2014-09-12 18:43:13 +02:00
|
|
|
}
|
2014-11-13 18:39:20 +01:00
|
|
|
if (plt_rela_ != nullptr) {
|
2015-05-07 19:48:00 +02:00
|
|
|
DEBUG("[ relocating %s plt ]", get_realpath());
|
2015-05-01 04:49:19 +02:00
|
|
|
if (!relocate(version_tracker,
|
|
|
|
plain_reloc_iterator(plt_rela_, plt_rela_count_), global_group, local_group)) {
|
2014-09-12 18:43:13 +02:00
|
|
|
return false;
|
2009-03-04 04:28:35 +01:00
|
|
|
}
|
2014-09-12 18:43:13 +02:00
|
|
|
}
|
2014-09-12 00:16:03 +02:00
|
|
|
#else
|
2014-11-13 18:39:20 +01:00
|
|
|
if (rel_ != nullptr) {
|
2015-05-07 19:48:00 +02:00
|
|
|
DEBUG("[ relocating %s ]", get_realpath());
|
2015-05-01 04:49:19 +02:00
|
|
|
if (!relocate(version_tracker,
|
|
|
|
plain_reloc_iterator(rel_, rel_count_), global_group, local_group)) {
|
2014-09-12 18:43:13 +02:00
|
|
|
return false;
|
2009-03-04 04:28:35 +01:00
|
|
|
}
|
2014-09-12 18:43:13 +02:00
|
|
|
}
|
2014-11-13 18:39:20 +01:00
|
|
|
if (plt_rel_ != nullptr) {
|
2015-05-07 19:48:00 +02:00
|
|
|
DEBUG("[ relocating %s plt ]", get_realpath());
|
2015-05-01 04:49:19 +02:00
|
|
|
if (!relocate(version_tracker,
|
|
|
|
plain_reloc_iterator(plt_rel_, plt_rel_count_), global_group, local_group)) {
|
2014-09-12 18:43:13 +02:00
|
|
|
return false;
|
2014-07-23 20:22:25 +02:00
|
|
|
}
|
2014-09-12 18:43:13 +02:00
|
|
|
}
|
2014-09-12 00:16:03 +02:00
|
|
|
#endif
|
2014-07-23 20:22:25 +02:00
|
|
|
|
2013-10-26 02:38:02 +02:00
|
|
|
#if defined(__mips__)
|
2015-05-01 05:17:03 +02:00
|
|
|
if (!mips_relocate_got(version_tracker, global_group, local_group)) {
|
2014-09-12 18:43:13 +02:00
|
|
|
return false;
|
|
|
|
}
|
2012-07-31 21:07:22 +02:00
|
|
|
#endif
|
|
|
|
|
2015-05-07 19:48:00 +02:00
|
|
|
DEBUG("[ finished linking %s ]", get_realpath());
|
2009-03-04 04:28:35 +01:00
|
|
|
|
2015-04-01 23:18:48 +02:00
|
|
|
#if !defined(__LP64__)
|
|
|
|
if (has_text_relocations) {
|
|
|
|
// All relocations are done, we can protect our segments back to read-only.
|
|
|
|
if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
|
|
|
|
DL_ERR("can't protect segments for \"%s\": %s",
|
2015-05-07 19:48:00 +02:00
|
|
|
get_realpath(), strerror(errno));
|
2015-04-01 23:18:48 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2015-11-12 08:02:14 +01:00
|
|
|
// We can also turn on GNU RELRO protection if we're not linking the dynamic linker
|
|
|
|
// itself --- it can't make system calls yet, and will have to call protect_relro later.
|
|
|
|
if (!is_linker() && !protect_relro()) {
|
2014-09-12 18:43:13 +02:00
|
|
|
return false;
|
|
|
|
}
|
2012-02-28 19:40:00 +01:00
|
|
|
|
2014-09-12 18:43:13 +02:00
|
|
|
/* Handle serializing/sharing the RELRO segment */
|
|
|
|
if (extinfo && (extinfo->flags & ANDROID_DLEXT_WRITE_RELRO)) {
|
|
|
|
if (phdr_table_serialize_gnu_relro(phdr, phnum, load_bias,
|
|
|
|
extinfo->relro_fd) < 0) {
|
|
|
|
DL_ERR("failed serializing GNU RELRO section for \"%s\": %s",
|
2015-05-07 19:48:00 +02:00
|
|
|
get_realpath(), strerror(errno));
|
2014-09-12 18:43:13 +02:00
|
|
|
return false;
|
2014-02-27 14:18:00 +01:00
|
|
|
}
|
2014-09-12 18:43:13 +02:00
|
|
|
} else if (extinfo && (extinfo->flags & ANDROID_DLEXT_USE_RELRO)) {
|
|
|
|
if (phdr_table_map_gnu_relro(phdr, phnum, load_bias,
|
|
|
|
extinfo->relro_fd) < 0) {
|
|
|
|
DL_ERR("failed mapping GNU RELRO section for \"%s\": %s",
|
2015-05-07 19:48:00 +02:00
|
|
|
get_realpath(), strerror(errno));
|
2014-09-12 18:43:13 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2014-02-27 14:18:00 +01:00
|
|
|
|
2014-09-12 18:43:13 +02:00
|
|
|
notify_gdb_of_load(this);
|
|
|
|
return true;
|
2009-03-04 04:28:35 +01:00
|
|
|
}
|
|
|
|
|
2015-11-12 08:02:14 +01:00
|
|
|
bool soinfo::protect_relro() {
|
|
|
|
if (phdr_table_protect_gnu_relro(phdr, phnum, load_bias) < 0) {
|
|
|
|
DL_ERR("can't enable GNU RELRO protection for \"%s\": %s",
|
|
|
|
get_realpath(), strerror(errno));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-03-07 20:19:05 +01:00
|
|
|
static void init_default_namespace_no_config(bool is_asan) {
|
2015-10-30 01:01:24 +01:00
|
|
|
g_default_namespace.set_isolated(false);
|
2017-03-06 22:02:29 +01:00
|
|
|
auto default_ld_paths = is_asan ? kAsanDefaultLdPaths : kDefaultLdPaths;
|
2015-10-30 01:01:24 +01:00
|
|
|
|
2016-10-04 04:00:27 +02:00
|
|
|
char real_path[PATH_MAX];
|
2015-10-30 01:01:24 +01:00
|
|
|
std::vector<std::string> ld_default_paths;
|
2017-03-06 22:02:29 +01:00
|
|
|
for (size_t i = 0; default_ld_paths[i] != nullptr; ++i) {
|
|
|
|
if (realpath(default_ld_paths[i], real_path) != nullptr) {
|
2016-10-04 04:00:27 +02:00
|
|
|
ld_default_paths.push_back(real_path);
|
|
|
|
} else {
|
2017-03-06 22:02:29 +01:00
|
|
|
ld_default_paths.push_back(default_ld_paths[i]);
|
2016-10-04 04:00:27 +02:00
|
|
|
}
|
2015-10-30 01:01:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
g_default_namespace.set_default_library_paths(std::move(ld_default_paths));
|
2017-03-07 20:19:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void init_default_namespace(const char* executable_path) {
|
|
|
|
g_default_namespace.set_name("(default)");
|
|
|
|
|
|
|
|
soinfo* somain = solist_get_somain();
|
|
|
|
|
|
|
|
const char *interp = phdr_table_get_interpreter_name(somain->phdr, somain->phnum,
|
|
|
|
somain->load_bias);
|
|
|
|
const char* bname = basename(interp);
|
|
|
|
|
|
|
|
g_is_asan = bname != nullptr &&
|
|
|
|
(strcmp(bname, "linker_asan") == 0 ||
|
|
|
|
strcmp(bname, "linker_asan64") == 0);
|
|
|
|
|
|
|
|
const Config* config = nullptr;
|
|
|
|
|
|
|
|
std::string error_msg;
|
|
|
|
|
|
|
|
if (!Config::read_binary_config(kLdConfigFilePath,
|
|
|
|
executable_path,
|
|
|
|
g_is_asan,
|
|
|
|
&config,
|
|
|
|
&error_msg)) {
|
|
|
|
if (!error_msg.empty()) {
|
|
|
|
DL_WARN("error reading config file \"%s\" for \"%s\" (will use default configuration): %s",
|
|
|
|
kLdConfigFilePath,
|
|
|
|
executable_path,
|
|
|
|
error_msg.c_str());
|
|
|
|
}
|
|
|
|
config = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (config == nullptr) {
|
|
|
|
init_default_namespace_no_config(g_is_asan);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const auto& namespace_configs = config->namespace_configs();
|
|
|
|
std::unordered_map<std::string, android_namespace_t*> namespaces;
|
|
|
|
|
|
|
|
// 1. Initialize default namespace
|
|
|
|
const NamespaceConfig* default_ns_config = config->default_namespace_config();
|
|
|
|
|
|
|
|
g_default_namespace.set_isolated(default_ns_config->isolated());
|
|
|
|
g_default_namespace.set_default_library_paths(default_ns_config->search_paths());
|
|
|
|
g_default_namespace.set_permitted_paths(default_ns_config->permitted_paths());
|
|
|
|
|
|
|
|
namespaces[default_ns_config->name()] = &g_default_namespace;
|
|
|
|
|
|
|
|
// 2. Initialize other namespaces
|
|
|
|
|
|
|
|
for (auto& ns_config : namespace_configs) {
|
|
|
|
if (namespaces.find(ns_config->name()) != namespaces.end()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
android_namespace_t* ns = new (g_namespace_allocator.alloc()) android_namespace_t();
|
|
|
|
ns->set_name(ns_config->name());
|
|
|
|
ns->set_isolated(ns_config->isolated());
|
|
|
|
ns->set_default_library_paths(ns_config->search_paths());
|
|
|
|
ns->set_permitted_paths(ns_config->permitted_paths());
|
|
|
|
|
|
|
|
namespaces[ns_config->name()] = ns;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 3. Establish links between namespaces
|
|
|
|
for (auto& ns_config : namespace_configs) {
|
|
|
|
auto it_from = namespaces.find(ns_config->name());
|
|
|
|
CHECK(it_from != namespaces.end());
|
|
|
|
android_namespace_t* namespace_from = it_from->second;
|
|
|
|
for (const NamespaceLinkConfig& ns_link : ns_config->links()) {
|
|
|
|
auto it_to = namespaces.find(ns_link.ns_name());
|
|
|
|
CHECK(it_to != namespaces.end());
|
|
|
|
android_namespace_t* namespace_to = it_to->second;
|
|
|
|
link_namespaces(namespace_from, namespace_to, ns_link.shared_libs().c_str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// we can no longer rely on the fact that libdl.so is part of default namespace
|
|
|
|
// this is why we want to add ld-android.so to all namespaces from ld.config.txt
|
|
|
|
soinfo* ld_android_so = solist_get_head();
|
|
|
|
for (auto it : namespaces) {
|
|
|
|
it.second->add_soinfo(ld_android_so);
|
|
|
|
// TODO (dimitry): somain and ld_preloads should probably be added to all of these namespaces too?
|
|
|
|
}
|
|
|
|
|
|
|
|
set_application_target_sdk_version(config->target_sdk_version());
|
|
|
|
}
|