blob: ece61873afcdc015ca32afb9357959b5202c8d4b [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 Ivanovec90e242017-02-10 11:04:20 -08001664 child->get_parents().remove(si);
1665
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001666 if (local_unload_list.contains(child)) {
1667 continue;
1668 } else if (child->is_linked() && child->get_local_group_root() != root) {
1669 external_unload_list.push_back(child);
Dimitry Ivanovec90e242017-02-10 11:04:20 -08001670 } else if (child->get_parents().empty()) {
1671 unload_list.push_back(child);
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001672 }
1673 }
1674 } else {
1675#if !defined(__work_around_b_24465209__)
1676 __libc_fatal("soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
1677#else
1678 PRINT("warning: soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
1679 for_each_dt_needed(si, [&] (const char* library_name) {
1680 TRACE("deprecated (old format of soinfo): %s needs to unload %s",
1681 si->get_realpath(), library_name);
1682
1683 soinfo* needed = find_library(si->get_primary_namespace(),
1684 library_name, RTLD_NOLOAD, nullptr, nullptr);
1685
1686 if (needed != nullptr) {
1687 // Not found: for example if symlink was deleted between dlopen and dlclose
1688 // Since we cannot really handle errors at this point - print and continue.
1689 PRINT("warning: couldn't find %s needed by %s on unload.",
1690 library_name, si->get_realpath());
1691 return;
1692 } else if (local_unload_list.contains(needed)) {
1693 // already visited
1694 return;
1695 } else if (needed->is_linked() && needed->get_local_group_root() != root) {
1696 // external group
1697 external_unload_list.push_back(needed);
1698 } else {
1699 // local group
1700 unload_list.push_front(needed);
1701 }
1702 });
1703#endif
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001704 }
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001705 }
1706
1707 local_unload_list.for_each([](soinfo* si) {
1708 si->call_destructors();
1709 });
1710
1711 while ((si = local_unload_list.pop_front()) != nullptr) {
1712 notify_gdb_of_unload(si);
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -07001713 get_cfi_shadow()->BeforeUnload(si);
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001714 soinfo_free(si);
1715 }
1716
1717 while ((si = external_unload_list.pop_front()) != nullptr) {
1718 soinfo_unload(si);
Dmitriy Ivanova2547052014-11-18 12:03:09 -08001719 }
1720}
1721
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001722static std::string symbol_display_name(const char* sym_name, const char* sym_ver) {
1723 if (sym_ver == nullptr) {
1724 return sym_name;
1725 }
1726
Dimitry Ivanov9cf99cb2015-12-11 14:22:24 -08001727 return std::string(sym_name) + ", version " + sym_ver;
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001728}
1729
Dimitry Ivanovaca299a2016-04-11 12:42:58 -07001730static android_namespace_t* get_caller_namespace(soinfo* caller) {
1731 return caller != nullptr ? caller->get_primary_namespace() : g_anonymous_namespace;
1732}
1733
Elliott Hughesa4aafd12014-01-13 16:37:47 -08001734void do_android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size) {
Christopher Ferris052fa3a2014-08-26 20:48:11 -07001735 // Use basic string manipulation calls to avoid snprintf.
1736 // snprintf indirectly calls pthread_getspecific to get the size of a buffer.
1737 // When debug malloc is enabled, this call returns 0. This in turn causes
1738 // snprintf to do nothing, which causes libraries to fail to load.
1739 // See b/17302493 for further details.
1740 // Once the above bug is fixed, this code can be modified to use
1741 // snprintf again.
Evgenii Stepanovd640b222015-07-10 17:54:01 -07001742 size_t required_len = 0;
1743 for (size_t i = 0; g_default_ld_paths[i] != nullptr; ++i) {
1744 required_len += strlen(g_default_ld_paths[i]) + 1;
1745 }
Christopher Ferris052fa3a2014-08-26 20:48:11 -07001746 if (buffer_size < required_len) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07001747 __libc_fatal("android_get_LD_LIBRARY_PATH failed, buffer too small: "
1748 "buffer len %zu, required len %zu", buffer_size, required_len);
Christopher Ferris052fa3a2014-08-26 20:48:11 -07001749 }
Evgenii Stepanovd640b222015-07-10 17:54:01 -07001750 char* end = buffer;
1751 for (size_t i = 0; g_default_ld_paths[i] != nullptr; ++i) {
1752 if (i > 0) *end++ = ':';
1753 end = stpcpy(end, g_default_ld_paths[i]);
1754 }
Elliott Hughesa4aafd12014-01-13 16:37:47 -08001755}
1756
Elliott Hughescade4c32012-12-20 14:42:14 -08001757void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path) {
Nick Kralevich6bb01b62015-03-07 13:37:05 -08001758 parse_LD_LIBRARY_PATH(ld_library_path);
Elliott Hughescade4c32012-12-20 14:42:14 -08001759}
1760
Dimitry Ivanovb996d602016-07-11 18:11:39 -07001761static std::string android_dlextinfo_to_string(const android_dlextinfo* info) {
1762 if (info == nullptr) {
1763 return "(null)";
1764 }
1765
1766 return android::base::StringPrintf("[flags=0x%" PRIx64 ","
1767 " reserved_addr=%p,"
1768 " reserved_size=0x%zx,"
1769 " relro_fd=%d,"
1770 " library_fd=%d,"
1771 " library_fd_offset=0x%" PRIx64 ","
1772 " library_namespace=%s@%p]",
1773 info->flags,
1774 info->reserved_addr,
1775 info->reserved_size,
1776 info->relro_fd,
1777 info->library_fd,
1778 info->library_fd_offset,
1779 (info->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0 ?
1780 (info->library_namespace != nullptr ?
1781 info->library_namespace->get_name() : "(null)") : "(n/a)",
1782 (info->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0 ?
1783 info->library_namespace : nullptr);
1784}
1785
Dimitry Ivanovd9e427c2016-11-22 16:55:25 -08001786void* do_dlopen(const char* name, int flags,
1787 const android_dlextinfo* extinfo,
1788 const void* caller_addr) {
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001789 soinfo* const caller = find_containing_library(caller_addr);
Dimitry Ivanovb996d602016-07-11 18:11:39 -07001790 android_namespace_t* ns = get_caller_namespace(caller);
1791
1792 LD_LOG(kLogDlopen,
1793 "dlopen(name=\"%s\", flags=0x%x, extinfo=%s, caller=\"%s\", caller_ns=%s@%p) ...",
1794 name,
1795 flags,
1796 android_dlextinfo_to_string(extinfo).c_str(),
1797 caller == nullptr ? "(null)" : caller->get_realpath(),
1798 ns == nullptr ? "(null)" : ns->get_name(),
1799 ns);
1800
1801 auto failure_guard = make_scope_guard([&]() {
1802 LD_LOG(kLogDlopen, "... dlopen failed: %s", linker_get_error_buffer());
1803 });
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001804
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -07001805 if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL|RTLD_NODELETE|RTLD_NOLOAD)) != 0) {
Elliott Hughese66190d2012-12-18 15:57:55 -08001806 DL_ERR("invalid flags to dlopen: %x", flags);
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07001807 return nullptr;
Elliott Hughese66190d2012-12-18 15:57:55 -08001808 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001809
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001810 if (extinfo != nullptr) {
1811 if ((extinfo->flags & ~(ANDROID_DLEXT_VALID_FLAG_BITS)) != 0) {
1812 DL_ERR("invalid extended flags to android_dlopen_ext: 0x%" PRIx64, extinfo->flags);
1813 return nullptr;
1814 }
Dmitriy Ivanov126af752015-10-07 16:34:20 -07001815
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001816 if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) == 0 &&
Dmitriy Ivanova6c12792014-10-21 12:09:18 -07001817 (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07001818 DL_ERR("invalid extended flag combination (ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET without "
1819 "ANDROID_DLEXT_USE_LIBRARY_FD): 0x%" PRIx64, extinfo->flags);
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001820 return nullptr;
1821 }
Dmitriy Ivanov126af752015-10-07 16:34:20 -07001822
1823 if ((extinfo->flags & ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS) != 0 &&
1824 (extinfo->flags & (ANDROID_DLEXT_RESERVED_ADDRESS | ANDROID_DLEXT_RESERVED_ADDRESS_HINT)) != 0) {
1825 DL_ERR("invalid extended flag combination: ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS is not "
1826 "compatible with ANDROID_DLEXT_RESERVED_ADDRESS/ANDROID_DLEXT_RESERVED_ADDRESS_HINT");
1827 return nullptr;
1828 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001829
1830 if ((extinfo->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0) {
1831 if (extinfo->library_namespace == nullptr) {
1832 DL_ERR("ANDROID_DLEXT_USE_NAMESPACE is set but extinfo->library_namespace is null");
1833 return nullptr;
1834 }
1835 ns = extinfo->library_namespace;
1836 }
Torne (Richard Coles)012cb452014-02-06 14:34:21 +00001837 }
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -08001838
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -07001839 std::string asan_name_holder;
1840
1841 const char* translated_name = name;
Dimitry Ivanov6c14f862016-12-05 13:35:47 -08001842 if (g_is_asan && translated_name != nullptr && translated_name[0] == '/') {
1843 char translated_path[PATH_MAX];
1844 if (realpath(translated_name, translated_path) != nullptr) {
1845 if (file_is_in_dir(translated_path, kSystemLibDir)) {
1846 asan_name_holder = std::string(kAsanSystemLibDir) + "/" + basename(translated_path);
1847 if (file_exists(asan_name_holder.c_str())) {
1848 translated_name = asan_name_holder.c_str();
1849 PRINT("linker_asan dlopen translating \"%s\" -> \"%s\"", name, translated_name);
1850 }
1851 } else if (file_is_in_dir(translated_path, kVendorLibDir)) {
1852 asan_name_holder = std::string(kAsanVendorLibDir) + "/" + basename(translated_path);
1853 if (file_exists(asan_name_holder.c_str())) {
1854 translated_name = asan_name_holder.c_str();
1855 PRINT("linker_asan dlopen translating \"%s\" -> \"%s\"", name, translated_name);
1856 }
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -07001857 }
1858 }
1859 }
1860
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -08001861 ProtectedDataGuard guard;
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -07001862 soinfo* si = find_library(ns, translated_name, flags, extinfo, caller);
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07001863 if (si != nullptr) {
Dimitry Ivanovb996d602016-07-11 18:11:39 -07001864 void* handle = si->to_handle();
1865 LD_LOG(kLogDlopen,
Dimitry Ivanovae4a0c12016-11-21 10:44:35 -08001866 "... dlopen calling constructors: realpath=\"%s\", soname=\"%s\", handle=%p",
1867 si->get_realpath(), si->get_soname(), handle);
1868 si->call_constructors();
1869 failure_guard.disable();
1870 LD_LOG(kLogDlopen,
Dimitry Ivanovb996d602016-07-11 18:11:39 -07001871 "... dlopen successful: realpath=\"%s\", soname=\"%s\", handle=%p",
1872 si->get_realpath(), si->get_soname(), handle);
1873 return handle;
Elliott Hughesd23736e2012-11-01 15:16:56 -07001874 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001875
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001876 return nullptr;
Elliott Hughesd23736e2012-11-01 15:16:56 -07001877}
1878
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001879int do_dladdr(const void* addr, Dl_info* info) {
1880 // Determine if this address can be found in any library currently mapped.
1881 soinfo* si = find_containing_library(addr);
1882 if (si == nullptr) {
1883 return 0;
1884 }
1885
1886 memset(info, 0, sizeof(Dl_info));
1887
1888 info->dli_fname = si->get_realpath();
1889 // Address at which the shared object is loaded.
1890 info->dli_fbase = reinterpret_cast<void*>(si->base);
1891
1892 // Determine if any symbol in the library contains the specified address.
1893 ElfW(Sym)* sym = si->find_symbol_by_address(addr);
1894 if (sym != nullptr) {
1895 info->dli_sname = si->get_string(sym->st_name);
1896 info->dli_saddr = reinterpret_cast<void*>(si->resolve_symbol_address(sym));
1897 }
1898
1899 return 1;
1900}
1901
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001902static soinfo* soinfo_from_handle(void* handle) {
1903 if ((reinterpret_cast<uintptr_t>(handle) & 1) != 0) {
1904 auto it = g_soinfo_handles_map.find(reinterpret_cast<uintptr_t>(handle));
1905 if (it == g_soinfo_handles_map.end()) {
1906 return nullptr;
1907 } else {
1908 return it->second;
1909 }
1910 }
1911
1912 return static_cast<soinfo*>(handle);
1913}
1914
Dimitry Ivanovd9e427c2016-11-22 16:55:25 -08001915bool do_dlsym(void* handle,
1916 const char* sym_name,
1917 const char* sym_ver,
1918 const void* caller_addr,
1919 void** symbol) {
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001920#if !defined(__LP64__)
1921 if (handle == nullptr) {
1922 DL_ERR("dlsym failed: library handle is null");
1923 return false;
1924 }
1925#endif
1926
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001927 soinfo* found = nullptr;
1928 const ElfW(Sym)* sym = nullptr;
1929 soinfo* caller = find_containing_library(caller_addr);
Dimitry Ivanovaca299a2016-04-11 12:42:58 -07001930 android_namespace_t* ns = get_caller_namespace(caller);
Dimitry Ivanov4742abd2016-12-12 16:30:15 -08001931 soinfo* si = nullptr;
1932 if (handle != RTLD_DEFAULT && handle != RTLD_NEXT) {
1933 si = soinfo_from_handle(handle);
1934 }
1935
1936 LD_LOG(kLogDlsym,
1937 "dlsym(handle=%p(\"%s\"), sym_name=\"%s\", sym_ver=\"%s\", caller=\"%s\", caller_ns=%s@%p) ...",
1938 handle,
1939 si != nullptr ? si->get_realpath() : "n/a",
1940 sym_name,
1941 sym_ver,
1942 caller == nullptr ? "(null)" : caller->get_realpath(),
1943 ns == nullptr ? "(null)" : ns->get_name(),
1944 ns);
1945
1946 auto failure_guard = make_scope_guard([&]() {
1947 LD_LOG(kLogDlsym, "... dlsym failed: %s", linker_get_error_buffer());
1948 });
1949
1950 if (sym_name == nullptr) {
1951 DL_ERR("dlsym failed: symbol name is null");
1952 return false;
1953 }
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001954
1955 version_info vi_instance;
1956 version_info* vi = nullptr;
1957
1958 if (sym_ver != nullptr) {
Dimitry Ivanov9cf99cb2015-12-11 14:22:24 -08001959 vi_instance.name = sym_ver;
1960 vi_instance.elf_hash = calculate_elf_hash(sym_ver);
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001961 vi = &vi_instance;
1962 }
1963
1964 if (handle == RTLD_DEFAULT || handle == RTLD_NEXT) {
1965 sym = dlsym_linear_lookup(ns, sym_name, vi, &found, caller, handle);
1966 } else {
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001967 if (si == nullptr) {
1968 DL_ERR("dlsym failed: invalid handle: %p", handle);
1969 return false;
1970 }
1971 sym = dlsym_handle_lookup(si, &found, sym_name, vi);
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001972 }
1973
1974 if (sym != nullptr) {
1975 uint32_t bind = ELF_ST_BIND(sym->st_info);
1976
1977 if ((bind == STB_GLOBAL || bind == STB_WEAK) && sym->st_shndx != 0) {
1978 *symbol = reinterpret_cast<void*>(found->resolve_symbol_address(sym));
Dimitry Ivanov4742abd2016-12-12 16:30:15 -08001979 failure_guard.disable();
1980 LD_LOG(kLogDlsym,
1981 "... dlsym successful: sym_name=\"%s\", sym_ver=\"%s\", found in=\"%s\", address=%p",
1982 sym_name, sym_ver, found->get_soname(), *symbol);
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001983 return true;
1984 }
1985
1986 DL_ERR("symbol \"%s\" found but not global", symbol_display_name(sym_name, sym_ver).c_str());
1987 return false;
1988 }
1989
1990 DL_ERR("undefined symbol: %s", symbol_display_name(sym_name, sym_ver).c_str());
1991 return false;
1992}
1993
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001994int do_dlclose(void* handle) {
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -08001995 ProtectedDataGuard guard;
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001996 soinfo* si = soinfo_from_handle(handle);
1997 if (si == nullptr) {
1998 DL_ERR("invalid handle: %p", handle);
1999 return -1;
2000 }
2001
Dmitriy Ivanovb648a8a2014-05-19 15:06:58 -07002002 soinfo_unload(si);
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07002003 return 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002004}
2005
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002006bool init_namespaces(const char* public_ns_sonames, const char* anon_ns_library_path) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002007 if (g_public_namespace_initialized) {
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002008 DL_ERR("public namespace has already been initialized.");
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002009 return false;
2010 }
2011
Dimitry Ivanov54807612016-04-21 14:57:38 -07002012 if (public_ns_sonames == nullptr || public_ns_sonames[0] == '\0') {
2013 DL_ERR("error initializing public namespace: the list of public libraries is empty.");
2014 return false;
2015 }
2016
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08002017 auto sonames = android::base::Split(public_ns_sonames, ":");
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002018
2019 ProtectedDataGuard guard;
2020
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08002021 g_public_namespace_sonames = std::unordered_set<std::string>(sonames.begin(), sonames.end());
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002022
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002023 g_public_namespace_initialized = true;
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002024
2025 // create anonymous namespace
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002026 // When the caller is nullptr - create_namespace will take global group
2027 // from the anonymous namespace, which is fine because anonymous namespace
2028 // is still pointing to the default one.
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002029 android_namespace_t* anon_ns =
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002030 create_namespace(nullptr, "(anonymous)", nullptr, anon_ns_library_path,
Dimitry Ivanov52408632016-05-23 10:31:11 -07002031 ANDROID_NAMESPACE_TYPE_REGULAR, nullptr, &g_default_namespace);
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002032
2033 if (anon_ns == nullptr) {
2034 g_public_namespace_initialized = false;
2035 return false;
2036 }
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08002037
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002038 g_anonymous_namespace = anon_ns;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002039 return true;
2040}
2041
Dimitry Ivanovb943f302016-08-03 16:00:10 -07002042static void add_soinfos_to_namespace(const soinfo_list_t& soinfos, android_namespace_t* ns) {
2043 ns->add_soinfos(soinfos);
2044 for (auto si : soinfos) {
2045 si->add_secondary_namespace(ns);
2046 }
2047}
2048
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002049android_namespace_t* create_namespace(const void* caller_addr,
2050 const char* name,
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002051 const char* ld_library_path,
2052 const char* default_library_path,
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002053 uint64_t type,
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002054 const char* permitted_when_isolated_path,
2055 android_namespace_t* parent_namespace) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002056 if (!g_public_namespace_initialized) {
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002057 DL_ERR("cannot create namespace: public namespace is not initialized.");
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002058 return nullptr;
2059 }
2060
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002061 if (parent_namespace == nullptr) {
Dimitry Ivanov52408632016-05-23 10:31:11 -07002062 // if parent_namespace is nullptr -> set it to the caller namespace
2063 soinfo* caller_soinfo = find_containing_library(caller_addr);
2064
2065 parent_namespace = caller_soinfo != nullptr ?
2066 caller_soinfo->get_primary_namespace() :
2067 g_anonymous_namespace;
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002068 }
2069
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002070 ProtectedDataGuard guard;
2071 std::vector<std::string> ld_library_paths;
2072 std::vector<std::string> default_library_paths;
Dimitry Ivanov284ae352015-12-08 10:47:13 -08002073 std::vector<std::string> permitted_paths;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002074
2075 parse_path(ld_library_path, ":", &ld_library_paths);
2076 parse_path(default_library_path, ":", &default_library_paths);
Dimitry Ivanov284ae352015-12-08 10:47:13 -08002077 parse_path(permitted_when_isolated_path, ":", &permitted_paths);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002078
2079 android_namespace_t* ns = new (g_namespace_allocator.alloc()) android_namespace_t();
2080 ns->set_name(name);
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002081 ns->set_isolated((type & ANDROID_NAMESPACE_TYPE_ISOLATED) != 0);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002082 ns->set_ld_library_paths(std::move(ld_library_paths));
2083 ns->set_default_library_paths(std::move(default_library_paths));
Dimitry Ivanov284ae352015-12-08 10:47:13 -08002084 ns->set_permitted_paths(std::move(permitted_paths));
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002085
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002086 if ((type & ANDROID_NAMESPACE_TYPE_SHARED) != 0) {
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002087 // If shared - clone the parent namespace
Dimitry Ivanovb943f302016-08-03 16:00:10 -07002088 add_soinfos_to_namespace(parent_namespace->soinfo_list(), ns);
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002089 } else {
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002090 // If not shared - copy only the shared group
Dimitry Ivanovb943f302016-08-03 16:00:10 -07002091 add_soinfos_to_namespace(get_shared_group(parent_namespace), ns);
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002092 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002093
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08002094 // link it to default namespace
2095 // TODO (dimitry): replace this with user-supplied link once interface is updated
2096 ns->add_linked_namespace(&g_default_namespace, g_public_namespace_sonames);
2097
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002098 return ns;
2099}
2100
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002101ElfW(Addr) call_ifunc_resolver(ElfW(Addr) resolver_addr) {
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07002102 typedef ElfW(Addr) (*ifunc_resolver_t)(void);
2103 ifunc_resolver_t ifunc_resolver = reinterpret_cast<ifunc_resolver_t>(resolver_addr);
2104 ElfW(Addr) ifunc_addr = ifunc_resolver();
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002105 TRACE_TYPE(RELO, "Called ifunc_resolver@%p. The result is %p",
2106 ifunc_resolver, reinterpret_cast<void*>(ifunc_addr));
Brigid Smithc5a13ef2014-07-23 11:22:25 -07002107
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07002108 return ifunc_addr;
Brigid Smithc5a13ef2014-07-23 11:22:25 -07002109}
Brigid Smithc5a13ef2014-07-23 11:22:25 -07002110
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002111const version_info* VersionTracker::get_version_info(ElfW(Versym) source_symver) const {
2112 if (source_symver < 2 ||
2113 source_symver >= version_infos.size() ||
2114 version_infos[source_symver].name == nullptr) {
2115 return nullptr;
2116 }
2117
2118 return &version_infos[source_symver];
2119}
2120
2121void VersionTracker::add_version_info(size_t source_index,
2122 ElfW(Word) elf_hash,
2123 const char* ver_name,
2124 const soinfo* target_si) {
2125 if (source_index >= version_infos.size()) {
2126 version_infos.resize(source_index+1);
2127 }
2128
2129 version_infos[source_index].elf_hash = elf_hash;
2130 version_infos[source_index].name = ver_name;
2131 version_infos[source_index].target_si = target_si;
2132}
2133
2134bool VersionTracker::init_verneed(const soinfo* si_from) {
2135 uintptr_t verneed_ptr = si_from->get_verneed_ptr();
2136
2137 if (verneed_ptr == 0) {
2138 return true;
2139 }
2140
2141 size_t verneed_cnt = si_from->get_verneed_cnt();
2142
2143 for (size_t i = 0, offset = 0; i<verneed_cnt; ++i) {
2144 const ElfW(Verneed)* verneed = reinterpret_cast<ElfW(Verneed)*>(verneed_ptr + offset);
2145 size_t vernaux_offset = offset + verneed->vn_aux;
2146 offset += verneed->vn_next;
2147
2148 if (verneed->vn_version != 1) {
2149 DL_ERR("unsupported verneed[%zd] vn_version: %d (expected 1)", i, verneed->vn_version);
2150 return false;
2151 }
2152
2153 const char* target_soname = si_from->get_string(verneed->vn_file);
2154 // find it in dependencies
2155 soinfo* target_si = si_from->get_children().find_if([&](const soinfo* si) {
Dmitriy Ivanov406d9962015-05-06 11:05:27 -07002156 return si->get_soname() != nullptr && strcmp(si->get_soname(), target_soname) == 0;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002157 });
2158
2159 if (target_si == nullptr) {
2160 DL_ERR("cannot find \"%s\" from verneed[%zd] in DT_NEEDED list for \"%s\"",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002161 target_soname, i, si_from->get_realpath());
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002162 return false;
2163 }
2164
2165 for (size_t j = 0; j<verneed->vn_cnt; ++j) {
2166 const ElfW(Vernaux)* vernaux = reinterpret_cast<ElfW(Vernaux)*>(verneed_ptr + vernaux_offset);
2167 vernaux_offset += vernaux->vna_next;
2168
2169 const ElfW(Word) elf_hash = vernaux->vna_hash;
2170 const char* ver_name = si_from->get_string(vernaux->vna_name);
2171 ElfW(Half) source_index = vernaux->vna_other;
2172
2173 add_version_info(source_index, elf_hash, ver_name, target_si);
2174 }
2175 }
2176
2177 return true;
2178}
2179
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002180template <typename F>
2181static bool for_each_verdef(const soinfo* si, F functor) {
2182 if (!si->has_min_version(2)) {
2183 return true;
2184 }
2185
2186 uintptr_t verdef_ptr = si->get_verdef_ptr();
2187 if (verdef_ptr == 0) {
2188 return true;
2189 }
2190
2191 size_t offset = 0;
2192
2193 size_t verdef_cnt = si->get_verdef_cnt();
2194 for (size_t i = 0; i<verdef_cnt; ++i) {
2195 const ElfW(Verdef)* verdef = reinterpret_cast<ElfW(Verdef)*>(verdef_ptr + offset);
2196 size_t verdaux_offset = offset + verdef->vd_aux;
2197 offset += verdef->vd_next;
2198
2199 if (verdef->vd_version != 1) {
2200 DL_ERR("unsupported verdef[%zd] vd_version: %d (expected 1) library: %s",
2201 i, verdef->vd_version, si->get_realpath());
2202 return false;
2203 }
2204
2205 if ((verdef->vd_flags & VER_FLG_BASE) != 0) {
2206 // "this is the version of the file itself. It must not be used for
2207 // matching a symbol. It can be used to match references."
2208 //
2209 // http://www.akkadia.org/drepper/symbol-versioning
2210 continue;
2211 }
2212
2213 if (verdef->vd_cnt == 0) {
2214 DL_ERR("invalid verdef[%zd] vd_cnt == 0 (version without a name)", i);
2215 return false;
2216 }
2217
2218 const ElfW(Verdaux)* verdaux = reinterpret_cast<ElfW(Verdaux)*>(verdef_ptr + verdaux_offset);
2219
2220 if (functor(i, verdef, verdaux) == true) {
2221 break;
2222 }
2223 }
2224
2225 return true;
2226}
2227
2228bool find_verdef_version_index(const soinfo* si, const version_info* vi, ElfW(Versym)* versym) {
2229 if (vi == nullptr) {
2230 *versym = kVersymNotNeeded;
2231 return true;
2232 }
2233
2234 *versym = kVersymGlobal;
2235
2236 return for_each_verdef(si,
2237 [&](size_t, const ElfW(Verdef)* verdef, const ElfW(Verdaux)* verdaux) {
2238 if (verdef->vd_hash == vi->elf_hash &&
2239 strcmp(vi->name, si->get_string(verdaux->vda_name)) == 0) {
2240 *versym = verdef->vd_ndx;
2241 return true;
2242 }
2243
2244 return false;
2245 }
2246 );
2247}
2248
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002249bool VersionTracker::init_verdef(const soinfo* si_from) {
2250 return for_each_verdef(si_from,
2251 [&](size_t, const ElfW(Verdef)* verdef, const ElfW(Verdaux)* verdaux) {
2252 add_version_info(verdef->vd_ndx, verdef->vd_hash,
2253 si_from->get_string(verdaux->vda_name), si_from);
2254 return false;
2255 }
2256 );
2257}
2258
2259bool VersionTracker::init(const soinfo* si_from) {
2260 if (!si_from->has_min_version(2)) {
2261 return true;
2262 }
2263
2264 return init_verneed(si_from) && init_verdef(si_from);
2265}
2266
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002267// TODO (dimitry): Methods below need to be moved out of soinfo
2268// and in more isolated file in order minimize dependencies on
2269// unnecessary object in the linker binary. Consider making them
2270// independent from soinfo (?).
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002271bool soinfo::lookup_version_info(const VersionTracker& version_tracker, ElfW(Word) sym,
2272 const char* sym_name, const version_info** vi) {
2273 const ElfW(Versym)* sym_ver_ptr = get_versym(sym);
2274 ElfW(Versym) sym_ver = sym_ver_ptr == nullptr ? 0 : *sym_ver_ptr;
2275
2276 if (sym_ver != VER_NDX_LOCAL && sym_ver != VER_NDX_GLOBAL) {
2277 *vi = version_tracker.get_version_info(sym_ver);
2278
2279 if (*vi == nullptr) {
2280 DL_ERR("cannot find verneed/verdef for version index=%d "
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002281 "referenced by symbol \"%s\" at \"%s\"", sym_ver, sym_name, get_realpath());
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002282 return false;
2283 }
2284 } else {
2285 // there is no version info
2286 *vi = nullptr;
2287 }
2288
2289 return true;
2290}
2291
Dimitry Ivanov576a3752016-08-09 06:58:55 -07002292#if !defined(__mips__)
2293#if defined(USE_RELA)
2294static ElfW(Addr) get_addend(ElfW(Rela)* rela, ElfW(Addr) reloc_addr __unused) {
2295 return rela->r_addend;
2296}
2297#else
2298static ElfW(Addr) get_addend(ElfW(Rel)* rel, ElfW(Addr) reloc_addr) {
2299 if (ELFW(R_TYPE)(rel->r_info) == R_GENERIC_RELATIVE ||
2300 ELFW(R_TYPE)(rel->r_info) == R_GENERIC_IRELATIVE) {
2301 return *reinterpret_cast<ElfW(Addr)*>(reloc_addr);
2302 }
2303 return 0;
2304}
2305#endif
2306
Dmitriy Ivanovfa26eee2015-02-03 16:06:47 -08002307template<typename ElfRelIteratorT>
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07002308bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& rel_iterator,
2309 const soinfo_list_t& global_group, const soinfo_list_t& local_group) {
Dmitriy Ivanovfa26eee2015-02-03 16:06:47 -08002310 for (size_t idx = 0; rel_iterator.has_next(); ++idx) {
2311 const auto rel = rel_iterator.next();
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002312 if (rel == nullptr) {
2313 return false;
2314 }
2315
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002316 ElfW(Word) type = ELFW(R_TYPE)(rel->r_info);
2317 ElfW(Word) sym = ELFW(R_SYM)(rel->r_info);
2318
2319 ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rel->r_offset + load_bias);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002320 ElfW(Addr) sym_addr = 0;
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07002321 const char* sym_name = nullptr;
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002322 ElfW(Addr) addend = get_addend(rel, reloc);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002323
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07002324 DEBUG("Processing \"%s\" relocation at index %zd", get_realpath(), idx);
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002325 if (type == R_GENERIC_NONE) {
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002326 continue;
2327 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002328
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002329 const ElfW(Sym)* s = nullptr;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002330 soinfo* lsi = nullptr;
2331
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002332 if (sym != 0) {
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002333 sym_name = get_string(symtab_[sym].st_name);
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002334 const version_info* vi = nullptr;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002335
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002336 if (!lookup_version_info(version_tracker, sym, sym_name, &vi)) {
2337 return false;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002338 }
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002339
2340 if (!soinfo_do_lookup(this, sym_name, vi, &lsi, global_group, local_group, &s)) {
2341 return false;
2342 }
2343
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07002344 if (s == nullptr) {
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002345 // We only allow an undefined symbol if this is a weak reference...
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002346 s = &symtab_[sym];
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002347 if (ELF_ST_BIND(s->st_info) != STB_WEAK) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002348 DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, get_realpath());
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002349 return false;
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002350 }
2351
2352 /* IHI0044C AAELF 4.5.1.1:
2353
2354 Libraries are not searched to resolve weak references.
2355 It is not an error for a weak reference to remain unsatisfied.
2356
2357 During linking, the value of an undefined weak reference is:
2358 - Zero if the relocation type is absolute
2359 - The address of the place if the relocation is pc-relative
2360 - The address of nominal base address if the relocation
2361 type is base-relative.
2362 */
2363
2364 switch (type) {
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002365 case R_GENERIC_JUMP_SLOT:
2366 case R_GENERIC_GLOB_DAT:
2367 case R_GENERIC_RELATIVE:
2368 case R_GENERIC_IRELATIVE:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002369#if defined(__aarch64__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002370 case R_AARCH64_ABS64:
2371 case R_AARCH64_ABS32:
2372 case R_AARCH64_ABS16:
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002373#elif defined(__x86_64__)
2374 case R_X86_64_32:
2375 case R_X86_64_64:
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002376#elif defined(__arm__)
2377 case R_ARM_ABS32:
2378#elif defined(__i386__)
2379 case R_386_32:
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002380#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002381 /*
2382 * The sym_addr was initialized to be zero above, or the relocation
2383 * code below does not care about value of sym_addr.
2384 * No need to do anything.
2385 */
2386 break;
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002387#if defined(__x86_64__)
Dimitry Ivanovd338aac2015-01-13 22:31:54 +00002388 case R_X86_64_PC32:
2389 sym_addr = reloc;
2390 break;
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002391#elif defined(__i386__)
2392 case R_386_PC32:
2393 sym_addr = reloc;
2394 break;
2395#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002396 default:
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002397 DL_ERR("unknown weak reloc type %d @ %p (%zu)", type, rel, idx);
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002398 return false;
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002399 }
Dmitriy Ivanovec83a612015-07-26 07:37:09 -07002400 } else { // We got a definition.
2401#if !defined(__LP64__)
2402 // When relocating dso with text_relocation .text segment is
2403 // not executable. We need to restore elf flags before resolving
2404 // STT_GNU_IFUNC symbol.
2405 bool protect_segments = has_text_relocations &&
2406 lsi == this &&
2407 ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC;
2408 if (protect_segments) {
2409 if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
2410 DL_ERR("can't protect segments for \"%s\": %s",
2411 get_realpath(), strerror(errno));
2412 return false;
2413 }
2414 }
2415#endif
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07002416 sym_addr = lsi->resolve_symbol_address(s);
Dmitriy Ivanovec83a612015-07-26 07:37:09 -07002417#if !defined(__LP64__)
2418 if (protect_segments) {
2419 if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
2420 DL_ERR("can't unprotect loadable segments for \"%s\": %s",
2421 get_realpath(), strerror(errno));
2422 return false;
2423 }
2424 }
2425#endif
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002426 }
2427 count_relocation(kRelocSymbol);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002428 }
2429
2430 switch (type) {
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002431 case R_GENERIC_JUMP_SLOT:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002432 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002433 MARK(rel->r_offset);
2434 TRACE_TYPE(RELO, "RELO JMP_SLOT %16p <- %16p %s\n",
2435 reinterpret_cast<void*>(reloc),
2436 reinterpret_cast<void*>(sym_addr + addend), sym_name);
2437
2438 *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002439 break;
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002440 case R_GENERIC_GLOB_DAT:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002441 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002442 MARK(rel->r_offset);
2443 TRACE_TYPE(RELO, "RELO GLOB_DAT %16p <- %16p %s\n",
2444 reinterpret_cast<void*>(reloc),
2445 reinterpret_cast<void*>(sym_addr + addend), sym_name);
2446 *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002447 break;
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002448 case R_GENERIC_RELATIVE:
2449 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002450 MARK(rel->r_offset);
2451 TRACE_TYPE(RELO, "RELO RELATIVE %16p <- %16p\n",
2452 reinterpret_cast<void*>(reloc),
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002453 reinterpret_cast<void*>(load_bias + addend));
2454 *reinterpret_cast<ElfW(Addr)*>(reloc) = (load_bias + addend);
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002455 break;
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002456 case R_GENERIC_IRELATIVE:
2457 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002458 MARK(rel->r_offset);
2459 TRACE_TYPE(RELO, "RELO IRELATIVE %16p <- %16p\n",
2460 reinterpret_cast<void*>(reloc),
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002461 reinterpret_cast<void*>(load_bias + addend));
Dmitriy Ivanovec83a612015-07-26 07:37:09 -07002462 {
2463#if !defined(__LP64__)
2464 // When relocating dso with text_relocation .text segment is
2465 // not executable. We need to restore elf flags for this
2466 // particular call.
2467 if (has_text_relocations) {
2468 if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
2469 DL_ERR("can't protect segments for \"%s\": %s",
2470 get_realpath(), strerror(errno));
2471 return false;
2472 }
2473 }
2474#endif
2475 ElfW(Addr) ifunc_addr = call_ifunc_resolver(load_bias + addend);
2476#if !defined(__LP64__)
2477 // Unprotect it afterwards...
2478 if (has_text_relocations) {
2479 if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
2480 DL_ERR("can't unprotect loadable segments for \"%s\": %s",
2481 get_realpath(), strerror(errno));
2482 return false;
2483 }
2484 }
2485#endif
2486 *reinterpret_cast<ElfW(Addr)*>(reloc) = ifunc_addr;
2487 }
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002488 break;
2489
2490#if defined(__aarch64__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002491 case R_AARCH64_ABS64:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002492 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002493 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002494 TRACE_TYPE(RELO, "RELO ABS64 %16llx <- %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002495 reloc, sym_addr + addend, sym_name);
2496 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend;
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002497 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002498 case R_AARCH64_ABS32:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002499 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002500 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002501 TRACE_TYPE(RELO, "RELO ABS32 %16llx <- %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002502 reloc, sym_addr + addend, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002503 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002504 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT32_MIN);
2505 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT32_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002506 if ((min_value <= (sym_addr + addend)) &&
2507 ((sym_addr + addend) <= max_value)) {
2508 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend;
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002509 } else {
2510 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002511 sym_addr + addend, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002512 return false;
2513 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002514 }
2515 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002516 case R_AARCH64_ABS16:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002517 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002518 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002519 TRACE_TYPE(RELO, "RELO ABS16 %16llx <- %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002520 reloc, sym_addr + addend, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002521 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002522 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN);
2523 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT16_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002524 if ((min_value <= (sym_addr + addend)) &&
2525 ((sym_addr + addend) <= max_value)) {
2526 *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002527 } else {
2528 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002529 sym_addr + addend, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002530 return false;
2531 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002532 }
2533 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002534 case R_AARCH64_PREL64:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002535 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002536 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002537 TRACE_TYPE(RELO, "RELO REL64 %16llx <- %16llx - %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002538 reloc, sym_addr + addend, rel->r_offset, sym_name);
2539 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset;
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002540 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002541 case R_AARCH64_PREL32:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002542 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002543 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002544 TRACE_TYPE(RELO, "RELO REL32 %16llx <- %16llx - %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002545 reloc, sym_addr + addend, rel->r_offset, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002546 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002547 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT32_MIN);
2548 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT32_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002549 if ((min_value <= (sym_addr + addend - rel->r_offset)) &&
2550 ((sym_addr + addend - rel->r_offset) <= max_value)) {
2551 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset;
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002552 } else {
2553 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002554 sym_addr + addend - rel->r_offset, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002555 return false;
2556 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002557 }
2558 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002559 case R_AARCH64_PREL16:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002560 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002561 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002562 TRACE_TYPE(RELO, "RELO REL16 %16llx <- %16llx - %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002563 reloc, sym_addr + addend, rel->r_offset, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002564 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002565 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN);
2566 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT16_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002567 if ((min_value <= (sym_addr + addend - rel->r_offset)) &&
2568 ((sym_addr + addend - rel->r_offset) <= max_value)) {
2569 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset;
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002570 } else {
2571 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002572 sym_addr + addend - rel->r_offset, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002573 return false;
2574 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002575 }
2576 break;
2577
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002578 case R_AARCH64_COPY:
Nick Kralevich76e289c2014-07-03 12:04:31 -07002579 /*
2580 * ET_EXEC is not supported so this should not happen.
2581 *
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002582 * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0056b/IHI0056B_aaelf64.pdf
Nick Kralevich76e289c2014-07-03 12:04:31 -07002583 *
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002584 * Section 4.6.11 "Dynamic relocations"
Nick Kralevich76e289c2014-07-03 12:04:31 -07002585 * R_AARCH64_COPY may only appear in executable objects where e_type is
2586 * set to ET_EXEC.
2587 */
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002588 DL_ERR("%s R_AARCH64_COPY relocations are not supported", get_realpath());
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002589 return false;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002590 case R_AARCH64_TLS_TPREL64:
Elliott Hughes0266ae52014-02-10 17:46:57 -08002591 TRACE_TYPE(RELO, "RELO TLS_TPREL64 *** %16llx <- %16llx - %16llx\n",
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002592 reloc, (sym_addr + addend), rel->r_offset);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002593 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002594 case R_AARCH64_TLS_DTPREL32:
Elliott Hughes0266ae52014-02-10 17:46:57 -08002595 TRACE_TYPE(RELO, "RELO TLS_DTPREL32 *** %16llx <- %16llx - %16llx\n",
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002596 reloc, (sym_addr + addend), rel->r_offset);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002597 break;
2598#elif defined(__x86_64__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002599 case R_X86_64_32:
2600 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002601 MARK(rel->r_offset);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002602 TRACE_TYPE(RELO, "RELO R_X86_64_32 %08zx <- +%08zx %s", static_cast<size_t>(reloc),
2603 static_cast<size_t>(sym_addr), sym_name);
Junichi Uekawaff35b1e2015-11-18 10:18:59 +09002604 *reinterpret_cast<Elf32_Addr*>(reloc) = sym_addr + addend;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002605 break;
2606 case R_X86_64_64:
2607 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002608 MARK(rel->r_offset);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002609 TRACE_TYPE(RELO, "RELO R_X86_64_64 %08zx <- +%08zx %s", static_cast<size_t>(reloc),
2610 static_cast<size_t>(sym_addr), sym_name);
Junichi Uekawaff35b1e2015-11-18 10:18:59 +09002611 *reinterpret_cast<Elf64_Addr*>(reloc) = sym_addr + addend;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002612 break;
2613 case R_X86_64_PC32:
2614 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002615 MARK(rel->r_offset);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002616 TRACE_TYPE(RELO, "RELO R_X86_64_PC32 %08zx <- +%08zx (%08zx - %08zx) %s",
2617 static_cast<size_t>(reloc), static_cast<size_t>(sym_addr - reloc),
2618 static_cast<size_t>(sym_addr), static_cast<size_t>(reloc), sym_name);
Junichi Uekawaff35b1e2015-11-18 10:18:59 +09002619 *reinterpret_cast<Elf32_Addr*>(reloc) = sym_addr + addend - reloc;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002620 break;
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002621#elif defined(__arm__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002622 case R_ARM_ABS32:
2623 count_relocation(kRelocAbsolute);
2624 MARK(rel->r_offset);
2625 TRACE_TYPE(RELO, "RELO ABS %08x <- %08x %s", reloc, sym_addr, sym_name);
2626 *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
2627 break;
2628 case R_ARM_REL32:
2629 count_relocation(kRelocRelative);
2630 MARK(rel->r_offset);
2631 TRACE_TYPE(RELO, "RELO REL32 %08x <- %08x - %08x %s",
2632 reloc, sym_addr, rel->r_offset, sym_name);
2633 *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr - rel->r_offset;
2634 break;
2635 case R_ARM_COPY:
2636 /*
2637 * ET_EXEC is not supported so this should not happen.
2638 *
2639 * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044d/IHI0044D_aaelf.pdf
2640 *
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002641 * Section 4.6.1.10 "Dynamic relocations"
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002642 * R_ARM_COPY may only appear in executable objects where e_type is
2643 * set to ET_EXEC.
2644 */
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002645 DL_ERR("%s R_ARM_COPY relocations are not supported", get_realpath());
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002646 return false;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002647#elif defined(__i386__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002648 case R_386_32:
2649 count_relocation(kRelocRelative);
2650 MARK(rel->r_offset);
2651 TRACE_TYPE(RELO, "RELO R_386_32 %08x <- +%08x %s", reloc, sym_addr, sym_name);
2652 *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
2653 break;
2654 case R_386_PC32:
2655 count_relocation(kRelocRelative);
2656 MARK(rel->r_offset);
2657 TRACE_TYPE(RELO, "RELO R_386_PC32 %08x <- +%08x (%08x - %08x) %s",
2658 reloc, (sym_addr - reloc), sym_addr, reloc, sym_name);
2659 *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr - reloc);
2660 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002661#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002662 default:
2663 DL_ERR("unknown reloc type %d @ %p (%zu)", type, rel, idx);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002664 return false;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002665 }
2666 }
2667 return true;
Raghu Gandhamd7daacb2012-07-31 12:07:22 -07002668}
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002669#endif // !defined(__mips__)
Raghu Gandhamd7daacb2012-07-31 12:07:22 -07002670
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002671// An empty list of soinfos
Dimitry Ivanovb943f302016-08-03 16:00:10 -07002672static soinfo_list_t g_empty_list;
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07002673
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002674bool soinfo::prelink_image() {
Ningsheng Jiane93be992014-09-16 15:22:10 +08002675 /* Extract dynamic section */
2676 ElfW(Word) dynamic_flags = 0;
2677 phdr_table_get_dynamic_section(phdr, phnum, load_bias, &dynamic, &dynamic_flags);
Dmitriy Ivanov498eb182014-09-05 14:57:59 -07002678
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002679 /* We can't log anything until the linker is relocated */
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002680 bool relocating_linker = (flags_ & FLAG_LINKER) != 0;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002681 if (!relocating_linker) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07002682 INFO("[ Linking \"%s\" ]", get_realpath());
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002683 DEBUG("si->base = %p si->flags = 0x%08x", reinterpret_cast<void*>(base), flags_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002684 }
2685
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002686 if (dynamic == nullptr) {
David 'Digit' Turnerb52e4382012-06-19 01:24:17 +02002687 if (!relocating_linker) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002688 DL_ERR("missing PT_DYNAMIC in \"%s\"", get_realpath());
David 'Digit' Turnerb52e4382012-06-19 01:24:17 +02002689 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002690 return false;
2691 } else {
2692 if (!relocating_linker) {
2693 DEBUG("dynamic = %p", dynamic);
David 'Digit' Turner63f99f42012-06-19 00:08:39 +02002694 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002695 }
David 'Digit' Turner63f99f42012-06-19 00:08:39 +02002696
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07002697#if defined(__arm__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002698 (void) phdr_table_get_arm_exidx(phdr, phnum, load_bias,
2699 &ARM_exidx, &ARM_exidx_count);
David 'Digit' Turner63f99f42012-06-19 00:08:39 +02002700#endif
2701
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002702 // Extract useful information from dynamic section.
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07002703 // Note that: "Except for the DT_NULL element at the end of the array,
2704 // and the relative order of DT_NEEDED elements, entries may appear in any order."
2705 //
2706 // source: http://www.sco.com/developers/gabi/1998-04-29/ch5.dynamic.html
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002707 uint32_t needed_count = 0;
2708 for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
2709 DEBUG("d = %p, d[0](tag) = %p d[1](val) = %p",
2710 d, reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
2711 switch (d->d_tag) {
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002712 case DT_SONAME:
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07002713 // this is parsed after we have strtab initialized (see below).
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002714 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002715
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002716 case DT_HASH:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002717 nbucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0];
2718 nchain_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
2719 bucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8);
2720 chain_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8 + nbucket_ * 4);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002721 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002722
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002723 case DT_GNU_HASH:
Dmitriy Ivanov3597b802015-03-09 12:02:02 -07002724 gnu_nbucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0];
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002725 // skip symndx
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002726 gnu_maskwords_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[2];
2727 gnu_shift2_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[3];
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002728
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002729 gnu_bloom_filter_ = reinterpret_cast<ElfW(Addr)*>(load_bias + d->d_un.d_ptr + 16);
Dmitriy Ivanov3597b802015-03-09 12:02:02 -07002730 gnu_bucket_ = reinterpret_cast<uint32_t*>(gnu_bloom_filter_ + gnu_maskwords_);
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002731 // amend chain for symndx = header[1]
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002732 gnu_chain_ = gnu_bucket_ + gnu_nbucket_ -
2733 reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002734
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002735 if (!powerof2(gnu_maskwords_)) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002736 DL_ERR("invalid maskwords for gnu_hash = 0x%x, in \"%s\" expecting power to two",
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002737 gnu_maskwords_, get_realpath());
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002738 return false;
2739 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002740 --gnu_maskwords_;
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002741
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002742 flags_ |= FLAG_GNU_HASH;
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002743 break;
2744
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002745 case DT_STRTAB:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002746 strtab_ = reinterpret_cast<const char*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002747 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002748
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07002749 case DT_STRSZ:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002750 strtab_size_ = d->d_un.d_val;
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07002751 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002752
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002753 case DT_SYMTAB:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002754 symtab_ = reinterpret_cast<ElfW(Sym)*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002755 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002756
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002757 case DT_SYMENT:
2758 if (d->d_un.d_val != sizeof(ElfW(Sym))) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002759 DL_ERR("invalid DT_SYMENT: %zd in \"%s\"",
2760 static_cast<size_t>(d->d_un.d_val), get_realpath());
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002761 return false;
2762 }
2763 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002764
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002765 case DT_PLTREL:
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002766#if defined(USE_RELA)
2767 if (d->d_un.d_val != DT_RELA) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002768 DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_RELA", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002769 return false;
2770 }
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002771#else
2772 if (d->d_un.d_val != DT_REL) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002773 DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_REL", get_realpath());
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002774 return false;
2775 }
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002776#endif
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002777 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002778
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002779 case DT_JMPREL:
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07002780#if defined(USE_RELA)
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002781 plt_rela_ = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002782#else
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002783 plt_rel_ = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002784#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002785 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002786
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002787 case DT_PLTRELSZ:
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07002788#if defined(USE_RELA)
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002789 plt_rela_count_ = d->d_un.d_val / sizeof(ElfW(Rela));
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002790#else
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002791 plt_rel_count_ = d->d_un.d_val / sizeof(ElfW(Rel));
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002792#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002793 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002794
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002795 case DT_PLTGOT:
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002796#if defined(__mips__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002797 // Used by mips and mips64.
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002798 plt_got_ = reinterpret_cast<ElfW(Addr)**>(load_bias + d->d_un.d_ptr);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002799#endif
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002800 // Ignore for other platforms... (because RTLD_LAZY is not supported)
2801 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002802
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002803 case DT_DEBUG:
2804 // Set the DT_DEBUG entry to the address of _r_debug for GDB
2805 // if the dynamic table is writable
Chris Dearman99186652014-02-06 20:36:51 -08002806// FIXME: not working currently for N64
2807// The flags for the LOAD and DYNAMIC program headers do not agree.
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002808// The LOAD section containing the dynamic table has been mapped as
Chris Dearman99186652014-02-06 20:36:51 -08002809// read-only, but the DYNAMIC header claims it is writable.
2810#if !(defined(__mips__) && defined(__LP64__))
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002811 if ((dynamic_flags & PF_W) != 0) {
2812 d->d_un.d_val = reinterpret_cast<uintptr_t>(&_r_debug);
2813 }
Chris Dearman99186652014-02-06 20:36:51 -08002814#endif
Dmitriy Ivanovc6292ea2015-02-13 16:29:50 -08002815 break;
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07002816#if defined(USE_RELA)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002817 case DT_RELA:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002818 rela_ = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002819 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002820
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002821 case DT_RELASZ:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002822 rela_count_ = d->d_un.d_val / sizeof(ElfW(Rela));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002823 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002824
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002825 case DT_ANDROID_RELA:
2826 android_relocs_ = reinterpret_cast<uint8_t*>(load_bias + d->d_un.d_ptr);
2827 break;
2828
2829 case DT_ANDROID_RELASZ:
2830 android_relocs_size_ = d->d_un.d_val;
2831 break;
2832
2833 case DT_ANDROID_REL:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002834 DL_ERR("unsupported DT_ANDROID_REL in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002835 return false;
2836
2837 case DT_ANDROID_RELSZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002838 DL_ERR("unsupported DT_ANDROID_RELSZ in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002839 return false;
2840
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002841 case DT_RELAENT:
2842 if (d->d_un.d_val != sizeof(ElfW(Rela))) {
Dmitriy Ivanovf240aa82014-09-16 23:34:20 -07002843 DL_ERR("invalid DT_RELAENT: %zd", static_cast<size_t>(d->d_un.d_val));
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002844 return false;
2845 }
2846 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002847
2848 // ignored (see DT_RELCOUNT comments for details)
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002849 case DT_RELACOUNT:
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002850 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002851
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002852 case DT_REL:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002853 DL_ERR("unsupported DT_REL in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002854 return false;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002855
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002856 case DT_RELSZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002857 DL_ERR("unsupported DT_RELSZ in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002858 return false;
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002859
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002860#else
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002861 case DT_REL:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002862 rel_ = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002863 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002864
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002865 case DT_RELSZ:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002866 rel_count_ = d->d_un.d_val / sizeof(ElfW(Rel));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002867 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002868
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002869 case DT_RELENT:
2870 if (d->d_un.d_val != sizeof(ElfW(Rel))) {
Dmitriy Ivanovf240aa82014-09-16 23:34:20 -07002871 DL_ERR("invalid DT_RELENT: %zd", static_cast<size_t>(d->d_un.d_val));
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002872 return false;
2873 }
2874 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002875
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002876 case DT_ANDROID_REL:
2877 android_relocs_ = reinterpret_cast<uint8_t*>(load_bias + d->d_un.d_ptr);
2878 break;
2879
2880 case DT_ANDROID_RELSZ:
2881 android_relocs_size_ = d->d_un.d_val;
2882 break;
2883
2884 case DT_ANDROID_RELA:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002885 DL_ERR("unsupported DT_ANDROID_RELA in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002886 return false;
2887
2888 case DT_ANDROID_RELASZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002889 DL_ERR("unsupported DT_ANDROID_RELASZ in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002890 return false;
2891
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002892 // "Indicates that all RELATIVE relocations have been concatenated together,
2893 // and specifies the RELATIVE relocation count."
2894 //
2895 // TODO: Spec also mentions that this can be used to optimize relocation process;
2896 // Not currently used by bionic linker - ignored.
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002897 case DT_RELCOUNT:
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002898 break;
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002899
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002900 case DT_RELA:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002901 DL_ERR("unsupported DT_RELA in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002902 return false;
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002903
2904 case DT_RELASZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002905 DL_ERR("unsupported DT_RELASZ in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002906 return false;
2907
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002908#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002909 case DT_INIT:
Dimitry Ivanov55437462016-07-20 15:33:07 -07002910 init_func_ = reinterpret_cast<linker_ctor_function_t>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002911 DEBUG("%s constructors (DT_INIT) found at %p", get_realpath(), init_func_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002912 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002913
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002914 case DT_FINI:
Dimitry Ivanov55437462016-07-20 15:33:07 -07002915 fini_func_ = reinterpret_cast<linker_dtor_function_t>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002916 DEBUG("%s destructors (DT_FINI) found at %p", get_realpath(), fini_func_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002917 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002918
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002919 case DT_INIT_ARRAY:
Dimitry Ivanov55437462016-07-20 15:33:07 -07002920 init_array_ = reinterpret_cast<linker_ctor_function_t*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002921 DEBUG("%s constructors (DT_INIT_ARRAY) found at %p", get_realpath(), init_array_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002922 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002923
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002924 case DT_INIT_ARRAYSZ:
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -08002925 init_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002926 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002927
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002928 case DT_FINI_ARRAY:
Dimitry Ivanov55437462016-07-20 15:33:07 -07002929 fini_array_ = reinterpret_cast<linker_dtor_function_t*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002930 DEBUG("%s destructors (DT_FINI_ARRAY) found at %p", get_realpath(), fini_array_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002931 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002932
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002933 case DT_FINI_ARRAYSZ:
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -08002934 fini_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002935 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002936
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002937 case DT_PREINIT_ARRAY:
Dimitry Ivanov55437462016-07-20 15:33:07 -07002938 preinit_array_ = reinterpret_cast<linker_ctor_function_t*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002939 DEBUG("%s constructors (DT_PREINIT_ARRAY) found at %p", get_realpath(), preinit_array_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002940 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002941
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002942 case DT_PREINIT_ARRAYSZ:
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -08002943 preinit_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002944 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002945
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002946 case DT_TEXTREL:
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00002947#if defined(__LP64__)
Dimitry Ivanov816676e2016-10-19 11:00:28 -07002948 DL_ERR("\"%s\" has text relocations", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002949 return false;
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00002950#else
2951 has_text_relocations = true;
2952 break;
2953#endif
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002954
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002955 case DT_SYMBOLIC:
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -07002956 has_DT_SYMBOLIC = true;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002957 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002958
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002959 case DT_NEEDED:
2960 ++needed_count;
2961 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002962
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002963 case DT_FLAGS:
2964 if (d->d_un.d_val & DF_TEXTREL) {
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00002965#if defined(__LP64__)
Dimitry Ivanov816676e2016-10-19 11:00:28 -07002966 DL_ERR("\"%s\" has text relocations", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002967 return false;
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00002968#else
2969 has_text_relocations = true;
2970#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002971 }
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -07002972 if (d->d_un.d_val & DF_SYMBOLIC) {
2973 has_DT_SYMBOLIC = true;
2974 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002975 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002976
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07002977 case DT_FLAGS_1:
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07002978 set_dt_flags_1(d->d_un.d_val);
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -07002979
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07002980 if ((d->d_un.d_val & ~SUPPORTED_DT_FLAGS_1) != 0) {
Dimitry Ivanov816676e2016-10-19 11:00:28 -07002981 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 -07002982 }
2983 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002984#if defined(__mips__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002985 case DT_MIPS_RLD_MAP:
2986 // Set the DT_MIPS_RLD_MAP entry to the address of _r_debug for GDB.
2987 {
2988 r_debug** dp = reinterpret_cast<r_debug**>(load_bias + d->d_un.d_ptr);
2989 *dp = &_r_debug;
2990 }
2991 break;
Lazar Trsic83b44a92016-04-06 13:39:17 +02002992 case DT_MIPS_RLD_MAP_REL:
2993 // Set the DT_MIPS_RLD_MAP_REL entry to the address of _r_debug for GDB.
Raghu Gandham68815722014-12-18 19:12:19 -08002994 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002995 r_debug** dp = reinterpret_cast<r_debug**>(
2996 reinterpret_cast<ElfW(Addr)>(d) + d->d_un.d_val);
Raghu Gandham68815722014-12-18 19:12:19 -08002997 *dp = &_r_debug;
2998 }
2999 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003000
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003001 case DT_MIPS_RLD_VERSION:
3002 case DT_MIPS_FLAGS:
3003 case DT_MIPS_BASE_ADDRESS:
3004 case DT_MIPS_UNREFEXTNO:
3005 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003006
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003007 case DT_MIPS_SYMTABNO:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003008 mips_symtabno_ = d->d_un.d_val;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003009 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003010
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003011 case DT_MIPS_LOCAL_GOTNO:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003012 mips_local_gotno_ = d->d_un.d_val;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003013 break;
3014
3015 case DT_MIPS_GOTSYM:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003016 mips_gotsym_ = d->d_un.d_val;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003017 break;
3018#endif
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003019 // Ignored: "Its use has been superseded by the DF_BIND_NOW flag"
3020 case DT_BIND_NOW:
3021 break;
3022
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003023 case DT_VERSYM:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003024 versym_ = reinterpret_cast<ElfW(Versym)*>(load_bias + d->d_un.d_ptr);
3025 break;
3026
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003027 case DT_VERDEF:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003028 verdef_ptr_ = load_bias + d->d_un.d_ptr;
3029 break;
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003030 case DT_VERDEFNUM:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003031 verdef_cnt_ = d->d_un.d_val;
3032 break;
3033
Alexander Ivchenkoe8314332014-12-02 15:32:25 +03003034 case DT_VERNEED:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003035 verneed_ptr_ = load_bias + d->d_un.d_ptr;
3036 break;
3037
Alexander Ivchenkoe8314332014-12-02 15:32:25 +03003038 case DT_VERNEEDNUM:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003039 verneed_cnt_ = d->d_un.d_val;
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003040 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003041
Evgenii Stepanov68650822015-06-10 13:38:39 -07003042 case DT_RUNPATH:
3043 // this is parsed after we have strtab initialized (see below).
3044 break;
3045
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003046 default:
Dmitriy Ivanov8f61d992014-09-16 14:31:06 -07003047 if (!relocating_linker) {
Dimitry Ivanov816676e2016-10-19 11:00:28 -07003048 DL_WARN("\"%s\" unused DT entry: type %p arg %p", get_realpath(),
Dmitriy Ivanov8f61d992014-09-16 14:31:06 -07003049 reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
3050 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003051 break;
Brian Carlstromd4ee82d2013-02-28 15:58:45 -08003052 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003053 }
3054
Duane Sandbc425c72015-06-01 16:29:14 -07003055#if defined(__mips__) && !defined(__LP64__)
3056 if (!mips_check_and_adjust_fp_modes()) {
3057 return false;
3058 }
3059#endif
3060
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003061 DEBUG("si->base = %p, si->strtab = %p, si->symtab = %p",
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003062 reinterpret_cast<void*>(base), strtab_, symtab_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003063
3064 // Sanity checks.
3065 if (relocating_linker && needed_count != 0) {
3066 DL_ERR("linker cannot have DT_NEEDED dependencies on other libraries");
3067 return false;
3068 }
Dmitriy Ivanov3597b802015-03-09 12:02:02 -07003069 if (nbucket_ == 0 && gnu_nbucket_ == 0) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003070 DL_ERR("empty/missing DT_HASH/DT_GNU_HASH in \"%s\" "
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003071 "(new hash type from the future?)", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003072 return false;
3073 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003074 if (strtab_ == 0) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003075 DL_ERR("empty/missing DT_STRTAB in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003076 return false;
3077 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003078 if (symtab_ == 0) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003079 DL_ERR("empty/missing DT_SYMTAB in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003080 return false;
3081 }
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003082
Dmitriy Ivanov624b8f12015-06-08 10:41:33 -07003083 // second pass - parse entries relying on strtab
3084 for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
Evgenii Stepanov68650822015-06-10 13:38:39 -07003085 switch (d->d_tag) {
3086 case DT_SONAME:
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07003087 set_soname(get_string(d->d_un.d_val));
Evgenii Stepanov68650822015-06-10 13:38:39 -07003088 break;
3089 case DT_RUNPATH:
Evgenii Stepanov68650822015-06-10 13:38:39 -07003090 set_dt_runpath(get_string(d->d_un.d_val));
3091 break;
Dmitriy Ivanov624b8f12015-06-08 10:41:33 -07003092 }
3093 }
3094
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003095 // Before M release linker was using basename in place of soname.
Dmitriy Ivanov19133522015-06-02 17:36:54 -07003096 // In the case when dt_soname is absent some apps stop working
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003097 // because they can't find dt_needed library by soname.
3098 // This workaround should keep them working. (applies only
Elliott Hughes5bc78c82016-11-16 11:35:43 -08003099 // for apps targeting sdk version < M). Make an exception for
Dmitriy Ivanov19133522015-06-02 17:36:54 -07003100 // the main executable and linker; they do not need to have dt_soname
Dimitry Ivanov3f660572016-09-09 10:00:39 -07003101 if (soname_ == nullptr &&
3102 this != solist_get_somain() &&
3103 (flags_ & FLAG_LINKER) == 0 &&
Elliott Hughes5bc78c82016-11-16 11:35:43 -08003104 get_application_target_sdk_version() < __ANDROID_API_M__) {
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003105 soname_ = basename(realpath_.c_str());
3106 DL_WARN("%s: is missing DT_SONAME will use basename as a replacement: \"%s\"",
3107 get_realpath(), soname_);
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07003108 // 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 -07003109 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003110 return true;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07003111}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003112
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003113bool soinfo::link_image(const soinfo_list_t& global_group, const soinfo_list_t& local_group,
3114 const android_dlextinfo* extinfo) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003115
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08003116 local_group_root_ = local_group.front();
3117 if (local_group_root_ == nullptr) {
3118 local_group_root_ = this;
3119 }
3120
Dmitriy Ivanov19133522015-06-02 17:36:54 -07003121 if ((flags_ & FLAG_LINKER) == 0 && local_group_root_ == this) {
3122 target_sdk_version_ = get_application_target_sdk_version();
3123 }
3124
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003125 VersionTracker version_tracker;
3126
3127 if (!version_tracker.init(this)) {
3128 return false;
3129 }
3130
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003131#if !defined(__LP64__)
3132 if (has_text_relocations) {
Elliott Hughes5bc78c82016-11-16 11:35:43 -08003133 // Fail if app is targeting M or above.
3134 if (get_application_target_sdk_version() >= __ANDROID_API_M__) {
Dimitry Ivanov816676e2016-10-19 11:00:28 -07003135 DL_ERR_AND_LOG("\"%s\" has text relocations", get_realpath());
Dmitriy Ivanove4ad91f2015-06-12 15:00:31 -07003136 return false;
3137 }
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003138 // Make segments writable to allow text relocations to work properly. We will later call
Dmitriy Ivanov7e039932015-10-01 14:02:19 -07003139 // phdr_table_protect_segments() after all of them are applied.
Dimitry Ivanov816676e2016-10-19 11:00:28 -07003140 DL_WARN("\"%s\" has text relocations. This is wasting memory and prevents "
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003141 "security hardening. Please fix.", get_realpath());
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07003142 add_dlwarning(get_realpath(), "text relocations");
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003143 if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
3144 DL_ERR("can't unprotect loadable segments for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003145 get_realpath(), strerror(errno));
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003146 return false;
3147 }
3148 }
3149#endif
3150
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003151 if (android_relocs_ != nullptr) {
3152 // check signature
3153 if (android_relocs_size_ > 3 &&
3154 android_relocs_[0] == 'A' &&
3155 android_relocs_[1] == 'P' &&
Dmitriy Ivanov18870d32015-04-22 13:10:04 -07003156 android_relocs_[2] == 'S' &&
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003157 android_relocs_[3] == '2') {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003158 DEBUG("[ android relocating %s ]", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003159
3160 bool relocated = false;
3161 const uint8_t* packed_relocs = android_relocs_ + 4;
3162 const size_t packed_relocs_size = android_relocs_size_ - 4;
3163
Dmitriy Ivanov18870d32015-04-22 13:10:04 -07003164 relocated = relocate(
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003165 version_tracker,
Dmitriy Ivanov18870d32015-04-22 13:10:04 -07003166 packed_reloc_iterator<sleb128_decoder>(
3167 sleb128_decoder(packed_relocs, packed_relocs_size)),
3168 global_group, local_group);
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003169
3170 if (!relocated) {
3171 return false;
3172 }
3173 } else {
3174 DL_ERR("bad android relocation header.");
3175 return false;
3176 }
3177 }
3178
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07003179#if defined(USE_RELA)
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003180 if (rela_ != nullptr) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003181 DEBUG("[ relocating %s ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003182 if (!relocate(version_tracker,
3183 plain_reloc_iterator(rela_, rela_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003184 return false;
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07003185 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003186 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003187 if (plt_rela_ != nullptr) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003188 DEBUG("[ relocating %s plt ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003189 if (!relocate(version_tracker,
3190 plain_reloc_iterator(plt_rela_, plt_rela_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003191 return false;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003192 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003193 }
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07003194#else
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003195 if (rel_ != nullptr) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003196 DEBUG("[ relocating %s ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003197 if (!relocate(version_tracker,
3198 plain_reloc_iterator(rel_, rel_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003199 return false;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003200 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003201 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003202 if (plt_rel_ != nullptr) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003203 DEBUG("[ relocating %s plt ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003204 if (!relocate(version_tracker,
3205 plain_reloc_iterator(plt_rel_, plt_rel_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003206 return false;
Brigid Smithc5a13ef2014-07-23 11:22:25 -07003207 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003208 }
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07003209#endif
Brigid Smithc5a13ef2014-07-23 11:22:25 -07003210
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07003211#if defined(__mips__)
Dmitriy Ivanovf39cb632015-04-30 20:17:03 -07003212 if (!mips_relocate_got(version_tracker, global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003213 return false;
3214 }
Raghu Gandhamd7daacb2012-07-31 12:07:22 -07003215#endif
3216
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003217 DEBUG("[ finished linking %s ]", get_realpath());
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003218
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003219#if !defined(__LP64__)
3220 if (has_text_relocations) {
3221 // All relocations are done, we can protect our segments back to read-only.
3222 if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
3223 DL_ERR("can't protect segments for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003224 get_realpath(), strerror(errno));
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003225 return false;
3226 }
3227 }
3228#endif
3229
Mingwei Shibe910522015-11-12 07:02:14 +00003230 // We can also turn on GNU RELRO protection if we're not linking the dynamic linker
3231 // itself --- it can't make system calls yet, and will have to call protect_relro later.
3232 if (!is_linker() && !protect_relro()) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003233 return false;
3234 }
Nick Kralevich9ec0f032012-02-28 10:40:00 -08003235
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003236 /* Handle serializing/sharing the RELRO segment */
3237 if (extinfo && (extinfo->flags & ANDROID_DLEXT_WRITE_RELRO)) {
3238 if (phdr_table_serialize_gnu_relro(phdr, phnum, load_bias,
3239 extinfo->relro_fd) < 0) {
3240 DL_ERR("failed serializing GNU RELRO section for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003241 get_realpath(), strerror(errno));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003242 return false;
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +00003243 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003244 } else if (extinfo && (extinfo->flags & ANDROID_DLEXT_USE_RELRO)) {
3245 if (phdr_table_map_gnu_relro(phdr, phnum, load_bias,
3246 extinfo->relro_fd) < 0) {
3247 DL_ERR("failed mapping GNU RELRO section for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003248 get_realpath(), strerror(errno));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003249 return false;
3250 }
3251 }
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +00003252
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003253 notify_gdb_of_load(this);
3254 return true;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003255}
3256
Mingwei Shibe910522015-11-12 07:02:14 +00003257bool soinfo::protect_relro() {
3258 if (phdr_table_protect_gnu_relro(phdr, phnum, load_bias) < 0) {
3259 DL_ERR("can't enable GNU RELRO protection for \"%s\": %s",
3260 get_realpath(), strerror(errno));
3261 return false;
3262 }
3263 return true;
3264}
3265
Dimitry Ivanov3f660572016-09-09 10:00:39 -07003266void init_default_namespace() {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003267 g_default_namespace.set_name("(default)");
3268 g_default_namespace.set_isolated(false);
3269
Dimitry Ivanov3f660572016-09-09 10:00:39 -07003270 soinfo* somain = solist_get_somain();
3271
Evgenii Stepanovd640b222015-07-10 17:54:01 -07003272 const char *interp = phdr_table_get_interpreter_name(somain->phdr, somain->phnum,
3273 somain->load_bias);
3274 const char* bname = basename(interp);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003275 if (bname && (strcmp(bname, "linker_asan") == 0 || strcmp(bname, "linker_asan64") == 0)) {
Evgenii Stepanovd640b222015-07-10 17:54:01 -07003276 g_default_ld_paths = kAsanDefaultLdPaths;
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -07003277 g_is_asan = true;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003278 } else {
Evgenii Stepanovd640b222015-07-10 17:54:01 -07003279 g_default_ld_paths = kDefaultLdPaths;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003280 }
3281
neo.chae2589f9d2016-10-04 11:00:27 +09003282 char real_path[PATH_MAX];
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003283 std::vector<std::string> ld_default_paths;
3284 for (size_t i = 0; g_default_ld_paths[i] != nullptr; ++i) {
neo.chae2589f9d2016-10-04 11:00:27 +09003285 if (realpath(g_default_ld_paths[i], real_path) != nullptr) {
3286 ld_default_paths.push_back(real_path);
3287 } else {
3288 ld_default_paths.push_back(g_default_ld_paths[i]);
3289 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003290 }
3291
3292 g_default_namespace.set_default_library_paths(std::move(ld_default_paths));
Evgenii Stepanovd640b222015-07-10 17:54:01 -07003293};