blob: 522d5dc1a95f11e28cfd2fa860f1f27a6a132625 [file] [log] [blame]
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001/*
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002 * Copyright (C) 2008 The Android Open Source Project
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
Dmitriy Ivanov19133522015-06-02 17:36:54 -070029#include <android/api-level.h>
Elliott Hughes46882792012-08-03 16:49:39 -070030#include <errno.h>
31#include <fcntl.h>
Elliott Hughes0266ae52014-02-10 17:46:57 -080032#include <inttypes.h>
Elliott Hughes46882792012-08-03 16:49:39 -070033#include <pthread.h>
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080034#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
Elliott Hughes46882792012-08-03 16:49:39 -070037#include <sys/mman.h>
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -080038#include <sys/param.h>
Elliott Hughes46882792012-08-03 16:49:39 -070039#include <unistd.h>
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080040
Dmitriy Ivanov0d150942014-08-22 12:25:04 -070041#include <new>
Dmitriy Ivanovd165f562015-03-23 18:43:02 -070042#include <string>
Dmitriy Ivanovb4827502015-09-28 16:38:31 -070043#include <unordered_map>
Dmitriy Ivanovd165f562015-03-23 18:43:02 -070044#include <vector>
Dmitriy Ivanov0d150942014-08-22 12:25:04 -070045
Elliott Hughes46882792012-08-03 16:49:39 -070046// Private C library headers.
Dmitriy Ivanov14669a92014-09-05 16:42:53 -070047#include "private/ScopeGuard.h"
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080048
49#include "linker.h"
Dmitriy Ivanovc9ce70d2015-03-10 15:30:26 -070050#include "linker_block_allocator.h"
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -070051#include "linker_cfi.h"
Dimitry Ivanov6b788ee2016-02-17 16:08:03 -080052#include "linker_gdb_support.h"
Dimitry Ivanov48ec2882016-08-04 11:50:36 -070053#include "linker_globals.h"
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080054#include "linker_debug.h"
Dimitry Ivanov769b33f2016-07-21 11:33:40 -070055#include "linker_dlwarning.h"
Dimitry Ivanov3f660572016-09-09 10:00:39 -070056#include "linker_main.h"
Dimitry Ivanovb943f302016-08-03 16:00:10 -070057#include "linker_namespaces.h"
Dmitriy Ivanov18870d32015-04-22 13:10:04 -070058#include "linker_sleb128.h"
David 'Digit' Turner23363ed2012-06-18 18:13:49 +020059#include "linker_phdr.h"
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -080060#include "linker_relocs.h"
Dmitriy Ivanovfa26eee2015-02-03 16:06:47 -080061#include "linker_reloc_iterators.h"
Dmitriy Ivanova1feb112015-10-01 18:41:57 -070062#include "linker_utils.h"
tony.ys_liub4474402015-07-29 18:00:22 +080063
Elliott Hughes939a7e02015-12-04 15:27:46 -080064#include "android-base/strings.h"
Dimitry Ivanovb996d602016-07-11 18:11:39 -070065#include "android-base/stringprintf.h"
Simon Baldwinaef71952015-01-16 13:22:54 +000066#include "ziparchive/zip_archive.h"
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080067
Elliott Hughes1801db32015-06-08 18:04:00 -070068// Override macros to use C++ style casts.
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -080069#undef ELF_ST_TYPE
70#define ELF_ST_TYPE(x) (static_cast<uint32_t>(x) & 0xf)
71
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -070072static android_namespace_t* g_anonymous_namespace = &g_default_namespace;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -070073
Dmitriy Ivanov600bc3c2015-03-10 15:43:50 -070074static LinkerTypeAllocator<soinfo> g_soinfo_allocator;
75static LinkerTypeAllocator<LinkedListEntry<soinfo>> g_soinfo_links_allocator;
Magnus Malmbornba98d922012-09-12 13:00:55 +020076
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -070077static LinkerTypeAllocator<android_namespace_t> g_namespace_allocator;
Dimitry Ivanovaca299a2016-04-11 12:42:58 -070078static LinkerTypeAllocator<LinkedListEntry<android_namespace_t>> g_namespace_list_allocator;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -070079
Elliott Hughes4eeb1f12013-10-25 17:38:02 -070080#if defined(__LP64__)
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -070081static const char* const kSystemLibDir = "/system/lib64";
82static const char* const kVendorLibDir = "/vendor/lib64";
83static const char* const kAsanSystemLibDir = "/data/lib64";
84static const char* const kAsanVendorLibDir = "/data/vendor/lib64";
Elliott Hughes011bc0b2013-10-08 14:27:10 -070085#else
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -070086static const char* const kSystemLibDir = "/system/lib";
87static const char* const kVendorLibDir = "/vendor/lib";
88static const char* const kAsanSystemLibDir = "/data/lib";
89static const char* const kAsanVendorLibDir = "/data/vendor/lib";
Elliott Hughes011bc0b2013-10-08 14:27:10 -070090#endif
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -070091
92static const char* const kDefaultLdPaths[] = {
93 kSystemLibDir,
94 kVendorLibDir,
Dmitriy Ivanov851135b2014-08-29 12:02:36 -070095 nullptr
Elliott Hughes124fae92012-10-31 14:20:03 -070096};
David Bartleybc3a5c22009-06-02 18:27:28 -070097
Evgenii Stepanovd640b222015-07-10 17:54:01 -070098static const char* const kAsanDefaultLdPaths[] = {
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -070099 kAsanSystemLibDir,
100 kSystemLibDir,
101 kAsanVendorLibDir,
102 kVendorLibDir,
Evgenii Stepanovd640b222015-07-10 17:54:01 -0700103 nullptr
104};
105
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700106// Is ASAN enabled?
107static bool g_is_asan = false;
108
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -0700109static CFIShadowWriter g_cfi_shadow;
110
111CFIShadowWriter* get_cfi_shadow() {
112 return &g_cfi_shadow;
113}
114
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700115static bool is_system_library(const std::string& realpath) {
116 for (const auto& dir : g_default_namespace.get_default_library_paths()) {
117 if (file_is_in_dir(realpath, dir)) {
118 return true;
119 }
120 }
121 return false;
122}
123
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700124// Checks if the file exists and not a directory.
125static bool file_exists(const char* path) {
Dimitry Ivanov4cf70242016-08-11 11:11:52 -0700126 struct stat s;
127
128 if (stat(path, &s) != 0) {
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700129 return false;
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700130 }
Dimitry Ivanov4cf70242016-08-11 11:11:52 -0700131
132 return S_ISREG(s.st_mode);
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700133}
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700134
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700135// TODO(dimitry): The grey-list is a workaround for http://b/26394120 ---
136// gradually remove libraries from this list until it is gone.
137static bool is_greylisted(const char* name, const soinfo* needed_by) {
138 static const char* const kLibraryGreyList[] = {
139 "libandroid_runtime.so",
140 "libbinder.so",
141 "libcrypto.so",
142 "libcutils.so",
143 "libexpat.so",
144 "libgui.so",
145 "libmedia.so",
146 "libnativehelper.so",
147 "libskia.so",
148 "libssl.so",
149 "libstagefright.so",
150 "libsqlite.so",
151 "libui.so",
152 "libutils.so",
153 "libvorbisidec.so",
154 nullptr
155 };
156
Elliott Hughes5bc78c82016-11-16 11:35:43 -0800157 // If you're targeting N, you don't get the greylist.
158 if (get_application_target_sdk_version() >= __ANDROID_API_N__) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700159 return false;
160 }
161
162 // if the library needed by a system library - implicitly assume it
163 // is greylisted
164
165 if (needed_by != nullptr && is_system_library(needed_by->get_realpath())) {
166 return true;
167 }
168
169 // if this is an absolute path - make sure it points to /system/lib(64)
170 if (name[0] == '/' && dirname(name) == kSystemLibDir) {
171 // and reduce the path to basename
172 name = basename(name);
173 }
174
175 for (size_t i = 0; kLibraryGreyList[i] != nullptr; ++i) {
176 if (strcmp(name, kLibraryGreyList[i]) == 0) {
177 return true;
178 }
179 }
180
181 return false;
182}
183// END OF WORKAROUND
184
Evgenii Stepanovd640b222015-07-10 17:54:01 -0700185static const char* const* g_default_ld_paths;
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700186static std::vector<std::string> g_ld_preload_names;
Elliott Hughesa4aafd12014-01-13 16:37:47 -0800187
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700188static bool g_public_namespace_initialized;
Dimitry Ivanov7d429d32017-02-01 15:28:52 -0800189
190// TODO (dimitry): Remove once interface between libnativeloader and the linker is updated
191static std::unordered_set<std::string> g_public_namespace_sonames;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700192
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800193#if STATS
Elliott Hughesbedfe382012-08-14 14:07:59 -0700194struct linker_stats_t {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700195 int count[kRelocMax];
Elliott Hughesbedfe382012-08-14 14:07:59 -0700196};
197
198static linker_stats_t linker_stats;
199
Dmitriy Ivanov114ff692015-01-14 11:36:38 -0800200void count_relocation(RelocationKind kind) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700201 ++linker_stats.count[kind];
Elliott Hughesbedfe382012-08-14 14:07:59 -0700202}
203#else
Dmitriy Ivanov114ff692015-01-14 11:36:38 -0800204void count_relocation(RelocationKind) {
Elliott Hughesbedfe382012-08-14 14:07:59 -0700205}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800206#endif
207
208#if COUNT_PAGES
Dmitriy Ivanov114ff692015-01-14 11:36:38 -0800209uint32_t bitmask[4096];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800210#endif
211
Elliott Hughesbedfe382012-08-14 14:07:59 -0700212static void notify_gdb_of_load(soinfo* info) {
Dimitry Ivanove97d8ed2016-03-01 15:55:56 -0800213 if (info->is_linker() || info->is_main_executable()) {
214 // gdb already knows about the linker and the main executable.
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700215 return;
216 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800217
Dimitry Ivanov6b788ee2016-02-17 16:08:03 -0800218 link_map* map = &(info->link_map_head);
Nicolas Geoffray0fa54102016-02-18 09:31:24 +0000219
Dimitry Ivanov6b788ee2016-02-17 16:08:03 -0800220 map->l_addr = info->load_bias;
221 // link_map l_name field is not const.
222 map->l_name = const_cast<char*>(info->get_realpath());
223 map->l_ld = info->dynamic;
Nicolas Geoffray0fa54102016-02-18 09:31:24 +0000224
Dimitry Ivanove97d8ed2016-03-01 15:55:56 -0800225 CHECK(map->l_name != nullptr);
226 CHECK(map->l_name[0] != '\0');
227
Dimitry Ivanov6b788ee2016-02-17 16:08:03 -0800228 notify_gdb_of_load(map);
Iliyan Malchev5e12d7e2009-03-24 19:02:00 -0700229}
230
Elliott Hughesbedfe382012-08-14 14:07:59 -0700231static void notify_gdb_of_unload(soinfo* info) {
Dimitry Ivanov6b788ee2016-02-17 16:08:03 -0800232 notify_gdb_of_unload(&(info->link_map_head));
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800233}
234
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -0700235LinkedListEntry<soinfo>* SoinfoListAllocator::alloc() {
236 return g_soinfo_links_allocator.alloc();
237}
238
239void SoinfoListAllocator::free(LinkedListEntry<soinfo>* entry) {
240 g_soinfo_links_allocator.free(entry);
241}
242
Dimitry Ivanovaca299a2016-04-11 12:42:58 -0700243LinkedListEntry<android_namespace_t>* NamespaceListAllocator::alloc() {
244 return g_namespace_list_allocator.alloc();
245}
246
247void NamespaceListAllocator::free(LinkedListEntry<android_namespace_t>* entry) {
248 g_namespace_list_allocator.free(entry);
249}
250
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700251soinfo* soinfo_alloc(android_namespace_t* ns, const char* name,
252 struct stat* file_stat, off64_t file_offset,
253 uint32_t rtld_flags) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700254 if (strlen(name) >= PATH_MAX) {
Magnus Malmbornba98d922012-09-12 13:00:55 +0200255 DL_ERR("library name \"%s\" too long", name);
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700256 return nullptr;
Magnus Malmbornba98d922012-09-12 13:00:55 +0200257 }
258
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700259 TRACE("name %s: allocating soinfo for ns=%p", name, ns);
260
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700261 soinfo* si = new (g_soinfo_allocator.alloc()) soinfo(ns, name, file_stat,
262 file_offset, rtld_flags);
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -0700263
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700264 solist_add_soinfo(si);
Magnus Malmbornba98d922012-09-12 13:00:55 +0200265
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -0700266 si->generate_handle();
267 ns->add_soinfo(si);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700268
Elliott Hughesca0c11b2013-03-12 10:40:45 -0700269 TRACE("name %s: allocated soinfo @ %p", name, si);
Magnus Malmbornba98d922012-09-12 13:00:55 +0200270 return si;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800271}
272
Elliott Hughesfaf05ba2014-02-11 16:59:37 -0800273static void soinfo_free(soinfo* si) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700274 if (si == nullptr) {
275 return;
276 }
277
278 if (si->base != 0 && si->size != 0) {
Dimitry Ivanovf45b0e92016-01-15 11:13:35 -0800279 if (!si->is_mapped_by_caller()) {
280 munmap(reinterpret_cast<void*>(si->base), si->size);
281 } else {
282 // remap the region as PROT_NONE, MAP_ANONYMOUS | MAP_NORESERVE
283 mmap(reinterpret_cast<void*>(si->base), si->size, PROT_NONE,
284 MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
285 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700286 }
287
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700288 TRACE("name %s: freeing soinfo @ %p", si->get_realpath(), si);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700289
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700290 if (!solist_remove_soinfo(si)) {
291 // TODO (dimitry): revisit this - for now preserving the logic
292 // but it does not look right, abort if soinfo is not in the list instead?
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700293 return;
294 }
Elliott Hughes46882792012-08-03 16:49:39 -0700295
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700296 // clear links to/from si
297 si->remove_all_links();
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -0700298
Dmitriy Ivanov609f11b2015-07-08 15:26:46 -0700299 si->~soinfo();
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700300 g_soinfo_allocator.free(si);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800301}
302
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700303static void parse_path(const char* path, const char* delimiters,
304 std::vector<std::string>* resolved_paths) {
305 std::vector<std::string> paths;
306 split_path(path, delimiters, &paths);
307 resolve_paths(paths, resolved_paths);
308}
309
Elliott Hughescade4c32012-12-20 14:42:14 -0800310static void parse_LD_LIBRARY_PATH(const char* path) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700311 std::vector<std::string> ld_libary_paths;
312 parse_path(path, ":", &ld_libary_paths);
313 g_default_namespace.set_ld_library_paths(std::move(ld_libary_paths));
Elliott Hughescade4c32012-12-20 14:42:14 -0800314}
315
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700316static bool realpath_fd(int fd, std::string* realpath) {
317 std::vector<char> buf(PATH_MAX), proc_self_fd(PATH_MAX);
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700318 __libc_format_buffer(&proc_self_fd[0], proc_self_fd.size(), "/proc/self/fd/%d", fd);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700319 if (readlink(&proc_self_fd[0], &buf[0], buf.size()) == -1) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700320 PRINT("readlink(\"%s\") failed: %s [fd=%d]", &proc_self_fd[0], strerror(errno), fd);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700321 return false;
322 }
323
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700324 *realpath = &buf[0];
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700325 return true;
326}
327
Elliott Hughes4eeb1f12013-10-25 17:38:02 -0700328#if defined(__arm__)
Elliott Hughes46882792012-08-03 16:49:39 -0700329
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700330// For a given PC, find the .so that it belongs to.
331// Returns the base address of the .ARM.exidx section
332// for that .so, and the number of 8-byte entries
333// in that section (via *pcount).
334//
335// Intended to be called by libc's __gnu_Unwind_Find_exidx().
Dimitry Ivanovd9e427c2016-11-22 16:55:25 -0800336_Unwind_Ptr do_dl_unwind_find_exidx(_Unwind_Ptr pc, int* pcount) {
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -0800337 uintptr_t addr = reinterpret_cast<uintptr_t>(pc);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800338
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700339 for (soinfo* si = solist_get_head(); si != 0; si = si->next) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700340 if ((addr >= si->base) && (addr < (si->base + si->size))) {
341 *pcount = si->ARM_exidx_count;
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -0800342 return reinterpret_cast<_Unwind_Ptr>(si->ARM_exidx);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800343 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700344 }
345 *pcount = 0;
346 return nullptr;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800347}
Elliott Hughes46882792012-08-03 16:49:39 -0700348
Christopher Ferris24053a42013-08-19 17:45:09 -0700349#endif
Elliott Hughes46882792012-08-03 16:49:39 -0700350
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700351// Here, we only have to provide a callback to iterate across all the
352// loaded libraries. gcc_eh does the rest.
Dmitriy Ivanov7271caf2015-06-29 14:48:25 -0700353int do_dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void* data) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700354 int rv = 0;
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700355 for (soinfo* si = solist_get_head(); si != nullptr; si = si->next) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700356 dl_phdr_info dl_info;
357 dl_info.dlpi_addr = si->link_map_head.l_addr;
358 dl_info.dlpi_name = si->link_map_head.l_name;
359 dl_info.dlpi_phdr = si->phdr;
360 dl_info.dlpi_phnum = si->phnum;
361 rv = cb(&dl_info, sizeof(dl_phdr_info), data);
362 if (rv != 0) {
363 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800364 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700365 }
366 return rv;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800367}
Elliott Hughes46882792012-08-03 16:49:39 -0700368
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800369
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700370bool soinfo_do_lookup(soinfo* si_from, const char* name, const version_info* vi,
Dimitry Ivanovb943f302016-08-03 16:00:10 -0700371 soinfo** si_found_in, const soinfo_list_t& global_group,
372 const soinfo_list_t& local_group, const ElfW(Sym)** symbol) {
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800373 SymbolName symbol_name(name);
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700374 const ElfW(Sym)* s = nullptr;
Iliyan Malchev6ed80c82009-09-28 19:38:04 -0700375
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -0700376 /* "This element's presence in a shared object library alters the dynamic linker's
377 * symbol resolution algorithm for references within the library. Instead of starting
378 * a symbol search with the executable file, the dynamic linker starts from the shared
379 * object itself. If the shared object fails to supply the referenced symbol, the
380 * dynamic linker then searches the executable file and other shared objects as usual."
381 *
382 * http://www.sco.com/developers/gabi/2012-12-31/ch5.dynamic.html
383 *
384 * Note that this is unlikely since static linker avoids generating
385 * relocations for -Bsymbolic linked dynamic executables.
386 */
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700387 if (si_from->has_DT_SYMBOLIC) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700388 DEBUG("%s: looking up %s in local scope (DT_SYMBOLIC)", si_from->get_realpath(), name);
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700389 if (!si_from->find_symbol_by_name(symbol_name, vi, &s)) {
390 return false;
391 }
392
Dmitriy Ivanov8f61d992014-09-16 14:31:06 -0700393 if (s != nullptr) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700394 *si_found_in = si_from;
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -0700395 }
396 }
397
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700398 // 1. Look for it in global_group
399 if (s == nullptr) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700400 bool error = false;
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700401 global_group.visit([&](soinfo* global_si) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700402 DEBUG("%s: looking up %s in %s (from global group)",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700403 si_from->get_realpath(), name, global_si->get_realpath());
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700404 if (!global_si->find_symbol_by_name(symbol_name, vi, &s)) {
405 error = true;
406 return false;
407 }
408
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -0700409 if (s != nullptr) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700410 *si_found_in = global_si;
411 return false;
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -0700412 }
Dmitriy Ivanovc2048942014-08-29 10:15:25 -0700413
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700414 return true;
415 });
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700416
417 if (error) {
418 return false;
419 }
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -0700420 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700421
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700422 // 2. Look for it in the local group
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700423 if (s == nullptr) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700424 bool error = false;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700425 local_group.visit([&](soinfo* local_si) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700426 if (local_si == si_from && si_from->has_DT_SYMBOLIC) {
Dmitriy Ivanove47b3f82014-10-23 14:19:07 -0700427 // we already did this - skip
428 return true;
429 }
430
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700431 DEBUG("%s: looking up %s in %s (from local group)",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700432 si_from->get_realpath(), name, local_si->get_realpath());
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700433 if (!local_si->find_symbol_by_name(symbol_name, vi, &s)) {
434 error = true;
435 return false;
436 }
437
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700438 if (s != nullptr) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700439 *si_found_in = local_si;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700440 return false;
441 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700442
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700443 return true;
444 });
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700445
446 if (error) {
447 return false;
448 }
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700449 }
450
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700451 if (s != nullptr) {
452 TRACE_TYPE(LOOKUP, "si %s sym %s s->st_value = %p, "
453 "found in %s, base = %p, load bias = %p",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700454 si_from->get_realpath(), name, reinterpret_cast<void*>(s->st_value),
455 (*si_found_in)->get_realpath(), reinterpret_cast<void*>((*si_found_in)->base),
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700456 reinterpret_cast<void*>((*si_found_in)->load_bias));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700457 }
Iliyan Malchev6ed80c82009-09-28 19:38:04 -0700458
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700459 *symbol = s;
460 return true;
Iliyan Malchev6ed80c82009-09-28 19:38:04 -0700461}
462
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700463ProtectedDataGuard::ProtectedDataGuard() {
464 if (ref_count_++ == 0) {
465 protect_data(PROT_READ | PROT_WRITE);
466 }
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700467
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700468 if (ref_count_ == 0) { // overflow
469 __libc_fatal("Too many nested calls to dlopen()");
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -0800470 }
Dimitry Ivanov68e6c032017-02-01 12:55:11 -0800471}
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -0800472
Dimitry Ivanov68e6c032017-02-01 12:55:11 -0800473ProtectedDataGuard::~ProtectedDataGuard() {
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700474 if (--ref_count_ == 0) {
475 protect_data(PROT_READ);
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -0800476 }
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700477}
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -0800478
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700479void ProtectedDataGuard::protect_data(int protection) {
480 g_soinfo_allocator.protect_all(protection);
481 g_soinfo_links_allocator.protect_all(protection);
482 g_namespace_allocator.protect_all(protection);
483 g_namespace_list_allocator.protect_all(protection);
484}
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -0800485
486size_t ProtectedDataGuard::ref_count_ = 0;
487
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700488// Each size has it's own allocator.
489template<size_t size>
490class SizeBasedAllocator {
491 public:
492 static void* alloc() {
493 return allocator_.alloc();
494 }
Dmitriy Ivanov4bea4982014-08-29 14:01:48 -0700495
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700496 static void free(void* ptr) {
497 allocator_.free(ptr);
498 }
Dmitriy Ivanov4bea4982014-08-29 14:01:48 -0700499
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700500 private:
501 static LinkerBlockAllocator allocator_;
502};
503
504template<size_t size>
505LinkerBlockAllocator SizeBasedAllocator<size>::allocator_(size);
506
507template<typename T>
508class TypeBasedAllocator {
509 public:
510 static T* alloc() {
511 return reinterpret_cast<T*>(SizeBasedAllocator<sizeof(T)>::alloc());
512 }
513
514 static void free(T* ptr) {
515 SizeBasedAllocator<sizeof(T)>::free(ptr);
516 }
517};
518
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700519class LoadTask {
520 public:
521 struct deleter_t {
522 void operator()(LoadTask* t) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700523 t->~LoadTask();
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700524 TypeBasedAllocator<LoadTask>::free(t);
525 }
526 };
527
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700528 static deleter_t deleter;
529
Dimitry Ivanov7d429d32017-02-01 15:28:52 -0800530 static LoadTask* create(const char* name,
531 soinfo* needed_by,
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700532 std::unordered_map<const soinfo*, ElfReader>* readers_map) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700533 LoadTask* ptr = TypeBasedAllocator<LoadTask>::alloc();
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700534 return new (ptr) LoadTask(name, needed_by, readers_map);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700535 }
536
537 const char* get_name() const {
538 return name_;
539 }
540
541 soinfo* get_needed_by() const {
542 return needed_by_;
543 }
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700544
545 soinfo* get_soinfo() const {
546 return si_;
547 }
548
549 void set_soinfo(soinfo* si) {
550 si_ = si;
551 }
552
553 off64_t get_file_offset() const {
554 return file_offset_;
555 }
556
557 void set_file_offset(off64_t offset) {
558 file_offset_ = offset;
559 }
560
561 int get_fd() const {
562 return fd_;
563 }
564
565 void set_fd(int fd, bool assume_ownership) {
566 fd_ = fd;
567 close_fd_ = assume_ownership;
568 }
569
570 const android_dlextinfo* get_extinfo() const {
571 return extinfo_;
572 }
573
574 void set_extinfo(const android_dlextinfo* extinfo) {
575 extinfo_ = extinfo;
576 }
577
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700578 bool is_dt_needed() const {
579 return is_dt_needed_;
580 }
581
582 void set_dt_needed(bool is_dt_needed) {
583 is_dt_needed_ = is_dt_needed;
584 }
585
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700586 const ElfReader& get_elf_reader() const {
587 CHECK(si_ != nullptr);
588 return (*elf_readers_map_)[si_];
589 }
590
591 ElfReader& get_elf_reader() {
592 CHECK(si_ != nullptr);
593 return (*elf_readers_map_)[si_];
594 }
595
596 std::unordered_map<const soinfo*, ElfReader>* get_readers_map() {
597 return elf_readers_map_;
598 }
599
600 bool read(const char* realpath, off64_t file_size) {
601 ElfReader& elf_reader = get_elf_reader();
602 return elf_reader.Read(realpath, fd_, file_offset_, file_size);
603 }
604
605 bool load() {
606 ElfReader& elf_reader = get_elf_reader();
607 if (!elf_reader.Load(extinfo_)) {
608 return false;
609 }
610
611 si_->base = elf_reader.load_start();
612 si_->size = elf_reader.load_size();
Dimitry Ivanovf45b0e92016-01-15 11:13:35 -0800613 si_->set_mapped_by_caller(elf_reader.is_mapped_by_caller());
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700614 si_->load_bias = elf_reader.load_bias();
615 si_->phnum = elf_reader.phdr_count();
616 si_->phdr = elf_reader.loaded_phdr();
617
618 return true;
619 }
620
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700621 private:
Dimitry Ivanov7d429d32017-02-01 15:28:52 -0800622 LoadTask(const char* name,
623 soinfo* needed_by,
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700624 std::unordered_map<const soinfo*, ElfReader>* readers_map)
625 : name_(name), needed_by_(needed_by), si_(nullptr),
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700626 fd_(-1), close_fd_(false), file_offset_(0), elf_readers_map_(readers_map),
627 is_dt_needed_(false) {}
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700628
629 ~LoadTask() {
630 if (fd_ != -1 && close_fd_) {
631 close(fd_);
632 }
633 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700634
635 const char* name_;
636 soinfo* needed_by_;
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700637 soinfo* si_;
638 const android_dlextinfo* extinfo_;
639 int fd_;
640 bool close_fd_;
641 off64_t file_offset_;
642 std::unordered_map<const soinfo*, ElfReader>* elf_readers_map_;
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700643 // TODO(dimitry): needed by workaround for http://b/26394120 (the grey-list)
644 bool is_dt_needed_;
645 // END OF WORKAROUND
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700646
647 DISALLOW_IMPLICIT_CONSTRUCTORS(LoadTask);
648};
649
Ningsheng Jiane93be992014-09-16 15:22:10 +0800650LoadTask::deleter_t LoadTask::deleter;
651
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700652template <typename T>
653using linked_list_t = LinkedList<T, TypeBasedAllocator<LinkedListEntry<T>>>;
654
655typedef linked_list_t<soinfo> SoinfoLinkedList;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700656typedef linked_list_t<const char> StringLinkedList;
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700657typedef std::vector<LoadTask*> LoadTaskList;
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700658
Dmitriy Ivanovaa0f2bd2014-07-28 17:32:20 -0700659
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700660// This function walks down the tree of soinfo dependencies
661// in breadth-first order and
662// * calls action(soinfo* si) for each node, and
663// * terminates walk if action returns false.
664//
665// walk_dependencies_tree returns false if walk was terminated
666// by the action and true otherwise.
667template<typename F>
668static bool walk_dependencies_tree(soinfo* root_soinfos[], size_t root_soinfos_size, F action) {
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700669 SoinfoLinkedList visit_list;
670 SoinfoLinkedList visited;
671
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700672 for (size_t i = 0; i < root_soinfos_size; ++i) {
673 visit_list.push_back(root_soinfos[i]);
674 }
675
676 soinfo* si;
677 while ((si = visit_list.pop_front()) != nullptr) {
678 if (visited.contains(si)) {
Dmitriy Ivanov042426b2014-08-12 21:02:13 -0700679 continue;
680 }
681
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700682 if (!action(si)) {
683 return false;
Dmitriy Ivanovaa0f2bd2014-07-28 17:32:20 -0700684 }
685
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700686 visited.push_back(si);
687
688 si->get_children().for_each([&](soinfo* child) {
Dmitriy Ivanovaa0f2bd2014-07-28 17:32:20 -0700689 visit_list.push_back(child);
690 });
691 }
692
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700693 return true;
694}
695
696
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700697static const ElfW(Sym)* dlsym_handle_lookup(soinfo* root, soinfo* skip_until,
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800698 soinfo** found, SymbolName& symbol_name,
699 const version_info* vi) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700700 const ElfW(Sym)* result = nullptr;
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700701 bool skip_lookup = skip_until != nullptr;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700702
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700703 walk_dependencies_tree(&root, 1, [&](soinfo* current_soinfo) {
704 if (skip_lookup) {
705 skip_lookup = current_soinfo != skip_until;
706 return true;
707 }
708
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800709 if (!current_soinfo->find_symbol_by_name(symbol_name, vi, &result)) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700710 result = nullptr;
711 return false;
712 }
713
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700714 if (result != nullptr) {
715 *found = current_soinfo;
716 return false;
717 }
718
719 return true;
720 });
721
722 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800723}
724
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800725static const ElfW(Sym)* dlsym_linear_lookup(android_namespace_t* ns,
726 const char* name,
727 const version_info* vi,
728 soinfo** found,
729 soinfo* caller,
730 void* handle);
731
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700732// This is used by dlsym(3). It performs symbol lookup only within the
733// specified soinfo object and its dependencies in breadth first order.
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800734static const ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found,
735 const char* name, const version_info* vi) {
Dmitriy Ivanovf439b5a2015-05-30 13:04:39 -0700736 // According to man dlopen(3) and posix docs in the case when si is handle
737 // of the main executable we need to search not only in the executable and its
738 // dependencies but also in all libraries loaded with RTLD_GLOBAL.
739 //
740 // Since RTLD_GLOBAL is always set for the main executable and all dt_needed shared
741 // libraries and they are loaded in breath-first (correct) order we can just execute
742 // dlsym(RTLD_DEFAULT, ...); instead of doing two stage lookup.
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700743 if (si == solist_get_somain()) {
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800744 return dlsym_linear_lookup(&g_default_namespace, name, vi, found, nullptr, RTLD_DEFAULT);
Dmitriy Ivanovf439b5a2015-05-30 13:04:39 -0700745 }
746
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700747 SymbolName symbol_name(name);
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800748 return dlsym_handle_lookup(si, nullptr, found, symbol_name, vi);
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700749}
750
Brian Carlstromd4ee82d2013-02-28 15:58:45 -0800751/* This is used by dlsym(3) to performs a global symbol lookup. If the
752 start value is null (for RTLD_DEFAULT), the search starts at the
753 beginning of the global solist. Otherwise the search starts at the
754 specified soinfo (for RTLD_NEXT).
Iliyan Malchev6ed80c82009-09-28 19:38:04 -0700755 */
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800756static const ElfW(Sym)* dlsym_linear_lookup(android_namespace_t* ns,
757 const char* name,
758 const version_info* vi,
759 soinfo** found,
760 soinfo* caller,
761 void* handle) {
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800762 SymbolName symbol_name(name);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800763
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -0700764 auto& soinfo_list = ns->soinfo_list();
765 auto start = soinfo_list.begin();
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -0700766
767 if (handle == RTLD_NEXT) {
Dmitriy Ivanovb96ac412015-05-22 12:34:42 -0700768 if (caller == nullptr) {
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -0700769 return nullptr;
770 } else {
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -0700771 auto it = soinfo_list.find(caller);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700772 CHECK (it != soinfo_list.end());
773 start = ++it;
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -0700774 }
Elliott Hughescade4c32012-12-20 14:42:14 -0800775 }
776
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700777 const ElfW(Sym)* s = nullptr;
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -0700778 for (auto it = start, end = soinfo_list.end(); it != end; ++it) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700779 soinfo* si = *it;
Dmitriy Ivanov19133522015-06-02 17:36:54 -0700780 // Do not skip RTLD_LOCAL libraries in dlsym(RTLD_DEFAULT, ...)
Elliott Hughes5bc78c82016-11-16 11:35:43 -0800781 // if the library is opened by application with target api level < M.
Dmitriy Ivanov19133522015-06-02 17:36:54 -0700782 // See http://b/21565766
Elliott Hughes5bc78c82016-11-16 11:35:43 -0800783 if ((si->get_rtld_flags() & RTLD_GLOBAL) == 0 &&
784 si->get_target_sdk_version() >= __ANDROID_API_M__) {
Dmitriy Ivanove8ba50f2014-09-15 17:00:10 -0700785 continue;
786 }
787
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800788 if (!si->find_symbol_by_name(symbol_name, vi, &s)) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700789 return nullptr;
790 }
791
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700792 if (s != nullptr) {
Elliott Hughescade4c32012-12-20 14:42:14 -0800793 *found = si;
794 break;
Matt Fischer1698d9e2009-12-31 12:17:56 -0600795 }
Elliott Hughescade4c32012-12-20 14:42:14 -0800796 }
Matt Fischer1698d9e2009-12-31 12:17:56 -0600797
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700798 // If not found - use dlsym_handle_lookup for caller's
799 // local_group unless it is part of the global group in which
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -0700800 // case we already did it.
801 if (s == nullptr && caller != nullptr &&
802 (caller->get_rtld_flags() & RTLD_GLOBAL) == 0) {
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700803 return dlsym_handle_lookup(caller->get_local_group_root(),
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800804 (handle == RTLD_NEXT) ? caller : nullptr, found, symbol_name, vi);
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -0700805 }
806
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700807 if (s != nullptr) {
Elliott Hughesc00f2cb2013-10-04 17:01:33 -0700808 TRACE_TYPE(LOOKUP, "%s s->st_value = %p, found->base = %p",
809 name, reinterpret_cast<void*>(s->st_value), reinterpret_cast<void*>((*found)->base));
Elliott Hughescade4c32012-12-20 14:42:14 -0800810 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800811
Elliott Hughescade4c32012-12-20 14:42:14 -0800812 return s;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800813}
814
Kito Chengfa8c05d2013-03-12 14:58:06 +0800815soinfo* find_containing_library(const void* p) {
Elliott Hughes0266ae52014-02-10 17:46:57 -0800816 ElfW(Addr) address = reinterpret_cast<ElfW(Addr)>(p);
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700817 for (soinfo* si = solist_get_head(); si != nullptr; si = si->next) {
Kito Chengfa8c05d2013-03-12 14:58:06 +0800818 if (address >= si->base && address - si->base < si->size) {
819 return si;
Matt Fischere2a8b1f2009-12-31 12:17:40 -0600820 }
Kito Chengfa8c05d2013-03-12 14:58:06 +0800821 }
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700822 return nullptr;
Matt Fischere2a8b1f2009-12-31 12:17:40 -0600823}
824
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700825class ZipArchiveCache {
826 public:
827 ZipArchiveCache() {}
828 ~ZipArchiveCache();
829
830 bool get_or_open(const char* zip_path, ZipArchiveHandle* handle);
831 private:
832 DISALLOW_COPY_AND_ASSIGN(ZipArchiveCache);
833
834 std::unordered_map<std::string, ZipArchiveHandle> cache_;
835};
836
837bool ZipArchiveCache::get_or_open(const char* zip_path, ZipArchiveHandle* handle) {
838 std::string key(zip_path);
839
840 auto it = cache_.find(key);
841 if (it != cache_.end()) {
842 *handle = it->second;
843 return true;
844 }
845
846 int fd = TEMP_FAILURE_RETRY(open(zip_path, O_RDONLY | O_CLOEXEC));
847 if (fd == -1) {
848 return false;
849 }
850
851 if (OpenArchiveFd(fd, "", handle) != 0) {
852 // invalid zip-file (?)
Yabin Cui722072d2016-03-21 17:10:12 -0700853 CloseArchive(handle);
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700854 close(fd);
855 return false;
856 }
857
858 cache_[key] = *handle;
859 return true;
860}
861
862ZipArchiveCache::~ZipArchiveCache() {
Dmitriy Ivanov5dce8942015-10-13 12:14:16 -0700863 for (const auto& it : cache_) {
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700864 CloseArchive(it.second);
865 }
866}
867
868static int open_library_in_zipfile(ZipArchiveCache* zip_archive_cache,
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700869 const char* const input_path,
870 off64_t* file_offset, std::string* realpath) {
871 std::string normalized_path;
872 if (!normalize_path(input_path, &normalized_path)) {
873 return -1;
874 }
875
876 const char* const path = normalized_path.c_str();
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700877 TRACE("Trying zip file open from path \"%s\" -> normalized \"%s\"", input_path, path);
Simon Baldwinaef71952015-01-16 13:22:54 +0000878
Dmitriy Ivanov402a7502015-06-09 13:46:51 -0700879 // Treat an '!/' separator inside a path as the separator between the name
Simon Baldwinaef71952015-01-16 13:22:54 +0000880 // of the zip file on disk and the subdirectory to search within it.
Dmitriy Ivanov402a7502015-06-09 13:46:51 -0700881 // For example, if path is "foo.zip!/bar/bas/x.so", then we search for
Simon Baldwinaef71952015-01-16 13:22:54 +0000882 // "bar/bas/x.so" within "foo.zip".
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700883 const char* const separator = strstr(path, kZipFileSeparator);
Simon Baldwinaef71952015-01-16 13:22:54 +0000884 if (separator == nullptr) {
885 return -1;
Elliott Hughes124fae92012-10-31 14:20:03 -0700886 }
Simon Baldwinaef71952015-01-16 13:22:54 +0000887
888 char buf[512];
889 if (strlcpy(buf, path, sizeof(buf)) >= sizeof(buf)) {
890 PRINT("Warning: ignoring very long library path: %s", path);
891 return -1;
892 }
893
894 buf[separator - path] = '\0';
895
896 const char* zip_path = buf;
Dmitriy Ivanov402a7502015-06-09 13:46:51 -0700897 const char* file_path = &buf[separator - path + 2];
Simon Baldwinaef71952015-01-16 13:22:54 +0000898 int fd = TEMP_FAILURE_RETRY(open(zip_path, O_RDONLY | O_CLOEXEC));
899 if (fd == -1) {
900 return -1;
901 }
902
903 ZipArchiveHandle handle;
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700904 if (!zip_archive_cache->get_or_open(zip_path, &handle)) {
Simon Baldwinaef71952015-01-16 13:22:54 +0000905 // invalid zip-file (?)
906 close(fd);
907 return -1;
908 }
909
Simon Baldwinaef71952015-01-16 13:22:54 +0000910 ZipEntry entry;
911
Yusuke Sato56f40fb2015-06-25 14:56:07 -0700912 if (FindEntry(handle, ZipString(file_path), &entry) != 0) {
Simon Baldwinaef71952015-01-16 13:22:54 +0000913 // Entry was not found.
914 close(fd);
915 return -1;
916 }
917
918 // Check if it is properly stored
919 if (entry.method != kCompressStored || (entry.offset % PAGE_SIZE) != 0) {
920 close(fd);
921 return -1;
922 }
923
924 *file_offset = entry.offset;
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700925
926 if (realpath_fd(fd, realpath)) {
927 *realpath += separator;
928 } else {
929 PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.",
930 normalized_path.c_str());
931 *realpath = normalized_path;
932 }
933
Simon Baldwinaef71952015-01-16 13:22:54 +0000934 return fd;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800935}
936
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700937static bool format_path(char* buf, size_t buf_size, const char* path, const char* name) {
938 int n = __libc_format_buffer(buf, buf_size, "%s/%s", path, name);
939 if (n < 0 || n >= static_cast<int>(buf_size)) {
940 PRINT("Warning: ignoring very long library path: %s/%s", path, name);
941 return false;
942 }
Simon Baldwinaef71952015-01-16 13:22:54 +0000943
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700944 return true;
945}
946
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700947static int open_library_on_paths(ZipArchiveCache* zip_archive_cache,
948 const char* name, off64_t* file_offset,
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700949 const std::vector<std::string>& paths,
950 std::string* realpath) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700951 for (const auto& path : paths) {
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700952 char buf[512];
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700953 if (!format_path(buf, sizeof(buf), path.c_str(), name)) {
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700954 continue;
955 }
956
957 int fd = -1;
Dmitriy Ivanov730ed9d2015-07-16 04:52:06 -0700958 if (strstr(buf, kZipFileSeparator) != nullptr) {
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700959 fd = open_library_in_zipfile(zip_archive_cache, buf, file_offset, realpath);
Simon Baldwinaef71952015-01-16 13:22:54 +0000960 }
961
962 if (fd == -1) {
963 fd = TEMP_FAILURE_RETRY(open(buf, O_RDONLY | O_CLOEXEC));
964 if (fd != -1) {
965 *file_offset = 0;
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700966 if (!realpath_fd(fd, realpath)) {
967 PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.", buf);
968 *realpath = buf;
969 }
Simon Baldwinaef71952015-01-16 13:22:54 +0000970 }
971 }
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700972
973 if (fd != -1) {
974 return fd;
975 }
Simon Baldwinaef71952015-01-16 13:22:54 +0000976 }
977
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700978 return -1;
Simon Baldwinaef71952015-01-16 13:22:54 +0000979}
980
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700981static int open_library(android_namespace_t* ns,
982 ZipArchiveCache* zip_archive_cache,
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700983 const char* name, soinfo *needed_by,
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700984 off64_t* file_offset, std::string* realpath) {
Elliott Hughesca0c11b2013-03-12 10:40:45 -0700985 TRACE("[ opening %s ]", name);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800986
Elliott Hughes124fae92012-10-31 14:20:03 -0700987 // If the name contains a slash, we should attempt to open it directly and not search the paths.
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700988 if (strchr(name, '/') != nullptr) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700989 int fd = -1;
990
Dmitriy Ivanov730ed9d2015-07-16 04:52:06 -0700991 if (strstr(name, kZipFileSeparator) != nullptr) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700992 fd = open_library_in_zipfile(zip_archive_cache, name, file_offset, realpath);
993 }
994
995 if (fd == -1) {
996 fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_CLOEXEC));
Simon Baldwinaef71952015-01-16 13:22:54 +0000997 if (fd != -1) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700998 *file_offset = 0;
999 if (!realpath_fd(fd, realpath)) {
1000 PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.", name);
1001 *realpath = name;
1002 }
Simon Baldwinaef71952015-01-16 13:22:54 +00001003 }
1004 }
1005
Dmitriy Ivanove44fffd2015-03-17 17:12:18 -07001006 return fd;
Elliott Hughes124fae92012-10-31 14:20:03 -07001007 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001008
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001009 // Otherwise we try LD_LIBRARY_PATH first, and fall back to the default library path
1010 int fd = open_library_on_paths(zip_archive_cache, name, file_offset, ns->get_ld_library_paths(), realpath);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001011 if (fd == -1 && needed_by != nullptr) {
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001012 fd = open_library_on_paths(zip_archive_cache, name, file_offset, needed_by->get_dt_runpath(), realpath);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001013 // Check if the library is accessible
1014 if (fd != -1 && !ns->is_accessible(*realpath)) {
1015 fd = -1;
1016 }
Evgenii Stepanov68650822015-06-10 13:38:39 -07001017 }
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001018
Elliott Hughes124fae92012-10-31 14:20:03 -07001019 if (fd == -1) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001020 fd = open_library_on_paths(zip_archive_cache, name, file_offset, ns->get_default_library_paths(), realpath);
Elliott Hughes124fae92012-10-31 14:20:03 -07001021 }
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001022
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001023 // TODO(dimitry): workaround for http://b/26394120 (the grey-list)
1024 if (fd == -1 && ns != &g_default_namespace && is_greylisted(name, needed_by)) {
1025 // try searching for it on default_namespace default_library_path
1026 fd = open_library_on_paths(zip_archive_cache, name, file_offset,
1027 g_default_namespace.get_default_library_paths(), realpath);
1028 }
1029 // END OF WORKAROUND
1030
Elliott Hughes124fae92012-10-31 14:20:03 -07001031 return fd;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001032}
1033
Dimitry Ivanov3f660572016-09-09 10:00:39 -07001034const char* fix_dt_needed(const char* dt_needed, const char* sopath __unused) {
Dmitriy Ivanovd974e882015-05-27 18:29:41 -07001035#if !defined(__LP64__)
1036 // Work around incorrect DT_NEEDED entries for old apps: http://b/21364029
Elliott Hughes5bc78c82016-11-16 11:35:43 -08001037 if (get_application_target_sdk_version() < __ANDROID_API_M__) {
Dmitriy Ivanovd974e882015-05-27 18:29:41 -07001038 const char* bname = basename(dt_needed);
1039 if (bname != dt_needed) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001040 DL_WARN("library \"%s\" has invalid DT_NEEDED entry \"%s\"", sopath, dt_needed);
1041 add_dlwarning(sopath, "invalid DT_NEEDED entry", dt_needed);
Dmitriy Ivanovd974e882015-05-27 18:29:41 -07001042 }
1043
1044 return bname;
1045 }
1046#endif
1047 return dt_needed;
1048}
1049
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001050template<typename F>
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001051static void for_each_dt_needed(const ElfReader& elf_reader, F action) {
1052 for (const ElfW(Dyn)* d = elf_reader.dynamic(); d->d_tag != DT_NULL; ++d) {
1053 if (d->d_tag == DT_NEEDED) {
1054 action(fix_dt_needed(elf_reader.get_string(d->d_un.d_val), elf_reader.name()));
1055 }
1056 }
1057}
1058
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001059static bool load_library(android_namespace_t* ns,
1060 LoadTask* task,
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001061 LoadTaskList* load_tasks,
1062 int rtld_flags,
1063 const std::string& realpath) {
1064 off64_t file_offset = task->get_file_offset();
1065 const char* name = task->get_name();
1066 const android_dlextinfo* extinfo = task->get_extinfo();
1067
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001068 if ((file_offset % PAGE_SIZE) != 0) {
Dmitriy Ivanova6c12792014-10-21 12:09:18 -07001069 DL_ERR("file offset for the library \"%s\" is not page-aligned: %" PRId64, name, file_offset);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001070 return false;
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001071 }
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001072 if (file_offset < 0) {
1073 DL_ERR("file offset for the library \"%s\" is negative: %" PRId64, name, file_offset);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001074 return false;
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001075 }
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001076
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001077 struct stat file_stat;
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001078 if (TEMP_FAILURE_RETRY(fstat(task->get_fd(), &file_stat)) != 0) {
Dmitriy Ivanova6c12792014-10-21 12:09:18 -07001079 DL_ERR("unable to stat file for the library \"%s\": %s", name, strerror(errno));
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001080 return false;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001081 }
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001082 if (file_offset >= file_stat.st_size) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07001083 DL_ERR("file offset for the library \"%s\" >= file size: %" PRId64 " >= %" PRId64,
1084 name, file_offset, file_stat.st_size);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001085 return false;
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001086 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001087
1088 // Check for symlink and other situations where
Dmitriy Ivanov9b821362015-04-02 16:03:56 -07001089 // file can have different names, unless ANDROID_DLEXT_FORCE_LOAD is set
1090 if (extinfo == nullptr || (extinfo->flags & ANDROID_DLEXT_FORCE_LOAD) == 0) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001091 auto predicate = [&](soinfo* si) {
1092 return si->get_st_dev() != 0 &&
1093 si->get_st_ino() != 0 &&
1094 si->get_st_dev() == file_stat.st_dev &&
1095 si->get_st_ino() == file_stat.st_ino &&
1096 si->get_file_offset() == file_offset;
1097 };
1098
1099 soinfo* si = ns->soinfo_list().find_if(predicate);
1100
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001101 if (si != nullptr) {
1102 TRACE("library \"%s\" is already loaded under different name/path \"%s\" - "
1103 "will return existing soinfo", name, si->get_realpath());
1104 task->set_soinfo(si);
1105 return true;
1106 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001107 }
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07001108
Dmitriy Ivanove8ba50f2014-09-15 17:00:10 -07001109 if ((rtld_flags & RTLD_NOLOAD) != 0) {
Dmitriy Ivanova6ac54a2014-09-09 10:21:42 -07001110 DL_ERR("library \"%s\" wasn't loaded and RTLD_NOLOAD prevented it", name);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001111 return false;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001112 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001113
Dimitry Ivanov22840aa2015-12-04 18:28:49 -08001114 if (!ns->is_accessible(realpath)) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001115 // TODO(dimitry): workaround for http://b/26394120 - the grey-list
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001116
1117 // TODO(dimitry) before O release: add a namespace attribute to have this enabled
1118 // only for classloader-namespaces
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001119 const soinfo* needed_by = task->is_dt_needed() ? task->get_needed_by() : nullptr;
1120 if (is_greylisted(name, needed_by)) {
1121 // print warning only if needed by non-system library
1122 if (needed_by == nullptr || !is_system_library(needed_by->get_realpath())) {
1123 const soinfo* needed_or_dlopened_by = task->get_needed_by();
1124 const char* sopath = needed_or_dlopened_by == nullptr ? "(unknown)" :
1125 needed_or_dlopened_by->get_realpath();
1126 DL_WARN("library \"%s\" (\"%s\") needed or dlopened by \"%s\" is not accessible for the namespace \"%s\""
1127 " - the access is temporarily granted as a workaround for http://b/26394120, note that the access"
1128 " will be removed in future releases of Android.",
1129 name, realpath.c_str(), sopath, ns->get_name());
1130 add_dlwarning(sopath, "unauthorized access to", name);
1131 }
1132 } else {
1133 // do not load libraries if they are not accessible for the specified namespace.
1134 const char* needed_or_dlopened_by = task->get_needed_by() == nullptr ?
1135 "(unknown)" :
1136 task->get_needed_by()->get_realpath();
Dimitry Ivanovd17a3772016-03-01 13:11:28 -08001137
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001138 DL_ERR("library \"%s\" needed or dlopened by \"%s\" is not accessible for the namespace \"%s\"",
1139 name, needed_or_dlopened_by, ns->get_name());
Dimitry Ivanovd17a3772016-03-01 13:11:28 -08001140
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001141 PRINT("library \"%s\" (\"%s\") needed or dlopened by \"%s\" is not accessible for the"
1142 " namespace: [name=\"%s\", ld_library_paths=\"%s\", default_library_paths=\"%s\","
1143 " permitted_paths=\"%s\"]",
1144 name, realpath.c_str(),
1145 needed_or_dlopened_by,
1146 ns->get_name(),
1147 android::base::Join(ns->get_ld_library_paths(), ':').c_str(),
1148 android::base::Join(ns->get_default_library_paths(), ':').c_str(),
1149 android::base::Join(ns->get_permitted_paths(), ':').c_str());
1150 return false;
1151 }
Dimitry Ivanov22840aa2015-12-04 18:28:49 -08001152 }
1153
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001154 soinfo* si = soinfo_alloc(ns, realpath.c_str(), &file_stat, file_offset, rtld_flags);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001155 if (si == nullptr) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001156 return false;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001157 }
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07001158
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001159 task->set_soinfo(si);
1160
1161 // Read the ELF header and some of the segments.
1162 if (!task->read(realpath.c_str(), file_stat.st_size)) {
Dmitriy Ivanovfd7a91e2015-11-06 10:44:37 -08001163 soinfo_free(si);
1164 task->set_soinfo(nullptr);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001165 return false;
1166 }
1167
1168 // find and set DT_RUNPATH and dt_soname
1169 // Note that these field values are temporary and are
1170 // going to be overwritten on soinfo::prelink_image
1171 // with values from PT_LOAD segments.
1172 const ElfReader& elf_reader = task->get_elf_reader();
1173 for (const ElfW(Dyn)* d = elf_reader.dynamic(); d->d_tag != DT_NULL; ++d) {
1174 if (d->d_tag == DT_RUNPATH) {
1175 si->set_dt_runpath(elf_reader.get_string(d->d_un.d_val));
1176 }
1177 if (d->d_tag == DT_SONAME) {
1178 si->set_soname(elf_reader.get_string(d->d_un.d_val));
1179 }
1180 }
1181
1182 for_each_dt_needed(task->get_elf_reader(), [&](const char* name) {
1183 load_tasks->push_back(LoadTask::create(name, si, task->get_readers_map()));
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001184 });
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07001185
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001186 return true;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001187}
1188
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001189static bool load_library(android_namespace_t* ns,
1190 LoadTask* task,
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001191 ZipArchiveCache* zip_archive_cache,
1192 LoadTaskList* load_tasks,
1193 int rtld_flags) {
1194 const char* name = task->get_name();
1195 soinfo* needed_by = task->get_needed_by();
1196 const android_dlextinfo* extinfo = task->get_extinfo();
1197
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001198 off64_t file_offset;
1199 std::string realpath;
Spencer Low0346ad72015-04-22 18:06:51 -07001200 if (extinfo != nullptr && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) {
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001201 file_offset = 0;
Spencer Low0346ad72015-04-22 18:06:51 -07001202 if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
1203 file_offset = extinfo->library_fd_offset;
1204 }
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001205
1206 if (!realpath_fd(extinfo->library_fd, &realpath)) {
1207 PRINT("warning: unable to get realpath for the library \"%s\" by extinfo->library_fd. "
1208 "Will use given name.", name);
1209 realpath = name;
1210 }
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001211
1212 task->set_fd(extinfo->library_fd, false);
1213 task->set_file_offset(file_offset);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001214 return load_library(ns, task, load_tasks, rtld_flags, realpath);
Spencer Low0346ad72015-04-22 18:06:51 -07001215 }
1216
1217 // Open the file.
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001218 int fd = open_library(ns, zip_archive_cache, name, needed_by, &file_offset, &realpath);
Spencer Low0346ad72015-04-22 18:06:51 -07001219 if (fd == -1) {
1220 DL_ERR("library \"%s\" not found", name);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001221 return false;
Spencer Low0346ad72015-04-22 18:06:51 -07001222 }
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001223
1224 task->set_fd(fd, true);
1225 task->set_file_offset(file_offset);
1226
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001227 return load_library(ns, task, load_tasks, rtld_flags, realpath);
Spencer Low0346ad72015-04-22 18:06:51 -07001228}
1229
Dimitry Ivanov3bd90612017-02-01 08:54:43 -08001230// Returns true if library was found and false otherwise
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001231static bool find_loaded_library_by_soname(android_namespace_t* ns,
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -07001232 const char* name, soinfo** candidate) {
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001233 *candidate = nullptr;
1234
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07001235 // Ignore filename with path.
1236 if (strchr(name, '/') != nullptr) {
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001237 return false;
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07001238 }
1239
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001240 return !ns->soinfo_list().visit([&](soinfo* si) {
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07001241 const char* soname = si->get_soname();
1242 if (soname != nullptr && (strcmp(name, soname) == 0)) {
Dimitry Ivanov3bd90612017-02-01 08:54:43 -08001243 *candidate = si;
1244 return false;
Ard Biesheuvel12c78bb2012-08-14 12:30:09 +02001245 }
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001246
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001247 return true;
1248 });
Ard Biesheuvel12c78bb2012-08-14 12:30:09 +02001249}
1250
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001251static std::string resolve_soname(const std::string& name) {
1252 // We assume that soname equals to basename here
1253
1254 // TODO(dimitry): consider having honest absolute-path -> soname resolution
1255 // note that since we might end up refusing to load this library because
1256 // it is not in shared libs list we need to get the soname without actually loading
1257 // the library.
1258 //
1259 // On the other hand there are several places where we already assume that
1260 // soname == basename in particular for any not-loaded library mentioned
1261 // in DT_NEEDED list.
1262 return basename(name.c_str());
1263}
1264
1265
1266static bool find_library_in_linked_namespace(const android_namespace_link_t& namespace_link,
1267 LoadTask* task,
1268 int rtld_flags) {
1269 android_namespace_t* ns = namespace_link.linked_namespace();
1270
1271 soinfo* candidate;
1272 bool loaded = false;
1273
1274 std::string soname;
1275 if (find_loaded_library_by_soname(ns, task->get_name(), &candidate)) {
1276 loaded = true;
1277 soname = candidate->get_soname();
1278 } else {
1279 soname = resolve_soname(task->get_name());
1280 }
1281
1282 if (!namespace_link.is_accessible(soname.c_str())) {
1283 // the library is not accessible via namespace_link
1284 return false;
1285 }
1286
1287 // if library is already loaded - return it
1288 if (loaded) {
1289 task->set_soinfo(candidate);
1290 return true;
1291 }
1292
1293 // try to load the library - once namespace boundary is crossed
1294 // we need to load a library within separate load_group
1295 // to avoid using symbols from foreign namespace while.
1296 //
1297 // All symbols during relocation should be resolved within a
1298 // namespace to preserve library locality to a namespace.
1299 const char* name = task->get_name();
1300 if (find_libraries(ns,
1301 task->get_needed_by(),
1302 &name,
1303 1,
1304 &candidate,
1305 nullptr /* ld_preloads */,
1306 0 /* ld_preload_count*/,
1307 rtld_flags,
1308 nullptr /* extinfo*/,
1309 false /* add_as_children */,
1310 false /* search_linked_namespaces */)) {
1311 task->set_soinfo(candidate);
1312 return true;
1313 }
1314
1315 return false;
1316}
1317
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001318static bool find_library_internal(android_namespace_t* ns,
1319 LoadTask* task,
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001320 ZipArchiveCache* zip_archive_cache,
1321 LoadTaskList* load_tasks,
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001322 int rtld_flags,
1323 bool search_linked_namespaces) {
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001324 soinfo* candidate;
1325
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001326 if (find_loaded_library_by_soname(ns, task->get_name(), &candidate)) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001327 task->set_soinfo(candidate);
1328 return true;
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001329 }
Dmitriy Ivanovb648a8a2014-05-19 15:06:58 -07001330
1331 // Library might still be loaded, the accurate detection
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001332 // of this fact is done by load_library.
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001333 TRACE("[ \"%s\" find_loaded_library_by_soname failed (*candidate=%s@%p). Trying harder...]",
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001334 task->get_name(), candidate == nullptr ? "n/a" : candidate->get_realpath(), candidate);
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001335
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001336 if (load_library(ns, task, zip_archive_cache, load_tasks, rtld_flags)) {
1337 return true;
1338 }
1339
1340 if (search_linked_namespaces) {
1341 // if a library was not found - look into linked namespaces
1342 for (auto& linked_namespace : ns->linked_namespaces()) {
1343 if (find_library_in_linked_namespace(linked_namespace,
1344 task,
1345 rtld_flags)) {
1346 return true;
1347 }
1348 }
1349 }
1350
1351 return false;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001352}
1353
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001354static void soinfo_unload(soinfo* si);
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001355static void soinfo_unload(soinfo* soinfos[], size_t count);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001356
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001357// TODO: this is slightly unusual way to construct
1358// the global group for relocation. Not every RTLD_GLOBAL
1359// library is included in this group for backwards-compatibility
1360// reasons.
1361//
1362// This group consists of the main executable, LD_PRELOADs
1363// and libraries with the DF_1_GLOBAL flag set.
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001364static soinfo_list_t make_global_group(android_namespace_t* ns) {
1365 soinfo_list_t global_group;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001366 ns->soinfo_list().for_each([&](soinfo* si) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001367 if ((si->get_dt_flags_1() & DF_1_GLOBAL) != 0) {
1368 global_group.push_back(si);
1369 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001370 });
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001371
1372 return global_group;
1373}
1374
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07001375// This function provides a list of libraries to be shared
1376// by the namespace. For the default namespace this is the global
1377// group (see make_global_group). For all others this is a group
1378// of RTLD_GLOBAL libraries (which includes the global group from
1379// the default namespace).
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001380static soinfo_list_t get_shared_group(android_namespace_t* ns) {
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07001381 if (ns == &g_default_namespace) {
1382 return make_global_group(ns);
1383 }
1384
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001385 soinfo_list_t shared_group;
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07001386 ns->soinfo_list().for_each([&](soinfo* si) {
1387 if ((si->get_rtld_flags() & RTLD_GLOBAL) != 0) {
1388 shared_group.push_back(si);
1389 }
1390 });
1391
1392 return shared_group;
1393}
1394
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001395static void shuffle(std::vector<LoadTask*>* v) {
1396 for (size_t i = 0, size = v->size(); i < size; ++i) {
1397 size_t n = size - i;
1398 size_t r = arc4random_uniform(n);
1399 std::swap((*v)[n-1], (*v)[r]);
1400 }
1401}
1402
Evgenii Stepanov0cdef7e2015-07-06 17:56:31 -07001403// add_as_children - add first-level loaded libraries (i.e. library_names[], but
1404// not their transitive dependencies) as children of the start_with library.
1405// This is false when find_libraries is called for dlopen(), when newly loaded
1406// libraries must form a disjoint tree.
Dimitry Ivanov3f660572016-09-09 10:00:39 -07001407bool find_libraries(android_namespace_t* ns,
1408 soinfo* start_with,
1409 const char* const library_names[],
1410 size_t library_names_count,
1411 soinfo* soinfos[],
1412 std::vector<soinfo*>* ld_preloads,
1413 size_t ld_preloads_count,
1414 int rtld_flags,
1415 const android_dlextinfo* extinfo,
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001416 bool add_as_children,
1417 bool search_linked_namespaces) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001418 // Step 0: prepare.
1419 LoadTaskList load_tasks;
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001420 std::unordered_map<const soinfo*, ElfReader> readers_map;
1421
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001422 for (size_t i = 0; i < library_names_count; ++i) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001423 const char* name = library_names[i];
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001424 load_tasks.push_back(LoadTask::create(name, start_with, &readers_map));
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001425 }
1426
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001427 // Construct global_group.
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001428 soinfo_list_t global_group = make_global_group(ns);
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001429
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001430 // If soinfos array is null allocate one on stack.
1431 // The array is needed in case of failure; for example
1432 // when library_names[] = {libone.so, libtwo.so} and libone.so
1433 // is loaded correctly but libtwo.so failed for some reason.
1434 // In this case libone.so should be unloaded on return.
1435 // See also implementation of failure_guard below.
1436
1437 if (soinfos == nullptr) {
1438 size_t soinfos_size = sizeof(soinfo*)*library_names_count;
1439 soinfos = reinterpret_cast<soinfo**>(alloca(soinfos_size));
1440 memset(soinfos, 0, soinfos_size);
1441 }
1442
1443 // list of libraries to link - see step 2.
1444 size_t soinfos_count = 0;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001445
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001446 auto scope_guard = make_scope_guard([&]() {
1447 for (LoadTask* t : load_tasks) {
1448 LoadTask::deleter(t);
1449 }
1450 });
1451
Dmitriy Ivanovd9ff7222014-09-08 16:22:22 -07001452 auto failure_guard = make_scope_guard([&]() {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001453 // Housekeeping
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001454 soinfo_unload(soinfos, soinfos_count);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001455 });
1456
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001457 ZipArchiveCache zip_archive_cache;
1458
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001459 // Step 1: expand the list of load_tasks to include
1460 // all DT_NEEDED libraries (do not load them just yet)
1461 for (size_t i = 0; i<load_tasks.size(); ++i) {
1462 LoadTask* task = load_tasks[i];
Evgenii Stepanov68650822015-06-10 13:38:39 -07001463 soinfo* needed_by = task->get_needed_by();
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001464
Dmitriy Ivanovedfc9f62015-09-02 16:32:02 -07001465 bool is_dt_needed = needed_by != nullptr && (needed_by != start_with || add_as_children);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001466 task->set_extinfo(is_dt_needed ? nullptr : extinfo);
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001467 task->set_dt_needed(is_dt_needed);
Dmitriy Ivanovedfc9f62015-09-02 16:32:02 -07001468
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001469 if (!find_library_internal(ns,
1470 task,
1471 &zip_archive_cache,
1472 &load_tasks,
1473 rtld_flags,
1474 search_linked_namespaces || is_dt_needed)) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001475 return false;
1476 }
1477
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001478 soinfo* si = task->get_soinfo();
1479
Dmitriy Ivanovedfc9f62015-09-02 16:32:02 -07001480 if (is_dt_needed) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001481 needed_by->add_child(si);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001482
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001483 if (si->is_linked()) {
1484 si->increment_ref_count();
1485 }
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001486 }
1487
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001488 // When ld_preloads is not null, the first
1489 // ld_preloads_count libs are in fact ld_preloads.
1490 if (ld_preloads != nullptr && soinfos_count < ld_preloads_count) {
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07001491 ld_preloads->push_back(si);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001492 }
1493
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001494 if (soinfos_count < library_names_count) {
1495 soinfos[soinfos_count++] = si;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001496 }
1497 }
1498
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001499 // Step 2: Load libraries in random order (see b/24047022)
1500 LoadTaskList load_list;
1501 for (auto&& task : load_tasks) {
1502 soinfo* si = task->get_soinfo();
1503 auto pred = [&](const LoadTask* t) {
1504 return t->get_soinfo() == si;
1505 };
1506
1507 if (!si->is_linked() &&
1508 std::find_if(load_list.begin(), load_list.end(), pred) == load_list.end() ) {
1509 load_list.push_back(task);
1510 }
1511 }
1512 shuffle(&load_list);
1513
1514 for (auto&& task : load_list) {
1515 if (!task->load()) {
1516 return false;
1517 }
1518 }
1519
1520 // Step 3: pre-link all DT_NEEDED libraries in breadth first order.
1521 for (auto&& task : load_tasks) {
1522 soinfo* si = task->get_soinfo();
1523 if (!si->is_linked() && !si->prelink_image()) {
1524 return false;
1525 }
1526 }
1527
1528 // Step 4: Add LD_PRELOADed libraries to the global group for
1529 // future runs. There is no need to explicitly add them to
1530 // the global group for this run because they are going to
1531 // appear in the local group in the correct order.
1532 if (ld_preloads != nullptr) {
1533 for (auto&& si : *ld_preloads) {
1534 si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL);
1535 }
1536 }
1537
1538
1539 // Step 5: link libraries.
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001540 soinfo_list_t local_group;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001541 walk_dependencies_tree(
Evgenii Stepanov0cdef7e2015-07-06 17:56:31 -07001542 (start_with != nullptr && add_as_children) ? &start_with : soinfos,
1543 (start_with != nullptr && add_as_children) ? 1 : soinfos_count,
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001544 [&] (soinfo* si) {
1545 local_group.push_back(si);
1546 return true;
1547 });
1548
1549 bool linked = local_group.visit([&](soinfo* si) {
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001550 if (!si->is_linked()) {
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -07001551 if (!si->link_image(global_group, local_group, extinfo) ||
1552 !get_cfi_shadow()->AfterLoad(si, solist_get_head())) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001553 return false;
1554 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001555 }
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001556
1557 return true;
1558 });
1559
1560 if (linked) {
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001561 local_group.for_each([](soinfo* si) {
1562 if (!si->is_linked()) {
1563 si->set_linked();
1564 }
1565 });
1566
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001567 failure_guard.disable();
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001568 }
1569
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001570 return linked;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001571}
1572
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001573static soinfo* find_library(android_namespace_t* ns,
1574 const char* name, int rtld_flags,
Evgenii Stepanov0cdef7e2015-07-06 17:56:31 -07001575 const android_dlextinfo* extinfo,
1576 soinfo* needed_by) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001577 soinfo* si;
1578
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001579 if (name == nullptr) {
Dimitry Ivanov3f660572016-09-09 10:00:39 -07001580 si = solist_get_somain();
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001581 } else if (!find_libraries(ns,
1582 needed_by,
1583 &name,
1584 1,
1585 &si,
1586 nullptr,
1587 0,
1588 rtld_flags,
1589 extinfo,
1590 false /* add_as_children */,
1591 true /* search_linked_namespaces */)) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001592 return nullptr;
1593 }
1594
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001595 si->increment_ref_count();
1596
Elliott Hughesd23736e2012-11-01 15:16:56 -07001597 return si;
1598}
Elliott Hughesbedfe382012-08-14 14:07:59 -07001599
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001600static void soinfo_unload(soinfo* root) {
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001601 if (root->is_linked()) {
1602 root = root->get_local_group_root();
1603 }
1604
1605 if (!root->can_unload()) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001606 TRACE("not unloading \"%s\" - the binary is flagged with NODELETE", root->get_realpath());
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -07001607 return;
1608 }
1609
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001610 soinfo_unload(&root, 1);
1611}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001612
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001613static void soinfo_unload(soinfo* soinfos[], size_t count) {
1614 // Note that the library can be loaded but not linked;
1615 // in which case there is no root but we still need
1616 // to walk the tree and unload soinfos involved.
1617 //
1618 // This happens on unsuccessful dlopen, when one of
1619 // the DT_NEEDED libraries could not be linked/found.
1620 if (count == 0) {
1621 return;
1622 }
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001623
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001624 soinfo_list_t unload_list;
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001625 for (size_t i = 0; i < count; ++i) {
1626 soinfo* si = soinfos[i];
Dmitriy Ivanov5ae82cb2014-12-02 17:08:42 -08001627
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001628 if (si->can_unload()) {
1629 size_t ref_count = si->is_linked() ? si->decrement_ref_count() : 0;
1630 if (ref_count == 0) {
1631 unload_list.push_back(si);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001632 } else {
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001633 TRACE("not unloading '%s' group, decrementing ref_count to %zd",
1634 si->get_realpath(), ref_count);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001635 }
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001636 } else {
1637 TRACE("not unloading '%s' - the binary is flagged with NODELETE", si->get_realpath());
1638 return;
1639 }
1640 }
1641
1642 // This is used to identify soinfos outside of the load-group
1643 // note that we cannot have > 1 in the array and have any of them
1644 // linked. This is why we can safely use the first one.
1645 soinfo* root = soinfos[0];
1646
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001647 soinfo_list_t local_unload_list;
1648 soinfo_list_t external_unload_list;
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001649 soinfo* si = nullptr;
1650
1651 while ((si = unload_list.pop_front()) != nullptr) {
1652 if (local_unload_list.contains(si)) {
1653 continue;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001654 }
Elliott Hughesd23736e2012-11-01 15:16:56 -07001655
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001656 local_unload_list.push_back(si);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001657
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001658 if (si->has_min_version(0)) {
1659 soinfo* child = nullptr;
1660 while ((child = si->get_children().pop_front()) != nullptr) {
1661 TRACE("%s@%p needs to unload %s@%p", si->get_realpath(), si,
1662 child->get_realpath(), child);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001663
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001664 if (local_unload_list.contains(child)) {
1665 continue;
1666 } else if (child->is_linked() && child->get_local_group_root() != root) {
1667 external_unload_list.push_back(child);
1668 } else {
1669 unload_list.push_front(child);
1670 }
1671 }
1672 } else {
1673#if !defined(__work_around_b_24465209__)
1674 __libc_fatal("soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
1675#else
1676 PRINT("warning: soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
1677 for_each_dt_needed(si, [&] (const char* library_name) {
1678 TRACE("deprecated (old format of soinfo): %s needs to unload %s",
1679 si->get_realpath(), library_name);
1680
1681 soinfo* needed = find_library(si->get_primary_namespace(),
1682 library_name, RTLD_NOLOAD, nullptr, nullptr);
1683
1684 if (needed != nullptr) {
1685 // Not found: for example if symlink was deleted between dlopen and dlclose
1686 // Since we cannot really handle errors at this point - print and continue.
1687 PRINT("warning: couldn't find %s needed by %s on unload.",
1688 library_name, si->get_realpath());
1689 return;
1690 } else if (local_unload_list.contains(needed)) {
1691 // already visited
1692 return;
1693 } else if (needed->is_linked() && needed->get_local_group_root() != root) {
1694 // external group
1695 external_unload_list.push_back(needed);
1696 } else {
1697 // local group
1698 unload_list.push_front(needed);
1699 }
1700 });
1701#endif
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001702 }
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001703 }
1704
1705 local_unload_list.for_each([](soinfo* si) {
1706 si->call_destructors();
1707 });
1708
1709 while ((si = local_unload_list.pop_front()) != nullptr) {
1710 notify_gdb_of_unload(si);
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -07001711 get_cfi_shadow()->BeforeUnload(si);
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001712 soinfo_free(si);
1713 }
1714
1715 while ((si = external_unload_list.pop_front()) != nullptr) {
1716 soinfo_unload(si);
Dmitriy Ivanova2547052014-11-18 12:03:09 -08001717 }
1718}
1719
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001720static std::string symbol_display_name(const char* sym_name, const char* sym_ver) {
1721 if (sym_ver == nullptr) {
1722 return sym_name;
1723 }
1724
Dimitry Ivanov9cf99cb2015-12-11 14:22:24 -08001725 return std::string(sym_name) + ", version " + sym_ver;
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001726}
1727
Dimitry Ivanovaca299a2016-04-11 12:42:58 -07001728static android_namespace_t* get_caller_namespace(soinfo* caller) {
1729 return caller != nullptr ? caller->get_primary_namespace() : g_anonymous_namespace;
1730}
1731
Elliott Hughesa4aafd12014-01-13 16:37:47 -08001732void do_android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size) {
Christopher Ferris052fa3a2014-08-26 20:48:11 -07001733 // Use basic string manipulation calls to avoid snprintf.
1734 // snprintf indirectly calls pthread_getspecific to get the size of a buffer.
1735 // When debug malloc is enabled, this call returns 0. This in turn causes
1736 // snprintf to do nothing, which causes libraries to fail to load.
1737 // See b/17302493 for further details.
1738 // Once the above bug is fixed, this code can be modified to use
1739 // snprintf again.
Evgenii Stepanovd640b222015-07-10 17:54:01 -07001740 size_t required_len = 0;
1741 for (size_t i = 0; g_default_ld_paths[i] != nullptr; ++i) {
1742 required_len += strlen(g_default_ld_paths[i]) + 1;
1743 }
Christopher Ferris052fa3a2014-08-26 20:48:11 -07001744 if (buffer_size < required_len) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07001745 __libc_fatal("android_get_LD_LIBRARY_PATH failed, buffer too small: "
1746 "buffer len %zu, required len %zu", buffer_size, required_len);
Christopher Ferris052fa3a2014-08-26 20:48:11 -07001747 }
Evgenii Stepanovd640b222015-07-10 17:54:01 -07001748 char* end = buffer;
1749 for (size_t i = 0; g_default_ld_paths[i] != nullptr; ++i) {
1750 if (i > 0) *end++ = ':';
1751 end = stpcpy(end, g_default_ld_paths[i]);
1752 }
Elliott Hughesa4aafd12014-01-13 16:37:47 -08001753}
1754
Elliott Hughescade4c32012-12-20 14:42:14 -08001755void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path) {
Nick Kralevich6bb01b62015-03-07 13:37:05 -08001756 parse_LD_LIBRARY_PATH(ld_library_path);
Elliott Hughescade4c32012-12-20 14:42:14 -08001757}
1758
Dimitry Ivanovb996d602016-07-11 18:11:39 -07001759static std::string android_dlextinfo_to_string(const android_dlextinfo* info) {
1760 if (info == nullptr) {
1761 return "(null)";
1762 }
1763
1764 return android::base::StringPrintf("[flags=0x%" PRIx64 ","
1765 " reserved_addr=%p,"
1766 " reserved_size=0x%zx,"
1767 " relro_fd=%d,"
1768 " library_fd=%d,"
1769 " library_fd_offset=0x%" PRIx64 ","
1770 " library_namespace=%s@%p]",
1771 info->flags,
1772 info->reserved_addr,
1773 info->reserved_size,
1774 info->relro_fd,
1775 info->library_fd,
1776 info->library_fd_offset,
1777 (info->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0 ?
1778 (info->library_namespace != nullptr ?
1779 info->library_namespace->get_name() : "(null)") : "(n/a)",
1780 (info->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0 ?
1781 info->library_namespace : nullptr);
1782}
1783
Dimitry Ivanovd9e427c2016-11-22 16:55:25 -08001784void* do_dlopen(const char* name, int flags,
1785 const android_dlextinfo* extinfo,
1786 const void* caller_addr) {
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001787 soinfo* const caller = find_containing_library(caller_addr);
Dimitry Ivanovb996d602016-07-11 18:11:39 -07001788 android_namespace_t* ns = get_caller_namespace(caller);
1789
1790 LD_LOG(kLogDlopen,
1791 "dlopen(name=\"%s\", flags=0x%x, extinfo=%s, caller=\"%s\", caller_ns=%s@%p) ...",
1792 name,
1793 flags,
1794 android_dlextinfo_to_string(extinfo).c_str(),
1795 caller == nullptr ? "(null)" : caller->get_realpath(),
1796 ns == nullptr ? "(null)" : ns->get_name(),
1797 ns);
1798
1799 auto failure_guard = make_scope_guard([&]() {
1800 LD_LOG(kLogDlopen, "... dlopen failed: %s", linker_get_error_buffer());
1801 });
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001802
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -07001803 if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL|RTLD_NODELETE|RTLD_NOLOAD)) != 0) {
Elliott Hughese66190d2012-12-18 15:57:55 -08001804 DL_ERR("invalid flags to dlopen: %x", flags);
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07001805 return nullptr;
Elliott Hughese66190d2012-12-18 15:57:55 -08001806 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001807
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001808 if (extinfo != nullptr) {
1809 if ((extinfo->flags & ~(ANDROID_DLEXT_VALID_FLAG_BITS)) != 0) {
1810 DL_ERR("invalid extended flags to android_dlopen_ext: 0x%" PRIx64, extinfo->flags);
1811 return nullptr;
1812 }
Dmitriy Ivanov126af752015-10-07 16:34:20 -07001813
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001814 if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) == 0 &&
Dmitriy Ivanova6c12792014-10-21 12:09:18 -07001815 (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07001816 DL_ERR("invalid extended flag combination (ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET without "
1817 "ANDROID_DLEXT_USE_LIBRARY_FD): 0x%" PRIx64, extinfo->flags);
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001818 return nullptr;
1819 }
Dmitriy Ivanov126af752015-10-07 16:34:20 -07001820
1821 if ((extinfo->flags & ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS) != 0 &&
1822 (extinfo->flags & (ANDROID_DLEXT_RESERVED_ADDRESS | ANDROID_DLEXT_RESERVED_ADDRESS_HINT)) != 0) {
1823 DL_ERR("invalid extended flag combination: ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS is not "
1824 "compatible with ANDROID_DLEXT_RESERVED_ADDRESS/ANDROID_DLEXT_RESERVED_ADDRESS_HINT");
1825 return nullptr;
1826 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001827
1828 if ((extinfo->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0) {
1829 if (extinfo->library_namespace == nullptr) {
1830 DL_ERR("ANDROID_DLEXT_USE_NAMESPACE is set but extinfo->library_namespace is null");
1831 return nullptr;
1832 }
1833 ns = extinfo->library_namespace;
1834 }
Torne (Richard Coles)012cb452014-02-06 14:34:21 +00001835 }
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -08001836
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -07001837 std::string asan_name_holder;
1838
1839 const char* translated_name = name;
Dimitry Ivanov6c14f862016-12-05 13:35:47 -08001840 if (g_is_asan && translated_name != nullptr && translated_name[0] == '/') {
1841 char translated_path[PATH_MAX];
1842 if (realpath(translated_name, translated_path) != nullptr) {
1843 if (file_is_in_dir(translated_path, kSystemLibDir)) {
1844 asan_name_holder = std::string(kAsanSystemLibDir) + "/" + basename(translated_path);
1845 if (file_exists(asan_name_holder.c_str())) {
1846 translated_name = asan_name_holder.c_str();
1847 PRINT("linker_asan dlopen translating \"%s\" -> \"%s\"", name, translated_name);
1848 }
1849 } else if (file_is_in_dir(translated_path, kVendorLibDir)) {
1850 asan_name_holder = std::string(kAsanVendorLibDir) + "/" + basename(translated_path);
1851 if (file_exists(asan_name_holder.c_str())) {
1852 translated_name = asan_name_holder.c_str();
1853 PRINT("linker_asan dlopen translating \"%s\" -> \"%s\"", name, translated_name);
1854 }
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -07001855 }
1856 }
1857 }
1858
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -08001859 ProtectedDataGuard guard;
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -07001860 soinfo* si = find_library(ns, translated_name, flags, extinfo, caller);
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07001861 if (si != nullptr) {
Dimitry Ivanovb996d602016-07-11 18:11:39 -07001862 void* handle = si->to_handle();
1863 LD_LOG(kLogDlopen,
Dimitry Ivanovae4a0c12016-11-21 10:44:35 -08001864 "... dlopen calling constructors: realpath=\"%s\", soname=\"%s\", handle=%p",
1865 si->get_realpath(), si->get_soname(), handle);
1866 si->call_constructors();
1867 failure_guard.disable();
1868 LD_LOG(kLogDlopen,
Dimitry Ivanovb996d602016-07-11 18:11:39 -07001869 "... dlopen successful: realpath=\"%s\", soname=\"%s\", handle=%p",
1870 si->get_realpath(), si->get_soname(), handle);
1871 return handle;
Elliott Hughesd23736e2012-11-01 15:16:56 -07001872 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001873
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001874 return nullptr;
Elliott Hughesd23736e2012-11-01 15:16:56 -07001875}
1876
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001877int do_dladdr(const void* addr, Dl_info* info) {
1878 // Determine if this address can be found in any library currently mapped.
1879 soinfo* si = find_containing_library(addr);
1880 if (si == nullptr) {
1881 return 0;
1882 }
1883
1884 memset(info, 0, sizeof(Dl_info));
1885
1886 info->dli_fname = si->get_realpath();
1887 // Address at which the shared object is loaded.
1888 info->dli_fbase = reinterpret_cast<void*>(si->base);
1889
1890 // Determine if any symbol in the library contains the specified address.
1891 ElfW(Sym)* sym = si->find_symbol_by_address(addr);
1892 if (sym != nullptr) {
1893 info->dli_sname = si->get_string(sym->st_name);
1894 info->dli_saddr = reinterpret_cast<void*>(si->resolve_symbol_address(sym));
1895 }
1896
1897 return 1;
1898}
1899
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001900static soinfo* soinfo_from_handle(void* handle) {
1901 if ((reinterpret_cast<uintptr_t>(handle) & 1) != 0) {
1902 auto it = g_soinfo_handles_map.find(reinterpret_cast<uintptr_t>(handle));
1903 if (it == g_soinfo_handles_map.end()) {
1904 return nullptr;
1905 } else {
1906 return it->second;
1907 }
1908 }
1909
1910 return static_cast<soinfo*>(handle);
1911}
1912
Dimitry Ivanovd9e427c2016-11-22 16:55:25 -08001913bool do_dlsym(void* handle,
1914 const char* sym_name,
1915 const char* sym_ver,
1916 const void* caller_addr,
1917 void** symbol) {
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001918#if !defined(__LP64__)
1919 if (handle == nullptr) {
1920 DL_ERR("dlsym failed: library handle is null");
1921 return false;
1922 }
1923#endif
1924
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001925 soinfo* found = nullptr;
1926 const ElfW(Sym)* sym = nullptr;
1927 soinfo* caller = find_containing_library(caller_addr);
Dimitry Ivanovaca299a2016-04-11 12:42:58 -07001928 android_namespace_t* ns = get_caller_namespace(caller);
Dimitry Ivanov4742abd2016-12-12 16:30:15 -08001929 soinfo* si = nullptr;
1930 if (handle != RTLD_DEFAULT && handle != RTLD_NEXT) {
1931 si = soinfo_from_handle(handle);
1932 }
1933
1934 LD_LOG(kLogDlsym,
1935 "dlsym(handle=%p(\"%s\"), sym_name=\"%s\", sym_ver=\"%s\", caller=\"%s\", caller_ns=%s@%p) ...",
1936 handle,
1937 si != nullptr ? si->get_realpath() : "n/a",
1938 sym_name,
1939 sym_ver,
1940 caller == nullptr ? "(null)" : caller->get_realpath(),
1941 ns == nullptr ? "(null)" : ns->get_name(),
1942 ns);
1943
1944 auto failure_guard = make_scope_guard([&]() {
1945 LD_LOG(kLogDlsym, "... dlsym failed: %s", linker_get_error_buffer());
1946 });
1947
1948 if (sym_name == nullptr) {
1949 DL_ERR("dlsym failed: symbol name is null");
1950 return false;
1951 }
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001952
1953 version_info vi_instance;
1954 version_info* vi = nullptr;
1955
1956 if (sym_ver != nullptr) {
Dimitry Ivanov9cf99cb2015-12-11 14:22:24 -08001957 vi_instance.name = sym_ver;
1958 vi_instance.elf_hash = calculate_elf_hash(sym_ver);
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001959 vi = &vi_instance;
1960 }
1961
1962 if (handle == RTLD_DEFAULT || handle == RTLD_NEXT) {
1963 sym = dlsym_linear_lookup(ns, sym_name, vi, &found, caller, handle);
1964 } else {
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001965 if (si == nullptr) {
1966 DL_ERR("dlsym failed: invalid handle: %p", handle);
1967 return false;
1968 }
1969 sym = dlsym_handle_lookup(si, &found, sym_name, vi);
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001970 }
1971
1972 if (sym != nullptr) {
1973 uint32_t bind = ELF_ST_BIND(sym->st_info);
1974
1975 if ((bind == STB_GLOBAL || bind == STB_WEAK) && sym->st_shndx != 0) {
1976 *symbol = reinterpret_cast<void*>(found->resolve_symbol_address(sym));
Dimitry Ivanov4742abd2016-12-12 16:30:15 -08001977 failure_guard.disable();
1978 LD_LOG(kLogDlsym,
1979 "... dlsym successful: sym_name=\"%s\", sym_ver=\"%s\", found in=\"%s\", address=%p",
1980 sym_name, sym_ver, found->get_soname(), *symbol);
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001981 return true;
1982 }
1983
1984 DL_ERR("symbol \"%s\" found but not global", symbol_display_name(sym_name, sym_ver).c_str());
1985 return false;
1986 }
1987
1988 DL_ERR("undefined symbol: %s", symbol_display_name(sym_name, sym_ver).c_str());
1989 return false;
1990}
1991
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001992int do_dlclose(void* handle) {
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -08001993 ProtectedDataGuard guard;
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001994 soinfo* si = soinfo_from_handle(handle);
1995 if (si == nullptr) {
1996 DL_ERR("invalid handle: %p", handle);
1997 return -1;
1998 }
1999
Dmitriy Ivanovb648a8a2014-05-19 15:06:58 -07002000 soinfo_unload(si);
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07002001 return 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002002}
2003
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002004bool init_namespaces(const char* public_ns_sonames, const char* anon_ns_library_path) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002005 if (g_public_namespace_initialized) {
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002006 DL_ERR("public namespace has already been initialized.");
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002007 return false;
2008 }
2009
Dimitry Ivanov54807612016-04-21 14:57:38 -07002010 if (public_ns_sonames == nullptr || public_ns_sonames[0] == '\0') {
2011 DL_ERR("error initializing public namespace: the list of public libraries is empty.");
2012 return false;
2013 }
2014
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08002015 auto sonames = android::base::Split(public_ns_sonames, ":");
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002016
2017 ProtectedDataGuard guard;
2018
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08002019 g_public_namespace_sonames = std::unordered_set<std::string>(sonames.begin(), sonames.end());
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002020
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002021 g_public_namespace_initialized = true;
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002022
2023 // create anonymous namespace
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002024 // When the caller is nullptr - create_namespace will take global group
2025 // from the anonymous namespace, which is fine because anonymous namespace
2026 // is still pointing to the default one.
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002027 android_namespace_t* anon_ns =
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002028 create_namespace(nullptr, "(anonymous)", nullptr, anon_ns_library_path,
Dimitry Ivanov52408632016-05-23 10:31:11 -07002029 ANDROID_NAMESPACE_TYPE_REGULAR, nullptr, &g_default_namespace);
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002030
2031 if (anon_ns == nullptr) {
2032 g_public_namespace_initialized = false;
2033 return false;
2034 }
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08002035
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002036 g_anonymous_namespace = anon_ns;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002037 return true;
2038}
2039
Dimitry Ivanovb943f302016-08-03 16:00:10 -07002040static void add_soinfos_to_namespace(const soinfo_list_t& soinfos, android_namespace_t* ns) {
2041 ns->add_soinfos(soinfos);
2042 for (auto si : soinfos) {
2043 si->add_secondary_namespace(ns);
2044 }
2045}
2046
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002047android_namespace_t* create_namespace(const void* caller_addr,
2048 const char* name,
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002049 const char* ld_library_path,
2050 const char* default_library_path,
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002051 uint64_t type,
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002052 const char* permitted_when_isolated_path,
2053 android_namespace_t* parent_namespace) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002054 if (!g_public_namespace_initialized) {
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002055 DL_ERR("cannot create namespace: public namespace is not initialized.");
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002056 return nullptr;
2057 }
2058
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002059 if (parent_namespace == nullptr) {
Dimitry Ivanov52408632016-05-23 10:31:11 -07002060 // if parent_namespace is nullptr -> set it to the caller namespace
2061 soinfo* caller_soinfo = find_containing_library(caller_addr);
2062
2063 parent_namespace = caller_soinfo != nullptr ?
2064 caller_soinfo->get_primary_namespace() :
2065 g_anonymous_namespace;
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002066 }
2067
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002068 ProtectedDataGuard guard;
2069 std::vector<std::string> ld_library_paths;
2070 std::vector<std::string> default_library_paths;
Dimitry Ivanov284ae352015-12-08 10:47:13 -08002071 std::vector<std::string> permitted_paths;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002072
2073 parse_path(ld_library_path, ":", &ld_library_paths);
2074 parse_path(default_library_path, ":", &default_library_paths);
Dimitry Ivanov284ae352015-12-08 10:47:13 -08002075 parse_path(permitted_when_isolated_path, ":", &permitted_paths);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002076
2077 android_namespace_t* ns = new (g_namespace_allocator.alloc()) android_namespace_t();
2078 ns->set_name(name);
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002079 ns->set_isolated((type & ANDROID_NAMESPACE_TYPE_ISOLATED) != 0);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002080 ns->set_ld_library_paths(std::move(ld_library_paths));
2081 ns->set_default_library_paths(std::move(default_library_paths));
Dimitry Ivanov284ae352015-12-08 10:47:13 -08002082 ns->set_permitted_paths(std::move(permitted_paths));
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002083
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002084 if ((type & ANDROID_NAMESPACE_TYPE_SHARED) != 0) {
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002085 // If shared - clone the parent namespace
Dimitry Ivanovb943f302016-08-03 16:00:10 -07002086 add_soinfos_to_namespace(parent_namespace->soinfo_list(), ns);
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002087 } else {
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002088 // If not shared - copy only the shared group
Dimitry Ivanovb943f302016-08-03 16:00:10 -07002089 add_soinfos_to_namespace(get_shared_group(parent_namespace), ns);
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002090 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002091
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08002092 // link it to default namespace
2093 // TODO (dimitry): replace this with user-supplied link once interface is updated
2094 ns->add_linked_namespace(&g_default_namespace, g_public_namespace_sonames);
2095
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002096 return ns;
2097}
2098
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002099ElfW(Addr) call_ifunc_resolver(ElfW(Addr) resolver_addr) {
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07002100 typedef ElfW(Addr) (*ifunc_resolver_t)(void);
2101 ifunc_resolver_t ifunc_resolver = reinterpret_cast<ifunc_resolver_t>(resolver_addr);
2102 ElfW(Addr) ifunc_addr = ifunc_resolver();
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002103 TRACE_TYPE(RELO, "Called ifunc_resolver@%p. The result is %p",
2104 ifunc_resolver, reinterpret_cast<void*>(ifunc_addr));
Brigid Smithc5a13ef2014-07-23 11:22:25 -07002105
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07002106 return ifunc_addr;
Brigid Smithc5a13ef2014-07-23 11:22:25 -07002107}
Brigid Smithc5a13ef2014-07-23 11:22:25 -07002108
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002109const version_info* VersionTracker::get_version_info(ElfW(Versym) source_symver) const {
2110 if (source_symver < 2 ||
2111 source_symver >= version_infos.size() ||
2112 version_infos[source_symver].name == nullptr) {
2113 return nullptr;
2114 }
2115
2116 return &version_infos[source_symver];
2117}
2118
2119void VersionTracker::add_version_info(size_t source_index,
2120 ElfW(Word) elf_hash,
2121 const char* ver_name,
2122 const soinfo* target_si) {
2123 if (source_index >= version_infos.size()) {
2124 version_infos.resize(source_index+1);
2125 }
2126
2127 version_infos[source_index].elf_hash = elf_hash;
2128 version_infos[source_index].name = ver_name;
2129 version_infos[source_index].target_si = target_si;
2130}
2131
2132bool VersionTracker::init_verneed(const soinfo* si_from) {
2133 uintptr_t verneed_ptr = si_from->get_verneed_ptr();
2134
2135 if (verneed_ptr == 0) {
2136 return true;
2137 }
2138
2139 size_t verneed_cnt = si_from->get_verneed_cnt();
2140
2141 for (size_t i = 0, offset = 0; i<verneed_cnt; ++i) {
2142 const ElfW(Verneed)* verneed = reinterpret_cast<ElfW(Verneed)*>(verneed_ptr + offset);
2143 size_t vernaux_offset = offset + verneed->vn_aux;
2144 offset += verneed->vn_next;
2145
2146 if (verneed->vn_version != 1) {
2147 DL_ERR("unsupported verneed[%zd] vn_version: %d (expected 1)", i, verneed->vn_version);
2148 return false;
2149 }
2150
2151 const char* target_soname = si_from->get_string(verneed->vn_file);
2152 // find it in dependencies
2153 soinfo* target_si = si_from->get_children().find_if([&](const soinfo* si) {
Dmitriy Ivanov406d9962015-05-06 11:05:27 -07002154 return si->get_soname() != nullptr && strcmp(si->get_soname(), target_soname) == 0;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002155 });
2156
2157 if (target_si == nullptr) {
2158 DL_ERR("cannot find \"%s\" from verneed[%zd] in DT_NEEDED list for \"%s\"",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002159 target_soname, i, si_from->get_realpath());
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002160 return false;
2161 }
2162
2163 for (size_t j = 0; j<verneed->vn_cnt; ++j) {
2164 const ElfW(Vernaux)* vernaux = reinterpret_cast<ElfW(Vernaux)*>(verneed_ptr + vernaux_offset);
2165 vernaux_offset += vernaux->vna_next;
2166
2167 const ElfW(Word) elf_hash = vernaux->vna_hash;
2168 const char* ver_name = si_from->get_string(vernaux->vna_name);
2169 ElfW(Half) source_index = vernaux->vna_other;
2170
2171 add_version_info(source_index, elf_hash, ver_name, target_si);
2172 }
2173 }
2174
2175 return true;
2176}
2177
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002178template <typename F>
2179static bool for_each_verdef(const soinfo* si, F functor) {
2180 if (!si->has_min_version(2)) {
2181 return true;
2182 }
2183
2184 uintptr_t verdef_ptr = si->get_verdef_ptr();
2185 if (verdef_ptr == 0) {
2186 return true;
2187 }
2188
2189 size_t offset = 0;
2190
2191 size_t verdef_cnt = si->get_verdef_cnt();
2192 for (size_t i = 0; i<verdef_cnt; ++i) {
2193 const ElfW(Verdef)* verdef = reinterpret_cast<ElfW(Verdef)*>(verdef_ptr + offset);
2194 size_t verdaux_offset = offset + verdef->vd_aux;
2195 offset += verdef->vd_next;
2196
2197 if (verdef->vd_version != 1) {
2198 DL_ERR("unsupported verdef[%zd] vd_version: %d (expected 1) library: %s",
2199 i, verdef->vd_version, si->get_realpath());
2200 return false;
2201 }
2202
2203 if ((verdef->vd_flags & VER_FLG_BASE) != 0) {
2204 // "this is the version of the file itself. It must not be used for
2205 // matching a symbol. It can be used to match references."
2206 //
2207 // http://www.akkadia.org/drepper/symbol-versioning
2208 continue;
2209 }
2210
2211 if (verdef->vd_cnt == 0) {
2212 DL_ERR("invalid verdef[%zd] vd_cnt == 0 (version without a name)", i);
2213 return false;
2214 }
2215
2216 const ElfW(Verdaux)* verdaux = reinterpret_cast<ElfW(Verdaux)*>(verdef_ptr + verdaux_offset);
2217
2218 if (functor(i, verdef, verdaux) == true) {
2219 break;
2220 }
2221 }
2222
2223 return true;
2224}
2225
2226bool find_verdef_version_index(const soinfo* si, const version_info* vi, ElfW(Versym)* versym) {
2227 if (vi == nullptr) {
2228 *versym = kVersymNotNeeded;
2229 return true;
2230 }
2231
2232 *versym = kVersymGlobal;
2233
2234 return for_each_verdef(si,
2235 [&](size_t, const ElfW(Verdef)* verdef, const ElfW(Verdaux)* verdaux) {
2236 if (verdef->vd_hash == vi->elf_hash &&
2237 strcmp(vi->name, si->get_string(verdaux->vda_name)) == 0) {
2238 *versym = verdef->vd_ndx;
2239 return true;
2240 }
2241
2242 return false;
2243 }
2244 );
2245}
2246
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002247bool VersionTracker::init_verdef(const soinfo* si_from) {
2248 return for_each_verdef(si_from,
2249 [&](size_t, const ElfW(Verdef)* verdef, const ElfW(Verdaux)* verdaux) {
2250 add_version_info(verdef->vd_ndx, verdef->vd_hash,
2251 si_from->get_string(verdaux->vda_name), si_from);
2252 return false;
2253 }
2254 );
2255}
2256
2257bool VersionTracker::init(const soinfo* si_from) {
2258 if (!si_from->has_min_version(2)) {
2259 return true;
2260 }
2261
2262 return init_verneed(si_from) && init_verdef(si_from);
2263}
2264
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002265// TODO (dimitry): Methods below need to be moved out of soinfo
2266// and in more isolated file in order minimize dependencies on
2267// unnecessary object in the linker binary. Consider making them
2268// independent from soinfo (?).
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002269bool soinfo::lookup_version_info(const VersionTracker& version_tracker, ElfW(Word) sym,
2270 const char* sym_name, const version_info** vi) {
2271 const ElfW(Versym)* sym_ver_ptr = get_versym(sym);
2272 ElfW(Versym) sym_ver = sym_ver_ptr == nullptr ? 0 : *sym_ver_ptr;
2273
2274 if (sym_ver != VER_NDX_LOCAL && sym_ver != VER_NDX_GLOBAL) {
2275 *vi = version_tracker.get_version_info(sym_ver);
2276
2277 if (*vi == nullptr) {
2278 DL_ERR("cannot find verneed/verdef for version index=%d "
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002279 "referenced by symbol \"%s\" at \"%s\"", sym_ver, sym_name, get_realpath());
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002280 return false;
2281 }
2282 } else {
2283 // there is no version info
2284 *vi = nullptr;
2285 }
2286
2287 return true;
2288}
2289
Dimitry Ivanov576a3752016-08-09 06:58:55 -07002290#if !defined(__mips__)
2291#if defined(USE_RELA)
2292static ElfW(Addr) get_addend(ElfW(Rela)* rela, ElfW(Addr) reloc_addr __unused) {
2293 return rela->r_addend;
2294}
2295#else
2296static ElfW(Addr) get_addend(ElfW(Rel)* rel, ElfW(Addr) reloc_addr) {
2297 if (ELFW(R_TYPE)(rel->r_info) == R_GENERIC_RELATIVE ||
2298 ELFW(R_TYPE)(rel->r_info) == R_GENERIC_IRELATIVE) {
2299 return *reinterpret_cast<ElfW(Addr)*>(reloc_addr);
2300 }
2301 return 0;
2302}
2303#endif
2304
Dmitriy Ivanovfa26eee2015-02-03 16:06:47 -08002305template<typename ElfRelIteratorT>
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07002306bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& rel_iterator,
2307 const soinfo_list_t& global_group, const soinfo_list_t& local_group) {
Dmitriy Ivanovfa26eee2015-02-03 16:06:47 -08002308 for (size_t idx = 0; rel_iterator.has_next(); ++idx) {
2309 const auto rel = rel_iterator.next();
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002310 if (rel == nullptr) {
2311 return false;
2312 }
2313
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002314 ElfW(Word) type = ELFW(R_TYPE)(rel->r_info);
2315 ElfW(Word) sym = ELFW(R_SYM)(rel->r_info);
2316
2317 ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rel->r_offset + load_bias);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002318 ElfW(Addr) sym_addr = 0;
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07002319 const char* sym_name = nullptr;
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002320 ElfW(Addr) addend = get_addend(rel, reloc);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002321
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07002322 DEBUG("Processing \"%s\" relocation at index %zd", get_realpath(), idx);
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002323 if (type == R_GENERIC_NONE) {
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002324 continue;
2325 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002326
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002327 const ElfW(Sym)* s = nullptr;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002328 soinfo* lsi = nullptr;
2329
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002330 if (sym != 0) {
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002331 sym_name = get_string(symtab_[sym].st_name);
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002332 const version_info* vi = nullptr;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002333
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002334 if (!lookup_version_info(version_tracker, sym, sym_name, &vi)) {
2335 return false;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002336 }
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002337
2338 if (!soinfo_do_lookup(this, sym_name, vi, &lsi, global_group, local_group, &s)) {
2339 return false;
2340 }
2341
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07002342 if (s == nullptr) {
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002343 // We only allow an undefined symbol if this is a weak reference...
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002344 s = &symtab_[sym];
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002345 if (ELF_ST_BIND(s->st_info) != STB_WEAK) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002346 DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, get_realpath());
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002347 return false;
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002348 }
2349
2350 /* IHI0044C AAELF 4.5.1.1:
2351
2352 Libraries are not searched to resolve weak references.
2353 It is not an error for a weak reference to remain unsatisfied.
2354
2355 During linking, the value of an undefined weak reference is:
2356 - Zero if the relocation type is absolute
2357 - The address of the place if the relocation is pc-relative
2358 - The address of nominal base address if the relocation
2359 type is base-relative.
2360 */
2361
2362 switch (type) {
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002363 case R_GENERIC_JUMP_SLOT:
2364 case R_GENERIC_GLOB_DAT:
2365 case R_GENERIC_RELATIVE:
2366 case R_GENERIC_IRELATIVE:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002367#if defined(__aarch64__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002368 case R_AARCH64_ABS64:
2369 case R_AARCH64_ABS32:
2370 case R_AARCH64_ABS16:
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002371#elif defined(__x86_64__)
2372 case R_X86_64_32:
2373 case R_X86_64_64:
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002374#elif defined(__arm__)
2375 case R_ARM_ABS32:
2376#elif defined(__i386__)
2377 case R_386_32:
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002378#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002379 /*
2380 * The sym_addr was initialized to be zero above, or the relocation
2381 * code below does not care about value of sym_addr.
2382 * No need to do anything.
2383 */
2384 break;
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002385#if defined(__x86_64__)
Dimitry Ivanovd338aac2015-01-13 22:31:54 +00002386 case R_X86_64_PC32:
2387 sym_addr = reloc;
2388 break;
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002389#elif defined(__i386__)
2390 case R_386_PC32:
2391 sym_addr = reloc;
2392 break;
2393#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002394 default:
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002395 DL_ERR("unknown weak reloc type %d @ %p (%zu)", type, rel, idx);
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002396 return false;
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002397 }
Dmitriy Ivanovec83a612015-07-26 07:37:09 -07002398 } else { // We got a definition.
2399#if !defined(__LP64__)
2400 // When relocating dso with text_relocation .text segment is
2401 // not executable. We need to restore elf flags before resolving
2402 // STT_GNU_IFUNC symbol.
2403 bool protect_segments = has_text_relocations &&
2404 lsi == this &&
2405 ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC;
2406 if (protect_segments) {
2407 if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
2408 DL_ERR("can't protect segments for \"%s\": %s",
2409 get_realpath(), strerror(errno));
2410 return false;
2411 }
2412 }
2413#endif
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07002414 sym_addr = lsi->resolve_symbol_address(s);
Dmitriy Ivanovec83a612015-07-26 07:37:09 -07002415#if !defined(__LP64__)
2416 if (protect_segments) {
2417 if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
2418 DL_ERR("can't unprotect loadable segments for \"%s\": %s",
2419 get_realpath(), strerror(errno));
2420 return false;
2421 }
2422 }
2423#endif
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002424 }
2425 count_relocation(kRelocSymbol);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002426 }
2427
2428 switch (type) {
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002429 case R_GENERIC_JUMP_SLOT:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002430 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002431 MARK(rel->r_offset);
2432 TRACE_TYPE(RELO, "RELO JMP_SLOT %16p <- %16p %s\n",
2433 reinterpret_cast<void*>(reloc),
2434 reinterpret_cast<void*>(sym_addr + addend), sym_name);
2435
2436 *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002437 break;
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002438 case R_GENERIC_GLOB_DAT:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002439 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002440 MARK(rel->r_offset);
2441 TRACE_TYPE(RELO, "RELO GLOB_DAT %16p <- %16p %s\n",
2442 reinterpret_cast<void*>(reloc),
2443 reinterpret_cast<void*>(sym_addr + addend), sym_name);
2444 *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002445 break;
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002446 case R_GENERIC_RELATIVE:
2447 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002448 MARK(rel->r_offset);
2449 TRACE_TYPE(RELO, "RELO RELATIVE %16p <- %16p\n",
2450 reinterpret_cast<void*>(reloc),
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002451 reinterpret_cast<void*>(load_bias + addend));
2452 *reinterpret_cast<ElfW(Addr)*>(reloc) = (load_bias + addend);
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002453 break;
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002454 case R_GENERIC_IRELATIVE:
2455 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002456 MARK(rel->r_offset);
2457 TRACE_TYPE(RELO, "RELO IRELATIVE %16p <- %16p\n",
2458 reinterpret_cast<void*>(reloc),
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002459 reinterpret_cast<void*>(load_bias + addend));
Dmitriy Ivanovec83a612015-07-26 07:37:09 -07002460 {
2461#if !defined(__LP64__)
2462 // When relocating dso with text_relocation .text segment is
2463 // not executable. We need to restore elf flags for this
2464 // particular call.
2465 if (has_text_relocations) {
2466 if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
2467 DL_ERR("can't protect segments for \"%s\": %s",
2468 get_realpath(), strerror(errno));
2469 return false;
2470 }
2471 }
2472#endif
2473 ElfW(Addr) ifunc_addr = call_ifunc_resolver(load_bias + addend);
2474#if !defined(__LP64__)
2475 // Unprotect it afterwards...
2476 if (has_text_relocations) {
2477 if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
2478 DL_ERR("can't unprotect loadable segments for \"%s\": %s",
2479 get_realpath(), strerror(errno));
2480 return false;
2481 }
2482 }
2483#endif
2484 *reinterpret_cast<ElfW(Addr)*>(reloc) = ifunc_addr;
2485 }
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002486 break;
2487
2488#if defined(__aarch64__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002489 case R_AARCH64_ABS64:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002490 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002491 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002492 TRACE_TYPE(RELO, "RELO ABS64 %16llx <- %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002493 reloc, sym_addr + addend, sym_name);
2494 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend;
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002495 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002496 case R_AARCH64_ABS32:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002497 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002498 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002499 TRACE_TYPE(RELO, "RELO ABS32 %16llx <- %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002500 reloc, sym_addr + addend, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002501 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002502 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT32_MIN);
2503 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT32_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002504 if ((min_value <= (sym_addr + addend)) &&
2505 ((sym_addr + addend) <= max_value)) {
2506 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend;
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002507 } else {
2508 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002509 sym_addr + addend, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002510 return false;
2511 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002512 }
2513 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002514 case R_AARCH64_ABS16:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002515 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002516 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002517 TRACE_TYPE(RELO, "RELO ABS16 %16llx <- %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002518 reloc, sym_addr + addend, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002519 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002520 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN);
2521 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT16_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002522 if ((min_value <= (sym_addr + addend)) &&
2523 ((sym_addr + addend) <= max_value)) {
2524 *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002525 } else {
2526 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002527 sym_addr + addend, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002528 return false;
2529 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002530 }
2531 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002532 case R_AARCH64_PREL64:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002533 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002534 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002535 TRACE_TYPE(RELO, "RELO REL64 %16llx <- %16llx - %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002536 reloc, sym_addr + addend, rel->r_offset, sym_name);
2537 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset;
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002538 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002539 case R_AARCH64_PREL32:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002540 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002541 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002542 TRACE_TYPE(RELO, "RELO REL32 %16llx <- %16llx - %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002543 reloc, sym_addr + addend, rel->r_offset, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002544 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002545 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT32_MIN);
2546 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT32_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002547 if ((min_value <= (sym_addr + addend - rel->r_offset)) &&
2548 ((sym_addr + addend - rel->r_offset) <= max_value)) {
2549 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset;
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002550 } else {
2551 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002552 sym_addr + addend - rel->r_offset, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002553 return false;
2554 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002555 }
2556 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002557 case R_AARCH64_PREL16:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002558 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002559 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002560 TRACE_TYPE(RELO, "RELO REL16 %16llx <- %16llx - %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002561 reloc, sym_addr + addend, rel->r_offset, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002562 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002563 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN);
2564 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT16_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002565 if ((min_value <= (sym_addr + addend - rel->r_offset)) &&
2566 ((sym_addr + addend - rel->r_offset) <= max_value)) {
2567 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset;
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002568 } else {
2569 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002570 sym_addr + addend - rel->r_offset, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002571 return false;
2572 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002573 }
2574 break;
2575
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002576 case R_AARCH64_COPY:
Nick Kralevich76e289c2014-07-03 12:04:31 -07002577 /*
2578 * ET_EXEC is not supported so this should not happen.
2579 *
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002580 * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0056b/IHI0056B_aaelf64.pdf
Nick Kralevich76e289c2014-07-03 12:04:31 -07002581 *
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002582 * Section 4.6.11 "Dynamic relocations"
Nick Kralevich76e289c2014-07-03 12:04:31 -07002583 * R_AARCH64_COPY may only appear in executable objects where e_type is
2584 * set to ET_EXEC.
2585 */
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002586 DL_ERR("%s R_AARCH64_COPY relocations are not supported", get_realpath());
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002587 return false;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002588 case R_AARCH64_TLS_TPREL64:
Elliott Hughes0266ae52014-02-10 17:46:57 -08002589 TRACE_TYPE(RELO, "RELO TLS_TPREL64 *** %16llx <- %16llx - %16llx\n",
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002590 reloc, (sym_addr + addend), rel->r_offset);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002591 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002592 case R_AARCH64_TLS_DTPREL32:
Elliott Hughes0266ae52014-02-10 17:46:57 -08002593 TRACE_TYPE(RELO, "RELO TLS_DTPREL32 *** %16llx <- %16llx - %16llx\n",
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002594 reloc, (sym_addr + addend), rel->r_offset);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002595 break;
2596#elif defined(__x86_64__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002597 case R_X86_64_32:
2598 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002599 MARK(rel->r_offset);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002600 TRACE_TYPE(RELO, "RELO R_X86_64_32 %08zx <- +%08zx %s", static_cast<size_t>(reloc),
2601 static_cast<size_t>(sym_addr), sym_name);
Junichi Uekawaff35b1e2015-11-18 10:18:59 +09002602 *reinterpret_cast<Elf32_Addr*>(reloc) = sym_addr + addend;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002603 break;
2604 case R_X86_64_64:
2605 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002606 MARK(rel->r_offset);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002607 TRACE_TYPE(RELO, "RELO R_X86_64_64 %08zx <- +%08zx %s", static_cast<size_t>(reloc),
2608 static_cast<size_t>(sym_addr), sym_name);
Junichi Uekawaff35b1e2015-11-18 10:18:59 +09002609 *reinterpret_cast<Elf64_Addr*>(reloc) = sym_addr + addend;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002610 break;
2611 case R_X86_64_PC32:
2612 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002613 MARK(rel->r_offset);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002614 TRACE_TYPE(RELO, "RELO R_X86_64_PC32 %08zx <- +%08zx (%08zx - %08zx) %s",
2615 static_cast<size_t>(reloc), static_cast<size_t>(sym_addr - reloc),
2616 static_cast<size_t>(sym_addr), static_cast<size_t>(reloc), sym_name);
Junichi Uekawaff35b1e2015-11-18 10:18:59 +09002617 *reinterpret_cast<Elf32_Addr*>(reloc) = sym_addr + addend - reloc;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002618 break;
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002619#elif defined(__arm__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002620 case R_ARM_ABS32:
2621 count_relocation(kRelocAbsolute);
2622 MARK(rel->r_offset);
2623 TRACE_TYPE(RELO, "RELO ABS %08x <- %08x %s", reloc, sym_addr, sym_name);
2624 *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
2625 break;
2626 case R_ARM_REL32:
2627 count_relocation(kRelocRelative);
2628 MARK(rel->r_offset);
2629 TRACE_TYPE(RELO, "RELO REL32 %08x <- %08x - %08x %s",
2630 reloc, sym_addr, rel->r_offset, sym_name);
2631 *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr - rel->r_offset;
2632 break;
2633 case R_ARM_COPY:
2634 /*
2635 * ET_EXEC is not supported so this should not happen.
2636 *
2637 * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044d/IHI0044D_aaelf.pdf
2638 *
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002639 * Section 4.6.1.10 "Dynamic relocations"
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002640 * R_ARM_COPY may only appear in executable objects where e_type is
2641 * set to ET_EXEC.
2642 */
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002643 DL_ERR("%s R_ARM_COPY relocations are not supported", get_realpath());
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002644 return false;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002645#elif defined(__i386__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002646 case R_386_32:
2647 count_relocation(kRelocRelative);
2648 MARK(rel->r_offset);
2649 TRACE_TYPE(RELO, "RELO R_386_32 %08x <- +%08x %s", reloc, sym_addr, sym_name);
2650 *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
2651 break;
2652 case R_386_PC32:
2653 count_relocation(kRelocRelative);
2654 MARK(rel->r_offset);
2655 TRACE_TYPE(RELO, "RELO R_386_PC32 %08x <- +%08x (%08x - %08x) %s",
2656 reloc, (sym_addr - reloc), sym_addr, reloc, sym_name);
2657 *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr - reloc);
2658 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002659#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002660 default:
2661 DL_ERR("unknown reloc type %d @ %p (%zu)", type, rel, idx);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002662 return false;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002663 }
2664 }
2665 return true;
Raghu Gandhamd7daacb2012-07-31 12:07:22 -07002666}
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002667#endif // !defined(__mips__)
Raghu Gandhamd7daacb2012-07-31 12:07:22 -07002668
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002669// An empty list of soinfos
Dimitry Ivanovb943f302016-08-03 16:00:10 -07002670static soinfo_list_t g_empty_list;
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07002671
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002672bool soinfo::prelink_image() {
Ningsheng Jiane93be992014-09-16 15:22:10 +08002673 /* Extract dynamic section */
2674 ElfW(Word) dynamic_flags = 0;
2675 phdr_table_get_dynamic_section(phdr, phnum, load_bias, &dynamic, &dynamic_flags);
Dmitriy Ivanov498eb182014-09-05 14:57:59 -07002676
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002677 /* We can't log anything until the linker is relocated */
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002678 bool relocating_linker = (flags_ & FLAG_LINKER) != 0;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002679 if (!relocating_linker) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07002680 INFO("[ Linking \"%s\" ]", get_realpath());
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002681 DEBUG("si->base = %p si->flags = 0x%08x", reinterpret_cast<void*>(base), flags_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002682 }
2683
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002684 if (dynamic == nullptr) {
David 'Digit' Turnerb52e4382012-06-19 01:24:17 +02002685 if (!relocating_linker) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002686 DL_ERR("missing PT_DYNAMIC in \"%s\"", get_realpath());
David 'Digit' Turnerb52e4382012-06-19 01:24:17 +02002687 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002688 return false;
2689 } else {
2690 if (!relocating_linker) {
2691 DEBUG("dynamic = %p", dynamic);
David 'Digit' Turner63f99f42012-06-19 00:08:39 +02002692 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002693 }
David 'Digit' Turner63f99f42012-06-19 00:08:39 +02002694
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07002695#if defined(__arm__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002696 (void) phdr_table_get_arm_exidx(phdr, phnum, load_bias,
2697 &ARM_exidx, &ARM_exidx_count);
David 'Digit' Turner63f99f42012-06-19 00:08:39 +02002698#endif
2699
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002700 // Extract useful information from dynamic section.
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07002701 // Note that: "Except for the DT_NULL element at the end of the array,
2702 // and the relative order of DT_NEEDED elements, entries may appear in any order."
2703 //
2704 // source: http://www.sco.com/developers/gabi/1998-04-29/ch5.dynamic.html
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002705 uint32_t needed_count = 0;
2706 for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
2707 DEBUG("d = %p, d[0](tag) = %p d[1](val) = %p",
2708 d, reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
2709 switch (d->d_tag) {
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002710 case DT_SONAME:
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07002711 // this is parsed after we have strtab initialized (see below).
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002712 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002713
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002714 case DT_HASH:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002715 nbucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0];
2716 nchain_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
2717 bucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8);
2718 chain_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8 + nbucket_ * 4);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002719 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002720
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002721 case DT_GNU_HASH:
Dmitriy Ivanov3597b802015-03-09 12:02:02 -07002722 gnu_nbucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0];
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002723 // skip symndx
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002724 gnu_maskwords_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[2];
2725 gnu_shift2_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[3];
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002726
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002727 gnu_bloom_filter_ = reinterpret_cast<ElfW(Addr)*>(load_bias + d->d_un.d_ptr + 16);
Dmitriy Ivanov3597b802015-03-09 12:02:02 -07002728 gnu_bucket_ = reinterpret_cast<uint32_t*>(gnu_bloom_filter_ + gnu_maskwords_);
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002729 // amend chain for symndx = header[1]
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002730 gnu_chain_ = gnu_bucket_ + gnu_nbucket_ -
2731 reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002732
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002733 if (!powerof2(gnu_maskwords_)) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002734 DL_ERR("invalid maskwords for gnu_hash = 0x%x, in \"%s\" expecting power to two",
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002735 gnu_maskwords_, get_realpath());
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002736 return false;
2737 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002738 --gnu_maskwords_;
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002739
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002740 flags_ |= FLAG_GNU_HASH;
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002741 break;
2742
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002743 case DT_STRTAB:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002744 strtab_ = reinterpret_cast<const char*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002745 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002746
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07002747 case DT_STRSZ:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002748 strtab_size_ = d->d_un.d_val;
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07002749 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002750
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002751 case DT_SYMTAB:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002752 symtab_ = reinterpret_cast<ElfW(Sym)*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002753 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002754
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002755 case DT_SYMENT:
2756 if (d->d_un.d_val != sizeof(ElfW(Sym))) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002757 DL_ERR("invalid DT_SYMENT: %zd in \"%s\"",
2758 static_cast<size_t>(d->d_un.d_val), get_realpath());
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002759 return false;
2760 }
2761 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002762
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002763 case DT_PLTREL:
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002764#if defined(USE_RELA)
2765 if (d->d_un.d_val != DT_RELA) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002766 DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_RELA", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002767 return false;
2768 }
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002769#else
2770 if (d->d_un.d_val != DT_REL) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002771 DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_REL", get_realpath());
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002772 return false;
2773 }
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002774#endif
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002775 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002776
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002777 case DT_JMPREL:
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07002778#if defined(USE_RELA)
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002779 plt_rela_ = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002780#else
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002781 plt_rel_ = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002782#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002783 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002784
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002785 case DT_PLTRELSZ:
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07002786#if defined(USE_RELA)
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002787 plt_rela_count_ = d->d_un.d_val / sizeof(ElfW(Rela));
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002788#else
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002789 plt_rel_count_ = d->d_un.d_val / sizeof(ElfW(Rel));
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002790#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002791 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002792
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002793 case DT_PLTGOT:
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002794#if defined(__mips__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002795 // Used by mips and mips64.
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002796 plt_got_ = reinterpret_cast<ElfW(Addr)**>(load_bias + d->d_un.d_ptr);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002797#endif
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002798 // Ignore for other platforms... (because RTLD_LAZY is not supported)
2799 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002800
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002801 case DT_DEBUG:
2802 // Set the DT_DEBUG entry to the address of _r_debug for GDB
2803 // if the dynamic table is writable
Chris Dearman99186652014-02-06 20:36:51 -08002804// FIXME: not working currently for N64
2805// The flags for the LOAD and DYNAMIC program headers do not agree.
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002806// The LOAD section containing the dynamic table has been mapped as
Chris Dearman99186652014-02-06 20:36:51 -08002807// read-only, but the DYNAMIC header claims it is writable.
2808#if !(defined(__mips__) && defined(__LP64__))
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002809 if ((dynamic_flags & PF_W) != 0) {
2810 d->d_un.d_val = reinterpret_cast<uintptr_t>(&_r_debug);
2811 }
Chris Dearman99186652014-02-06 20:36:51 -08002812#endif
Dmitriy Ivanovc6292ea2015-02-13 16:29:50 -08002813 break;
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07002814#if defined(USE_RELA)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002815 case DT_RELA:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002816 rela_ = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002817 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002818
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002819 case DT_RELASZ:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002820 rela_count_ = d->d_un.d_val / sizeof(ElfW(Rela));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002821 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002822
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002823 case DT_ANDROID_RELA:
2824 android_relocs_ = reinterpret_cast<uint8_t*>(load_bias + d->d_un.d_ptr);
2825 break;
2826
2827 case DT_ANDROID_RELASZ:
2828 android_relocs_size_ = d->d_un.d_val;
2829 break;
2830
2831 case DT_ANDROID_REL:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002832 DL_ERR("unsupported DT_ANDROID_REL in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002833 return false;
2834
2835 case DT_ANDROID_RELSZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002836 DL_ERR("unsupported DT_ANDROID_RELSZ in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002837 return false;
2838
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002839 case DT_RELAENT:
2840 if (d->d_un.d_val != sizeof(ElfW(Rela))) {
Dmitriy Ivanovf240aa82014-09-16 23:34:20 -07002841 DL_ERR("invalid DT_RELAENT: %zd", static_cast<size_t>(d->d_un.d_val));
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002842 return false;
2843 }
2844 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002845
2846 // ignored (see DT_RELCOUNT comments for details)
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002847 case DT_RELACOUNT:
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002848 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002849
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002850 case DT_REL:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002851 DL_ERR("unsupported DT_REL in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002852 return false;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002853
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002854 case DT_RELSZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002855 DL_ERR("unsupported DT_RELSZ in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002856 return false;
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002857
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002858#else
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002859 case DT_REL:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002860 rel_ = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002861 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002862
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002863 case DT_RELSZ:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002864 rel_count_ = d->d_un.d_val / sizeof(ElfW(Rel));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002865 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002866
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002867 case DT_RELENT:
2868 if (d->d_un.d_val != sizeof(ElfW(Rel))) {
Dmitriy Ivanovf240aa82014-09-16 23:34:20 -07002869 DL_ERR("invalid DT_RELENT: %zd", static_cast<size_t>(d->d_un.d_val));
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002870 return false;
2871 }
2872 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002873
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002874 case DT_ANDROID_REL:
2875 android_relocs_ = reinterpret_cast<uint8_t*>(load_bias + d->d_un.d_ptr);
2876 break;
2877
2878 case DT_ANDROID_RELSZ:
2879 android_relocs_size_ = d->d_un.d_val;
2880 break;
2881
2882 case DT_ANDROID_RELA:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002883 DL_ERR("unsupported DT_ANDROID_RELA in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002884 return false;
2885
2886 case DT_ANDROID_RELASZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002887 DL_ERR("unsupported DT_ANDROID_RELASZ in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002888 return false;
2889
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002890 // "Indicates that all RELATIVE relocations have been concatenated together,
2891 // and specifies the RELATIVE relocation count."
2892 //
2893 // TODO: Spec also mentions that this can be used to optimize relocation process;
2894 // Not currently used by bionic linker - ignored.
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002895 case DT_RELCOUNT:
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002896 break;
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002897
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002898 case DT_RELA:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002899 DL_ERR("unsupported DT_RELA in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002900 return false;
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002901
2902 case DT_RELASZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002903 DL_ERR("unsupported DT_RELASZ in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002904 return false;
2905
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002906#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002907 case DT_INIT:
Dimitry Ivanov55437462016-07-20 15:33:07 -07002908 init_func_ = reinterpret_cast<linker_ctor_function_t>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002909 DEBUG("%s constructors (DT_INIT) found at %p", get_realpath(), init_func_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002910 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002911
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002912 case DT_FINI:
Dimitry Ivanov55437462016-07-20 15:33:07 -07002913 fini_func_ = reinterpret_cast<linker_dtor_function_t>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002914 DEBUG("%s destructors (DT_FINI) found at %p", get_realpath(), fini_func_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002915 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002916
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002917 case DT_INIT_ARRAY:
Dimitry Ivanov55437462016-07-20 15:33:07 -07002918 init_array_ = reinterpret_cast<linker_ctor_function_t*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002919 DEBUG("%s constructors (DT_INIT_ARRAY) found at %p", get_realpath(), init_array_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002920 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002921
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002922 case DT_INIT_ARRAYSZ:
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -08002923 init_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002924 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002925
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002926 case DT_FINI_ARRAY:
Dimitry Ivanov55437462016-07-20 15:33:07 -07002927 fini_array_ = reinterpret_cast<linker_dtor_function_t*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002928 DEBUG("%s destructors (DT_FINI_ARRAY) found at %p", get_realpath(), fini_array_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002929 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002930
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002931 case DT_FINI_ARRAYSZ:
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -08002932 fini_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002933 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002934
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002935 case DT_PREINIT_ARRAY:
Dimitry Ivanov55437462016-07-20 15:33:07 -07002936 preinit_array_ = reinterpret_cast<linker_ctor_function_t*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002937 DEBUG("%s constructors (DT_PREINIT_ARRAY) found at %p", get_realpath(), preinit_array_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002938 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002939
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002940 case DT_PREINIT_ARRAYSZ:
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -08002941 preinit_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002942 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002943
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002944 case DT_TEXTREL:
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00002945#if defined(__LP64__)
Dimitry Ivanov816676e2016-10-19 11:00:28 -07002946 DL_ERR("\"%s\" has text relocations", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002947 return false;
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00002948#else
2949 has_text_relocations = true;
2950 break;
2951#endif
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002952
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002953 case DT_SYMBOLIC:
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -07002954 has_DT_SYMBOLIC = true;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002955 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002956
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002957 case DT_NEEDED:
2958 ++needed_count;
2959 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002960
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002961 case DT_FLAGS:
2962 if (d->d_un.d_val & DF_TEXTREL) {
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00002963#if defined(__LP64__)
Dimitry Ivanov816676e2016-10-19 11:00:28 -07002964 DL_ERR("\"%s\" has text relocations", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002965 return false;
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00002966#else
2967 has_text_relocations = true;
2968#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002969 }
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -07002970 if (d->d_un.d_val & DF_SYMBOLIC) {
2971 has_DT_SYMBOLIC = true;
2972 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002973 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002974
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07002975 case DT_FLAGS_1:
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07002976 set_dt_flags_1(d->d_un.d_val);
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -07002977
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07002978 if ((d->d_un.d_val & ~SUPPORTED_DT_FLAGS_1) != 0) {
Dimitry Ivanov816676e2016-10-19 11:00:28 -07002979 DL_WARN("\"%s\" has unsupported flags DT_FLAGS_1=%p", get_realpath(), reinterpret_cast<void*>(d->d_un.d_val));
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07002980 }
2981 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002982#if defined(__mips__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002983 case DT_MIPS_RLD_MAP:
2984 // Set the DT_MIPS_RLD_MAP entry to the address of _r_debug for GDB.
2985 {
2986 r_debug** dp = reinterpret_cast<r_debug**>(load_bias + d->d_un.d_ptr);
2987 *dp = &_r_debug;
2988 }
2989 break;
Lazar Trsic83b44a92016-04-06 13:39:17 +02002990 case DT_MIPS_RLD_MAP_REL:
2991 // Set the DT_MIPS_RLD_MAP_REL entry to the address of _r_debug for GDB.
Raghu Gandham68815722014-12-18 19:12:19 -08002992 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002993 r_debug** dp = reinterpret_cast<r_debug**>(
2994 reinterpret_cast<ElfW(Addr)>(d) + d->d_un.d_val);
Raghu Gandham68815722014-12-18 19:12:19 -08002995 *dp = &_r_debug;
2996 }
2997 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002998
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002999 case DT_MIPS_RLD_VERSION:
3000 case DT_MIPS_FLAGS:
3001 case DT_MIPS_BASE_ADDRESS:
3002 case DT_MIPS_UNREFEXTNO:
3003 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003004
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003005 case DT_MIPS_SYMTABNO:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003006 mips_symtabno_ = d->d_un.d_val;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003007 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003008
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003009 case DT_MIPS_LOCAL_GOTNO:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003010 mips_local_gotno_ = d->d_un.d_val;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003011 break;
3012
3013 case DT_MIPS_GOTSYM:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003014 mips_gotsym_ = d->d_un.d_val;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003015 break;
3016#endif
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003017 // Ignored: "Its use has been superseded by the DF_BIND_NOW flag"
3018 case DT_BIND_NOW:
3019 break;
3020
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003021 case DT_VERSYM:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003022 versym_ = reinterpret_cast<ElfW(Versym)*>(load_bias + d->d_un.d_ptr);
3023 break;
3024
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003025 case DT_VERDEF:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003026 verdef_ptr_ = load_bias + d->d_un.d_ptr;
3027 break;
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003028 case DT_VERDEFNUM:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003029 verdef_cnt_ = d->d_un.d_val;
3030 break;
3031
Alexander Ivchenkoe8314332014-12-02 15:32:25 +03003032 case DT_VERNEED:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003033 verneed_ptr_ = load_bias + d->d_un.d_ptr;
3034 break;
3035
Alexander Ivchenkoe8314332014-12-02 15:32:25 +03003036 case DT_VERNEEDNUM:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003037 verneed_cnt_ = d->d_un.d_val;
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003038 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003039
Evgenii Stepanov68650822015-06-10 13:38:39 -07003040 case DT_RUNPATH:
3041 // this is parsed after we have strtab initialized (see below).
3042 break;
3043
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003044 default:
Dmitriy Ivanov8f61d992014-09-16 14:31:06 -07003045 if (!relocating_linker) {
Dimitry Ivanov816676e2016-10-19 11:00:28 -07003046 DL_WARN("\"%s\" unused DT entry: type %p arg %p", get_realpath(),
Dmitriy Ivanov8f61d992014-09-16 14:31:06 -07003047 reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
3048 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003049 break;
Brian Carlstromd4ee82d2013-02-28 15:58:45 -08003050 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003051 }
3052
Duane Sandbc425c72015-06-01 16:29:14 -07003053#if defined(__mips__) && !defined(__LP64__)
3054 if (!mips_check_and_adjust_fp_modes()) {
3055 return false;
3056 }
3057#endif
3058
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003059 DEBUG("si->base = %p, si->strtab = %p, si->symtab = %p",
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003060 reinterpret_cast<void*>(base), strtab_, symtab_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003061
3062 // Sanity checks.
3063 if (relocating_linker && needed_count != 0) {
3064 DL_ERR("linker cannot have DT_NEEDED dependencies on other libraries");
3065 return false;
3066 }
Dmitriy Ivanov3597b802015-03-09 12:02:02 -07003067 if (nbucket_ == 0 && gnu_nbucket_ == 0) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003068 DL_ERR("empty/missing DT_HASH/DT_GNU_HASH in \"%s\" "
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003069 "(new hash type from the future?)", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003070 return false;
3071 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003072 if (strtab_ == 0) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003073 DL_ERR("empty/missing DT_STRTAB in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003074 return false;
3075 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003076 if (symtab_ == 0) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003077 DL_ERR("empty/missing DT_SYMTAB in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003078 return false;
3079 }
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003080
Dmitriy Ivanov624b8f12015-06-08 10:41:33 -07003081 // second pass - parse entries relying on strtab
3082 for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
Evgenii Stepanov68650822015-06-10 13:38:39 -07003083 switch (d->d_tag) {
3084 case DT_SONAME:
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07003085 set_soname(get_string(d->d_un.d_val));
Evgenii Stepanov68650822015-06-10 13:38:39 -07003086 break;
3087 case DT_RUNPATH:
Evgenii Stepanov68650822015-06-10 13:38:39 -07003088 set_dt_runpath(get_string(d->d_un.d_val));
3089 break;
Dmitriy Ivanov624b8f12015-06-08 10:41:33 -07003090 }
3091 }
3092
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003093 // Before M release linker was using basename in place of soname.
Dmitriy Ivanov19133522015-06-02 17:36:54 -07003094 // In the case when dt_soname is absent some apps stop working
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003095 // because they can't find dt_needed library by soname.
3096 // This workaround should keep them working. (applies only
Elliott Hughes5bc78c82016-11-16 11:35:43 -08003097 // for apps targeting sdk version < M). Make an exception for
Dmitriy Ivanov19133522015-06-02 17:36:54 -07003098 // the main executable and linker; they do not need to have dt_soname
Dimitry Ivanov3f660572016-09-09 10:00:39 -07003099 if (soname_ == nullptr &&
3100 this != solist_get_somain() &&
3101 (flags_ & FLAG_LINKER) == 0 &&
Elliott Hughes5bc78c82016-11-16 11:35:43 -08003102 get_application_target_sdk_version() < __ANDROID_API_M__) {
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003103 soname_ = basename(realpath_.c_str());
3104 DL_WARN("%s: is missing DT_SONAME will use basename as a replacement: \"%s\"",
3105 get_realpath(), soname_);
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07003106 // Don't call add_dlwarning because a missing DT_SONAME isn't important enough to show in the UI
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003107 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003108 return true;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07003109}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003110
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003111bool soinfo::link_image(const soinfo_list_t& global_group, const soinfo_list_t& local_group,
3112 const android_dlextinfo* extinfo) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003113
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08003114 local_group_root_ = local_group.front();
3115 if (local_group_root_ == nullptr) {
3116 local_group_root_ = this;
3117 }
3118
Dmitriy Ivanov19133522015-06-02 17:36:54 -07003119 if ((flags_ & FLAG_LINKER) == 0 && local_group_root_ == this) {
3120 target_sdk_version_ = get_application_target_sdk_version();
3121 }
3122
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003123 VersionTracker version_tracker;
3124
3125 if (!version_tracker.init(this)) {
3126 return false;
3127 }
3128
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003129#if !defined(__LP64__)
3130 if (has_text_relocations) {
Elliott Hughes5bc78c82016-11-16 11:35:43 -08003131 // Fail if app is targeting M or above.
3132 if (get_application_target_sdk_version() >= __ANDROID_API_M__) {
Dimitry Ivanov816676e2016-10-19 11:00:28 -07003133 DL_ERR_AND_LOG("\"%s\" has text relocations", get_realpath());
Dmitriy Ivanove4ad91f2015-06-12 15:00:31 -07003134 return false;
3135 }
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003136 // Make segments writable to allow text relocations to work properly. We will later call
Dmitriy Ivanov7e039932015-10-01 14:02:19 -07003137 // phdr_table_protect_segments() after all of them are applied.
Dimitry Ivanov816676e2016-10-19 11:00:28 -07003138 DL_WARN("\"%s\" has text relocations. This is wasting memory and prevents "
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003139 "security hardening. Please fix.", get_realpath());
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07003140 add_dlwarning(get_realpath(), "text relocations");
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003141 if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
3142 DL_ERR("can't unprotect loadable segments for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003143 get_realpath(), strerror(errno));
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003144 return false;
3145 }
3146 }
3147#endif
3148
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003149 if (android_relocs_ != nullptr) {
3150 // check signature
3151 if (android_relocs_size_ > 3 &&
3152 android_relocs_[0] == 'A' &&
3153 android_relocs_[1] == 'P' &&
Dmitriy Ivanov18870d32015-04-22 13:10:04 -07003154 android_relocs_[2] == 'S' &&
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003155 android_relocs_[3] == '2') {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003156 DEBUG("[ android relocating %s ]", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003157
3158 bool relocated = false;
3159 const uint8_t* packed_relocs = android_relocs_ + 4;
3160 const size_t packed_relocs_size = android_relocs_size_ - 4;
3161
Dmitriy Ivanov18870d32015-04-22 13:10:04 -07003162 relocated = relocate(
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003163 version_tracker,
Dmitriy Ivanov18870d32015-04-22 13:10:04 -07003164 packed_reloc_iterator<sleb128_decoder>(
3165 sleb128_decoder(packed_relocs, packed_relocs_size)),
3166 global_group, local_group);
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003167
3168 if (!relocated) {
3169 return false;
3170 }
3171 } else {
3172 DL_ERR("bad android relocation header.");
3173 return false;
3174 }
3175 }
3176
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07003177#if defined(USE_RELA)
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003178 if (rela_ != nullptr) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003179 DEBUG("[ relocating %s ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003180 if (!relocate(version_tracker,
3181 plain_reloc_iterator(rela_, rela_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003182 return false;
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07003183 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003184 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003185 if (plt_rela_ != nullptr) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003186 DEBUG("[ relocating %s plt ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003187 if (!relocate(version_tracker,
3188 plain_reloc_iterator(plt_rela_, plt_rela_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003189 return false;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003190 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003191 }
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07003192#else
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003193 if (rel_ != nullptr) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003194 DEBUG("[ relocating %s ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003195 if (!relocate(version_tracker,
3196 plain_reloc_iterator(rel_, rel_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003197 return false;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003198 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003199 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003200 if (plt_rel_ != nullptr) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003201 DEBUG("[ relocating %s plt ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003202 if (!relocate(version_tracker,
3203 plain_reloc_iterator(plt_rel_, plt_rel_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003204 return false;
Brigid Smithc5a13ef2014-07-23 11:22:25 -07003205 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003206 }
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07003207#endif
Brigid Smithc5a13ef2014-07-23 11:22:25 -07003208
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07003209#if defined(__mips__)
Dmitriy Ivanovf39cb632015-04-30 20:17:03 -07003210 if (!mips_relocate_got(version_tracker, global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003211 return false;
3212 }
Raghu Gandhamd7daacb2012-07-31 12:07:22 -07003213#endif
3214
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003215 DEBUG("[ finished linking %s ]", get_realpath());
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003216
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003217#if !defined(__LP64__)
3218 if (has_text_relocations) {
3219 // All relocations are done, we can protect our segments back to read-only.
3220 if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
3221 DL_ERR("can't protect segments for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003222 get_realpath(), strerror(errno));
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003223 return false;
3224 }
3225 }
3226#endif
3227
Mingwei Shibe910522015-11-12 07:02:14 +00003228 // We can also turn on GNU RELRO protection if we're not linking the dynamic linker
3229 // itself --- it can't make system calls yet, and will have to call protect_relro later.
3230 if (!is_linker() && !protect_relro()) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003231 return false;
3232 }
Nick Kralevich9ec0f032012-02-28 10:40:00 -08003233
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003234 /* Handle serializing/sharing the RELRO segment */
3235 if (extinfo && (extinfo->flags & ANDROID_DLEXT_WRITE_RELRO)) {
3236 if (phdr_table_serialize_gnu_relro(phdr, phnum, load_bias,
3237 extinfo->relro_fd) < 0) {
3238 DL_ERR("failed serializing GNU RELRO section for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003239 get_realpath(), strerror(errno));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003240 return false;
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +00003241 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003242 } else if (extinfo && (extinfo->flags & ANDROID_DLEXT_USE_RELRO)) {
3243 if (phdr_table_map_gnu_relro(phdr, phnum, load_bias,
3244 extinfo->relro_fd) < 0) {
3245 DL_ERR("failed mapping GNU RELRO section for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003246 get_realpath(), strerror(errno));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003247 return false;
3248 }
3249 }
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +00003250
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003251 notify_gdb_of_load(this);
3252 return true;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003253}
3254
Mingwei Shibe910522015-11-12 07:02:14 +00003255bool soinfo::protect_relro() {
3256 if (phdr_table_protect_gnu_relro(phdr, phnum, load_bias) < 0) {
3257 DL_ERR("can't enable GNU RELRO protection for \"%s\": %s",
3258 get_realpath(), strerror(errno));
3259 return false;
3260 }
3261 return true;
3262}
3263
Dimitry Ivanov3f660572016-09-09 10:00:39 -07003264void init_default_namespace() {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003265 g_default_namespace.set_name("(default)");
3266 g_default_namespace.set_isolated(false);
3267
Dimitry Ivanov3f660572016-09-09 10:00:39 -07003268 soinfo* somain = solist_get_somain();
3269
Evgenii Stepanovd640b222015-07-10 17:54:01 -07003270 const char *interp = phdr_table_get_interpreter_name(somain->phdr, somain->phnum,
3271 somain->load_bias);
3272 const char* bname = basename(interp);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003273 if (bname && (strcmp(bname, "linker_asan") == 0 || strcmp(bname, "linker_asan64") == 0)) {
Evgenii Stepanovd640b222015-07-10 17:54:01 -07003274 g_default_ld_paths = kAsanDefaultLdPaths;
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -07003275 g_is_asan = true;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003276 } else {
Evgenii Stepanovd640b222015-07-10 17:54:01 -07003277 g_default_ld_paths = kDefaultLdPaths;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003278 }
3279
neo.chae2589f9d2016-10-04 11:00:27 +09003280 char real_path[PATH_MAX];
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003281 std::vector<std::string> ld_default_paths;
3282 for (size_t i = 0; g_default_ld_paths[i] != nullptr; ++i) {
neo.chae2589f9d2016-10-04 11:00:27 +09003283 if (realpath(g_default_ld_paths[i], real_path) != nullptr) {
3284 ld_default_paths.push_back(real_path);
3285 } else {
3286 ld_default_paths.push_back(g_default_ld_paths[i]);
3287 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003288 }
3289
3290 g_default_namespace.set_default_library_paths(std::move(ld_default_paths));
Evgenii Stepanovd640b222015-07-10 17:54:01 -07003291};