blob: 80743237949436e8f0a7ec18ea4717510d37ed41 [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
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800188static bool g_anonymous_namespace_initialized;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700189
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800190#if STATS
Elliott Hughesbedfe382012-08-14 14:07:59 -0700191struct linker_stats_t {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700192 int count[kRelocMax];
Elliott Hughesbedfe382012-08-14 14:07:59 -0700193};
194
195static linker_stats_t linker_stats;
196
Dmitriy Ivanov114ff692015-01-14 11:36:38 -0800197void count_relocation(RelocationKind kind) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700198 ++linker_stats.count[kind];
Elliott Hughesbedfe382012-08-14 14:07:59 -0700199}
200#else
Dmitriy Ivanov114ff692015-01-14 11:36:38 -0800201void count_relocation(RelocationKind) {
Elliott Hughesbedfe382012-08-14 14:07:59 -0700202}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800203#endif
204
205#if COUNT_PAGES
Dmitriy Ivanov114ff692015-01-14 11:36:38 -0800206uint32_t bitmask[4096];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800207#endif
208
Elliott Hughesbedfe382012-08-14 14:07:59 -0700209static void notify_gdb_of_load(soinfo* info) {
Dimitry Ivanove97d8ed2016-03-01 15:55:56 -0800210 if (info->is_linker() || info->is_main_executable()) {
211 // gdb already knows about the linker and the main executable.
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700212 return;
213 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800214
Dimitry Ivanov6b788ee2016-02-17 16:08:03 -0800215 link_map* map = &(info->link_map_head);
Nicolas Geoffray0fa54102016-02-18 09:31:24 +0000216
Dimitry Ivanov6b788ee2016-02-17 16:08:03 -0800217 map->l_addr = info->load_bias;
218 // link_map l_name field is not const.
219 map->l_name = const_cast<char*>(info->get_realpath());
220 map->l_ld = info->dynamic;
Nicolas Geoffray0fa54102016-02-18 09:31:24 +0000221
Dimitry Ivanove97d8ed2016-03-01 15:55:56 -0800222 CHECK(map->l_name != nullptr);
223 CHECK(map->l_name[0] != '\0');
224
Dimitry Ivanov6b788ee2016-02-17 16:08:03 -0800225 notify_gdb_of_load(map);
Iliyan Malchev5e12d7e2009-03-24 19:02:00 -0700226}
227
Elliott Hughesbedfe382012-08-14 14:07:59 -0700228static void notify_gdb_of_unload(soinfo* info) {
Dimitry Ivanov6b788ee2016-02-17 16:08:03 -0800229 notify_gdb_of_unload(&(info->link_map_head));
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800230}
231
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -0700232LinkedListEntry<soinfo>* SoinfoListAllocator::alloc() {
233 return g_soinfo_links_allocator.alloc();
234}
235
236void SoinfoListAllocator::free(LinkedListEntry<soinfo>* entry) {
237 g_soinfo_links_allocator.free(entry);
238}
239
Dimitry Ivanovaca299a2016-04-11 12:42:58 -0700240LinkedListEntry<android_namespace_t>* NamespaceListAllocator::alloc() {
241 return g_namespace_list_allocator.alloc();
242}
243
244void NamespaceListAllocator::free(LinkedListEntry<android_namespace_t>* entry) {
245 g_namespace_list_allocator.free(entry);
246}
247
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700248soinfo* soinfo_alloc(android_namespace_t* ns, const char* name,
249 struct stat* file_stat, off64_t file_offset,
250 uint32_t rtld_flags) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700251 if (strlen(name) >= PATH_MAX) {
Magnus Malmbornba98d922012-09-12 13:00:55 +0200252 DL_ERR("library name \"%s\" too long", name);
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700253 return nullptr;
Magnus Malmbornba98d922012-09-12 13:00:55 +0200254 }
255
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700256 TRACE("name %s: allocating soinfo for ns=%p", name, ns);
257
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700258 soinfo* si = new (g_soinfo_allocator.alloc()) soinfo(ns, name, file_stat,
259 file_offset, rtld_flags);
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -0700260
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700261 solist_add_soinfo(si);
Magnus Malmbornba98d922012-09-12 13:00:55 +0200262
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -0700263 si->generate_handle();
264 ns->add_soinfo(si);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700265
Elliott Hughesca0c11b2013-03-12 10:40:45 -0700266 TRACE("name %s: allocated soinfo @ %p", name, si);
Magnus Malmbornba98d922012-09-12 13:00:55 +0200267 return si;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800268}
269
Elliott Hughesfaf05ba2014-02-11 16:59:37 -0800270static void soinfo_free(soinfo* si) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700271 if (si == nullptr) {
272 return;
273 }
274
275 if (si->base != 0 && si->size != 0) {
Dimitry Ivanovf45b0e92016-01-15 11:13:35 -0800276 if (!si->is_mapped_by_caller()) {
277 munmap(reinterpret_cast<void*>(si->base), si->size);
278 } else {
279 // remap the region as PROT_NONE, MAP_ANONYMOUS | MAP_NORESERVE
280 mmap(reinterpret_cast<void*>(si->base), si->size, PROT_NONE,
281 MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
282 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700283 }
284
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700285 TRACE("name %s: freeing soinfo @ %p", si->get_realpath(), si);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700286
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700287 if (!solist_remove_soinfo(si)) {
288 // TODO (dimitry): revisit this - for now preserving the logic
289 // but it does not look right, abort if soinfo is not in the list instead?
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700290 return;
291 }
Elliott Hughes46882792012-08-03 16:49:39 -0700292
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700293 // clear links to/from si
294 si->remove_all_links();
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -0700295
Dmitriy Ivanov609f11b2015-07-08 15:26:46 -0700296 si->~soinfo();
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700297 g_soinfo_allocator.free(si);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800298}
299
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700300static void parse_path(const char* path, const char* delimiters,
301 std::vector<std::string>* resolved_paths) {
302 std::vector<std::string> paths;
303 split_path(path, delimiters, &paths);
304 resolve_paths(paths, resolved_paths);
305}
306
Elliott Hughescade4c32012-12-20 14:42:14 -0800307static void parse_LD_LIBRARY_PATH(const char* path) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700308 std::vector<std::string> ld_libary_paths;
309 parse_path(path, ":", &ld_libary_paths);
310 g_default_namespace.set_ld_library_paths(std::move(ld_libary_paths));
Elliott Hughescade4c32012-12-20 14:42:14 -0800311}
312
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700313static bool realpath_fd(int fd, std::string* realpath) {
314 std::vector<char> buf(PATH_MAX), proc_self_fd(PATH_MAX);
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700315 __libc_format_buffer(&proc_self_fd[0], proc_self_fd.size(), "/proc/self/fd/%d", fd);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700316 if (readlink(&proc_self_fd[0], &buf[0], buf.size()) == -1) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700317 PRINT("readlink(\"%s\") failed: %s [fd=%d]", &proc_self_fd[0], strerror(errno), fd);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700318 return false;
319 }
320
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700321 *realpath = &buf[0];
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700322 return true;
323}
324
Elliott Hughes4eeb1f12013-10-25 17:38:02 -0700325#if defined(__arm__)
Elliott Hughes46882792012-08-03 16:49:39 -0700326
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700327// For a given PC, find the .so that it belongs to.
328// Returns the base address of the .ARM.exidx section
329// for that .so, and the number of 8-byte entries
330// in that section (via *pcount).
331//
332// Intended to be called by libc's __gnu_Unwind_Find_exidx().
Dimitry Ivanovd9e427c2016-11-22 16:55:25 -0800333_Unwind_Ptr do_dl_unwind_find_exidx(_Unwind_Ptr pc, int* pcount) {
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -0800334 uintptr_t addr = reinterpret_cast<uintptr_t>(pc);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800335
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700336 for (soinfo* si = solist_get_head(); si != 0; si = si->next) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700337 if ((addr >= si->base) && (addr < (si->base + si->size))) {
338 *pcount = si->ARM_exidx_count;
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -0800339 return reinterpret_cast<_Unwind_Ptr>(si->ARM_exidx);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800340 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700341 }
342 *pcount = 0;
343 return nullptr;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800344}
Elliott Hughes46882792012-08-03 16:49:39 -0700345
Christopher Ferris24053a42013-08-19 17:45:09 -0700346#endif
Elliott Hughes46882792012-08-03 16:49:39 -0700347
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700348// Here, we only have to provide a callback to iterate across all the
349// loaded libraries. gcc_eh does the rest.
Dmitriy Ivanov7271caf2015-06-29 14:48:25 -0700350int do_dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void* data) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700351 int rv = 0;
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700352 for (soinfo* si = solist_get_head(); si != nullptr; si = si->next) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700353 dl_phdr_info dl_info;
354 dl_info.dlpi_addr = si->link_map_head.l_addr;
355 dl_info.dlpi_name = si->link_map_head.l_name;
356 dl_info.dlpi_phdr = si->phdr;
357 dl_info.dlpi_phnum = si->phnum;
358 rv = cb(&dl_info, sizeof(dl_phdr_info), data);
359 if (rv != 0) {
360 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800361 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700362 }
363 return rv;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800364}
Elliott Hughes46882792012-08-03 16:49:39 -0700365
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800366
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700367bool soinfo_do_lookup(soinfo* si_from, const char* name, const version_info* vi,
Dimitry Ivanovb943f302016-08-03 16:00:10 -0700368 soinfo** si_found_in, const soinfo_list_t& global_group,
369 const soinfo_list_t& local_group, const ElfW(Sym)** symbol) {
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800370 SymbolName symbol_name(name);
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700371 const ElfW(Sym)* s = nullptr;
Iliyan Malchev6ed80c82009-09-28 19:38:04 -0700372
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -0700373 /* "This element's presence in a shared object library alters the dynamic linker's
374 * symbol resolution algorithm for references within the library. Instead of starting
375 * a symbol search with the executable file, the dynamic linker starts from the shared
376 * object itself. If the shared object fails to supply the referenced symbol, the
377 * dynamic linker then searches the executable file and other shared objects as usual."
378 *
379 * http://www.sco.com/developers/gabi/2012-12-31/ch5.dynamic.html
380 *
381 * Note that this is unlikely since static linker avoids generating
382 * relocations for -Bsymbolic linked dynamic executables.
383 */
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700384 if (si_from->has_DT_SYMBOLIC) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700385 DEBUG("%s: looking up %s in local scope (DT_SYMBOLIC)", si_from->get_realpath(), name);
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700386 if (!si_from->find_symbol_by_name(symbol_name, vi, &s)) {
387 return false;
388 }
389
Dmitriy Ivanov8f61d992014-09-16 14:31:06 -0700390 if (s != nullptr) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700391 *si_found_in = si_from;
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -0700392 }
393 }
394
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700395 // 1. Look for it in global_group
396 if (s == nullptr) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700397 bool error = false;
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700398 global_group.visit([&](soinfo* global_si) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700399 DEBUG("%s: looking up %s in %s (from global group)",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700400 si_from->get_realpath(), name, global_si->get_realpath());
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700401 if (!global_si->find_symbol_by_name(symbol_name, vi, &s)) {
402 error = true;
403 return false;
404 }
405
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -0700406 if (s != nullptr) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700407 *si_found_in = global_si;
408 return false;
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -0700409 }
Dmitriy Ivanovc2048942014-08-29 10:15:25 -0700410
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700411 return true;
412 });
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700413
414 if (error) {
415 return false;
416 }
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -0700417 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700418
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700419 // 2. Look for it in the local group
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700420 if (s == nullptr) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700421 bool error = false;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700422 local_group.visit([&](soinfo* local_si) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700423 if (local_si == si_from && si_from->has_DT_SYMBOLIC) {
Dmitriy Ivanove47b3f82014-10-23 14:19:07 -0700424 // we already did this - skip
425 return true;
426 }
427
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700428 DEBUG("%s: looking up %s in %s (from local group)",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700429 si_from->get_realpath(), name, local_si->get_realpath());
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700430 if (!local_si->find_symbol_by_name(symbol_name, vi, &s)) {
431 error = true;
432 return false;
433 }
434
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700435 if (s != nullptr) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700436 *si_found_in = local_si;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700437 return false;
438 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700439
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700440 return true;
441 });
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700442
443 if (error) {
444 return false;
445 }
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700446 }
447
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700448 if (s != nullptr) {
449 TRACE_TYPE(LOOKUP, "si %s sym %s s->st_value = %p, "
450 "found in %s, base = %p, load bias = %p",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700451 si_from->get_realpath(), name, reinterpret_cast<void*>(s->st_value),
452 (*si_found_in)->get_realpath(), reinterpret_cast<void*>((*si_found_in)->base),
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700453 reinterpret_cast<void*>((*si_found_in)->load_bias));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700454 }
Iliyan Malchev6ed80c82009-09-28 19:38:04 -0700455
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700456 *symbol = s;
457 return true;
Iliyan Malchev6ed80c82009-09-28 19:38:04 -0700458}
459
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700460ProtectedDataGuard::ProtectedDataGuard() {
461 if (ref_count_++ == 0) {
462 protect_data(PROT_READ | PROT_WRITE);
463 }
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700464
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700465 if (ref_count_ == 0) { // overflow
466 __libc_fatal("Too many nested calls to dlopen()");
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -0800467 }
Dimitry Ivanov68e6c032017-02-01 12:55:11 -0800468}
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -0800469
Dimitry Ivanov68e6c032017-02-01 12:55:11 -0800470ProtectedDataGuard::~ProtectedDataGuard() {
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700471 if (--ref_count_ == 0) {
472 protect_data(PROT_READ);
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -0800473 }
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700474}
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -0800475
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700476void ProtectedDataGuard::protect_data(int protection) {
477 g_soinfo_allocator.protect_all(protection);
478 g_soinfo_links_allocator.protect_all(protection);
479 g_namespace_allocator.protect_all(protection);
480 g_namespace_list_allocator.protect_all(protection);
481}
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -0800482
483size_t ProtectedDataGuard::ref_count_ = 0;
484
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700485// Each size has it's own allocator.
486template<size_t size>
487class SizeBasedAllocator {
488 public:
489 static void* alloc() {
490 return allocator_.alloc();
491 }
Dmitriy Ivanov4bea4982014-08-29 14:01:48 -0700492
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700493 static void free(void* ptr) {
494 allocator_.free(ptr);
495 }
Dmitriy Ivanov4bea4982014-08-29 14:01:48 -0700496
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700497 private:
498 static LinkerBlockAllocator allocator_;
499};
500
501template<size_t size>
502LinkerBlockAllocator SizeBasedAllocator<size>::allocator_(size);
503
504template<typename T>
505class TypeBasedAllocator {
506 public:
507 static T* alloc() {
508 return reinterpret_cast<T*>(SizeBasedAllocator<sizeof(T)>::alloc());
509 }
510
511 static void free(T* ptr) {
512 SizeBasedAllocator<sizeof(T)>::free(ptr);
513 }
514};
515
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700516class LoadTask {
517 public:
518 struct deleter_t {
519 void operator()(LoadTask* t) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700520 t->~LoadTask();
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700521 TypeBasedAllocator<LoadTask>::free(t);
522 }
523 };
524
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700525 static deleter_t deleter;
526
Dimitry Ivanov7d429d32017-02-01 15:28:52 -0800527 static LoadTask* create(const char* name,
528 soinfo* needed_by,
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700529 std::unordered_map<const soinfo*, ElfReader>* readers_map) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700530 LoadTask* ptr = TypeBasedAllocator<LoadTask>::alloc();
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700531 return new (ptr) LoadTask(name, needed_by, readers_map);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700532 }
533
534 const char* get_name() const {
535 return name_;
536 }
537
538 soinfo* get_needed_by() const {
539 return needed_by_;
540 }
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700541
542 soinfo* get_soinfo() const {
543 return si_;
544 }
545
546 void set_soinfo(soinfo* si) {
547 si_ = si;
548 }
549
550 off64_t get_file_offset() const {
551 return file_offset_;
552 }
553
554 void set_file_offset(off64_t offset) {
555 file_offset_ = offset;
556 }
557
558 int get_fd() const {
559 return fd_;
560 }
561
562 void set_fd(int fd, bool assume_ownership) {
563 fd_ = fd;
564 close_fd_ = assume_ownership;
565 }
566
567 const android_dlextinfo* get_extinfo() const {
568 return extinfo_;
569 }
570
571 void set_extinfo(const android_dlextinfo* extinfo) {
572 extinfo_ = extinfo;
573 }
574
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700575 bool is_dt_needed() const {
576 return is_dt_needed_;
577 }
578
579 void set_dt_needed(bool is_dt_needed) {
580 is_dt_needed_ = is_dt_needed;
581 }
582
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700583 const ElfReader& get_elf_reader() const {
584 CHECK(si_ != nullptr);
585 return (*elf_readers_map_)[si_];
586 }
587
588 ElfReader& get_elf_reader() {
589 CHECK(si_ != nullptr);
590 return (*elf_readers_map_)[si_];
591 }
592
593 std::unordered_map<const soinfo*, ElfReader>* get_readers_map() {
594 return elf_readers_map_;
595 }
596
597 bool read(const char* realpath, off64_t file_size) {
598 ElfReader& elf_reader = get_elf_reader();
599 return elf_reader.Read(realpath, fd_, file_offset_, file_size);
600 }
601
602 bool load() {
603 ElfReader& elf_reader = get_elf_reader();
604 if (!elf_reader.Load(extinfo_)) {
605 return false;
606 }
607
608 si_->base = elf_reader.load_start();
609 si_->size = elf_reader.load_size();
Dimitry Ivanovf45b0e92016-01-15 11:13:35 -0800610 si_->set_mapped_by_caller(elf_reader.is_mapped_by_caller());
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700611 si_->load_bias = elf_reader.load_bias();
612 si_->phnum = elf_reader.phdr_count();
613 si_->phdr = elf_reader.loaded_phdr();
614
615 return true;
616 }
617
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700618 private:
Dimitry Ivanov7d429d32017-02-01 15:28:52 -0800619 LoadTask(const char* name,
620 soinfo* needed_by,
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700621 std::unordered_map<const soinfo*, ElfReader>* readers_map)
622 : name_(name), needed_by_(needed_by), si_(nullptr),
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700623 fd_(-1), close_fd_(false), file_offset_(0), elf_readers_map_(readers_map),
624 is_dt_needed_(false) {}
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700625
626 ~LoadTask() {
627 if (fd_ != -1 && close_fd_) {
628 close(fd_);
629 }
630 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700631
632 const char* name_;
633 soinfo* needed_by_;
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700634 soinfo* si_;
635 const android_dlextinfo* extinfo_;
636 int fd_;
637 bool close_fd_;
638 off64_t file_offset_;
639 std::unordered_map<const soinfo*, ElfReader>* elf_readers_map_;
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700640 // TODO(dimitry): needed by workaround for http://b/26394120 (the grey-list)
641 bool is_dt_needed_;
642 // END OF WORKAROUND
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700643
644 DISALLOW_IMPLICIT_CONSTRUCTORS(LoadTask);
645};
646
Ningsheng Jiane93be992014-09-16 15:22:10 +0800647LoadTask::deleter_t LoadTask::deleter;
648
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700649template <typename T>
650using linked_list_t = LinkedList<T, TypeBasedAllocator<LinkedListEntry<T>>>;
651
652typedef linked_list_t<soinfo> SoinfoLinkedList;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700653typedef linked_list_t<const char> StringLinkedList;
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700654typedef std::vector<LoadTask*> LoadTaskList;
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700655
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800656enum walk_action_result_t : uint32_t {
657 kWalkStop = 0,
658 kWalkContinue = 1,
659 kWalkSkip = 2
660};
Dmitriy Ivanovaa0f2bd2014-07-28 17:32:20 -0700661
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700662// This function walks down the tree of soinfo dependencies
663// in breadth-first order and
664// * calls action(soinfo* si) for each node, and
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800665// * terminates walk if action returns kWalkStop
666// * skips children of the node if action
667// return kWalkSkip
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700668//
669// walk_dependencies_tree returns false if walk was terminated
670// by the action and true otherwise.
671template<typename F>
672static bool walk_dependencies_tree(soinfo* root_soinfos[], size_t root_soinfos_size, F action) {
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700673 SoinfoLinkedList visit_list;
674 SoinfoLinkedList visited;
675
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700676 for (size_t i = 0; i < root_soinfos_size; ++i) {
677 visit_list.push_back(root_soinfos[i]);
678 }
679
680 soinfo* si;
681 while ((si = visit_list.pop_front()) != nullptr) {
682 if (visited.contains(si)) {
Dmitriy Ivanov042426b2014-08-12 21:02:13 -0700683 continue;
684 }
685
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800686 walk_action_result_t result = action(si);
687
688 if (result == kWalkStop) {
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700689 return false;
Dmitriy Ivanovaa0f2bd2014-07-28 17:32:20 -0700690 }
691
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700692 visited.push_back(si);
693
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800694 if (result != kWalkSkip) {
695 si->get_children().for_each([&](soinfo* child) {
696 visit_list.push_back(child);
697 });
698 }
Dmitriy Ivanovaa0f2bd2014-07-28 17:32:20 -0700699 }
700
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700701 return true;
702}
703
704
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800705static const ElfW(Sym)* dlsym_handle_lookup(android_namespace_t* ns,
706 soinfo* root,
707 soinfo* skip_until,
708 soinfo** found,
709 SymbolName& symbol_name,
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800710 const version_info* vi) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700711 const ElfW(Sym)* result = nullptr;
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700712 bool skip_lookup = skip_until != nullptr;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700713
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700714 walk_dependencies_tree(&root, 1, [&](soinfo* current_soinfo) {
715 if (skip_lookup) {
716 skip_lookup = current_soinfo != skip_until;
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800717 return kWalkContinue;
718 }
719
720 if (!ns->is_accessible(current_soinfo)) {
721 return kWalkSkip;
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700722 }
723
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800724 if (!current_soinfo->find_symbol_by_name(symbol_name, vi, &result)) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700725 result = nullptr;
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800726 return kWalkStop;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700727 }
728
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700729 if (result != nullptr) {
730 *found = current_soinfo;
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800731 return kWalkStop;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700732 }
733
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800734 return kWalkContinue;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700735 });
736
737 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800738}
739
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800740static const ElfW(Sym)* dlsym_linear_lookup(android_namespace_t* ns,
741 const char* name,
742 const version_info* vi,
743 soinfo** found,
744 soinfo* caller,
745 void* handle);
746
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700747// This is used by dlsym(3). It performs symbol lookup only within the
748// specified soinfo object and its dependencies in breadth first order.
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800749static const ElfW(Sym)* dlsym_handle_lookup(soinfo* si,
750 soinfo** found,
751 const char* name,
752 const version_info* vi) {
Dmitriy Ivanovf439b5a2015-05-30 13:04:39 -0700753 // According to man dlopen(3) and posix docs in the case when si is handle
754 // of the main executable we need to search not only in the executable and its
755 // dependencies but also in all libraries loaded with RTLD_GLOBAL.
756 //
757 // Since RTLD_GLOBAL is always set for the main executable and all dt_needed shared
758 // libraries and they are loaded in breath-first (correct) order we can just execute
759 // dlsym(RTLD_DEFAULT, ...); instead of doing two stage lookup.
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700760 if (si == solist_get_somain()) {
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800761 return dlsym_linear_lookup(&g_default_namespace, name, vi, found, nullptr, RTLD_DEFAULT);
Dmitriy Ivanovf439b5a2015-05-30 13:04:39 -0700762 }
763
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700764 SymbolName symbol_name(name);
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800765 // note that the namespace is not the namespace associated with caller_addr
766 // we use ns associated with root si intentionally here. Using caller_ns
767 // causes problems when user uses dlopen_ext to open a library in the separate
768 // namespace and then calls dlsym() on the handle.
769 return dlsym_handle_lookup(si->get_primary_namespace(), si, nullptr, found, symbol_name, vi);
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700770}
771
Brian Carlstromd4ee82d2013-02-28 15:58:45 -0800772/* This is used by dlsym(3) to performs a global symbol lookup. If the
773 start value is null (for RTLD_DEFAULT), the search starts at the
774 beginning of the global solist. Otherwise the search starts at the
775 specified soinfo (for RTLD_NEXT).
Iliyan Malchev6ed80c82009-09-28 19:38:04 -0700776 */
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800777static const ElfW(Sym)* dlsym_linear_lookup(android_namespace_t* ns,
778 const char* name,
779 const version_info* vi,
780 soinfo** found,
781 soinfo* caller,
782 void* handle) {
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800783 SymbolName symbol_name(name);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800784
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -0700785 auto& soinfo_list = ns->soinfo_list();
786 auto start = soinfo_list.begin();
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -0700787
788 if (handle == RTLD_NEXT) {
Dmitriy Ivanovb96ac412015-05-22 12:34:42 -0700789 if (caller == nullptr) {
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -0700790 return nullptr;
791 } else {
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -0700792 auto it = soinfo_list.find(caller);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700793 CHECK (it != soinfo_list.end());
794 start = ++it;
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -0700795 }
Elliott Hughescade4c32012-12-20 14:42:14 -0800796 }
797
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700798 const ElfW(Sym)* s = nullptr;
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -0700799 for (auto it = start, end = soinfo_list.end(); it != end; ++it) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700800 soinfo* si = *it;
Dmitriy Ivanov19133522015-06-02 17:36:54 -0700801 // Do not skip RTLD_LOCAL libraries in dlsym(RTLD_DEFAULT, ...)
Elliott Hughes5bc78c82016-11-16 11:35:43 -0800802 // if the library is opened by application with target api level < M.
Dmitriy Ivanov19133522015-06-02 17:36:54 -0700803 // See http://b/21565766
Elliott Hughes5bc78c82016-11-16 11:35:43 -0800804 if ((si->get_rtld_flags() & RTLD_GLOBAL) == 0 &&
805 si->get_target_sdk_version() >= __ANDROID_API_M__) {
Dmitriy Ivanove8ba50f2014-09-15 17:00:10 -0700806 continue;
807 }
808
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800809 if (!si->find_symbol_by_name(symbol_name, vi, &s)) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700810 return nullptr;
811 }
812
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700813 if (s != nullptr) {
Elliott Hughescade4c32012-12-20 14:42:14 -0800814 *found = si;
815 break;
Matt Fischer1698d9e2009-12-31 12:17:56 -0600816 }
Elliott Hughescade4c32012-12-20 14:42:14 -0800817 }
Matt Fischer1698d9e2009-12-31 12:17:56 -0600818
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700819 // If not found - use dlsym_handle_lookup for caller's
820 // local_group unless it is part of the global group in which
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -0700821 // case we already did it.
822 if (s == nullptr && caller != nullptr &&
823 (caller->get_rtld_flags() & RTLD_GLOBAL) == 0) {
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800824 soinfo* local_group_root = caller->get_local_group_root();
825
826 return dlsym_handle_lookup(local_group_root->get_primary_namespace(),
827 local_group_root,
828 (handle == RTLD_NEXT) ? caller : nullptr,
829 found,
830 symbol_name,
831 vi);
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -0700832 }
833
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700834 if (s != nullptr) {
Elliott Hughesc00f2cb2013-10-04 17:01:33 -0700835 TRACE_TYPE(LOOKUP, "%s s->st_value = %p, found->base = %p",
836 name, reinterpret_cast<void*>(s->st_value), reinterpret_cast<void*>((*found)->base));
Elliott Hughescade4c32012-12-20 14:42:14 -0800837 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800838
Elliott Hughescade4c32012-12-20 14:42:14 -0800839 return s;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800840}
841
Kito Chengfa8c05d2013-03-12 14:58:06 +0800842soinfo* find_containing_library(const void* p) {
Elliott Hughes0266ae52014-02-10 17:46:57 -0800843 ElfW(Addr) address = reinterpret_cast<ElfW(Addr)>(p);
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700844 for (soinfo* si = solist_get_head(); si != nullptr; si = si->next) {
Kito Chengfa8c05d2013-03-12 14:58:06 +0800845 if (address >= si->base && address - si->base < si->size) {
846 return si;
Matt Fischere2a8b1f2009-12-31 12:17:40 -0600847 }
Kito Chengfa8c05d2013-03-12 14:58:06 +0800848 }
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700849 return nullptr;
Matt Fischere2a8b1f2009-12-31 12:17:40 -0600850}
851
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700852class ZipArchiveCache {
853 public:
854 ZipArchiveCache() {}
855 ~ZipArchiveCache();
856
857 bool get_or_open(const char* zip_path, ZipArchiveHandle* handle);
858 private:
859 DISALLOW_COPY_AND_ASSIGN(ZipArchiveCache);
860
861 std::unordered_map<std::string, ZipArchiveHandle> cache_;
862};
863
864bool ZipArchiveCache::get_or_open(const char* zip_path, ZipArchiveHandle* handle) {
865 std::string key(zip_path);
866
867 auto it = cache_.find(key);
868 if (it != cache_.end()) {
869 *handle = it->second;
870 return true;
871 }
872
873 int fd = TEMP_FAILURE_RETRY(open(zip_path, O_RDONLY | O_CLOEXEC));
874 if (fd == -1) {
875 return false;
876 }
877
878 if (OpenArchiveFd(fd, "", handle) != 0) {
879 // invalid zip-file (?)
Yabin Cui722072d2016-03-21 17:10:12 -0700880 CloseArchive(handle);
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700881 close(fd);
882 return false;
883 }
884
885 cache_[key] = *handle;
886 return true;
887}
888
889ZipArchiveCache::~ZipArchiveCache() {
Dmitriy Ivanov5dce8942015-10-13 12:14:16 -0700890 for (const auto& it : cache_) {
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700891 CloseArchive(it.second);
892 }
893}
894
895static int open_library_in_zipfile(ZipArchiveCache* zip_archive_cache,
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700896 const char* const input_path,
897 off64_t* file_offset, std::string* realpath) {
898 std::string normalized_path;
899 if (!normalize_path(input_path, &normalized_path)) {
900 return -1;
901 }
902
903 const char* const path = normalized_path.c_str();
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700904 TRACE("Trying zip file open from path \"%s\" -> normalized \"%s\"", input_path, path);
Simon Baldwinaef71952015-01-16 13:22:54 +0000905
Dmitriy Ivanov402a7502015-06-09 13:46:51 -0700906 // Treat an '!/' separator inside a path as the separator between the name
Simon Baldwinaef71952015-01-16 13:22:54 +0000907 // of the zip file on disk and the subdirectory to search within it.
Dmitriy Ivanov402a7502015-06-09 13:46:51 -0700908 // For example, if path is "foo.zip!/bar/bas/x.so", then we search for
Simon Baldwinaef71952015-01-16 13:22:54 +0000909 // "bar/bas/x.so" within "foo.zip".
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700910 const char* const separator = strstr(path, kZipFileSeparator);
Simon Baldwinaef71952015-01-16 13:22:54 +0000911 if (separator == nullptr) {
912 return -1;
Elliott Hughes124fae92012-10-31 14:20:03 -0700913 }
Simon Baldwinaef71952015-01-16 13:22:54 +0000914
915 char buf[512];
916 if (strlcpy(buf, path, sizeof(buf)) >= sizeof(buf)) {
917 PRINT("Warning: ignoring very long library path: %s", path);
918 return -1;
919 }
920
921 buf[separator - path] = '\0';
922
923 const char* zip_path = buf;
Dmitriy Ivanov402a7502015-06-09 13:46:51 -0700924 const char* file_path = &buf[separator - path + 2];
Simon Baldwinaef71952015-01-16 13:22:54 +0000925 int fd = TEMP_FAILURE_RETRY(open(zip_path, O_RDONLY | O_CLOEXEC));
926 if (fd == -1) {
927 return -1;
928 }
929
930 ZipArchiveHandle handle;
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700931 if (!zip_archive_cache->get_or_open(zip_path, &handle)) {
Simon Baldwinaef71952015-01-16 13:22:54 +0000932 // invalid zip-file (?)
933 close(fd);
934 return -1;
935 }
936
Simon Baldwinaef71952015-01-16 13:22:54 +0000937 ZipEntry entry;
938
Yusuke Sato56f40fb2015-06-25 14:56:07 -0700939 if (FindEntry(handle, ZipString(file_path), &entry) != 0) {
Simon Baldwinaef71952015-01-16 13:22:54 +0000940 // Entry was not found.
941 close(fd);
942 return -1;
943 }
944
945 // Check if it is properly stored
946 if (entry.method != kCompressStored || (entry.offset % PAGE_SIZE) != 0) {
947 close(fd);
948 return -1;
949 }
950
951 *file_offset = entry.offset;
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700952
953 if (realpath_fd(fd, realpath)) {
954 *realpath += separator;
955 } else {
956 PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.",
957 normalized_path.c_str());
958 *realpath = normalized_path;
959 }
960
Simon Baldwinaef71952015-01-16 13:22:54 +0000961 return fd;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800962}
963
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700964static bool format_path(char* buf, size_t buf_size, const char* path, const char* name) {
965 int n = __libc_format_buffer(buf, buf_size, "%s/%s", path, name);
966 if (n < 0 || n >= static_cast<int>(buf_size)) {
967 PRINT("Warning: ignoring very long library path: %s/%s", path, name);
968 return false;
969 }
Simon Baldwinaef71952015-01-16 13:22:54 +0000970
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700971 return true;
972}
973
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700974static int open_library_on_paths(ZipArchiveCache* zip_archive_cache,
975 const char* name, off64_t* file_offset,
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700976 const std::vector<std::string>& paths,
977 std::string* realpath) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700978 for (const auto& path : paths) {
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700979 char buf[512];
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700980 if (!format_path(buf, sizeof(buf), path.c_str(), name)) {
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700981 continue;
982 }
983
984 int fd = -1;
Dmitriy Ivanov730ed9d2015-07-16 04:52:06 -0700985 if (strstr(buf, kZipFileSeparator) != nullptr) {
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700986 fd = open_library_in_zipfile(zip_archive_cache, buf, file_offset, realpath);
Simon Baldwinaef71952015-01-16 13:22:54 +0000987 }
988
989 if (fd == -1) {
990 fd = TEMP_FAILURE_RETRY(open(buf, O_RDONLY | O_CLOEXEC));
991 if (fd != -1) {
992 *file_offset = 0;
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700993 if (!realpath_fd(fd, realpath)) {
994 PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.", buf);
995 *realpath = buf;
996 }
Simon Baldwinaef71952015-01-16 13:22:54 +0000997 }
998 }
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700999
1000 if (fd != -1) {
1001 return fd;
1002 }
Simon Baldwinaef71952015-01-16 13:22:54 +00001003 }
1004
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07001005 return -1;
Simon Baldwinaef71952015-01-16 13:22:54 +00001006}
1007
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001008static int open_library(android_namespace_t* ns,
1009 ZipArchiveCache* zip_archive_cache,
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001010 const char* name, soinfo *needed_by,
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001011 off64_t* file_offset, std::string* realpath) {
Elliott Hughesca0c11b2013-03-12 10:40:45 -07001012 TRACE("[ opening %s ]", name);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001013
Elliott Hughes124fae92012-10-31 14:20:03 -07001014 // 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 -07001015 if (strchr(name, '/') != nullptr) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001016 int fd = -1;
1017
Dmitriy Ivanov730ed9d2015-07-16 04:52:06 -07001018 if (strstr(name, kZipFileSeparator) != nullptr) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001019 fd = open_library_in_zipfile(zip_archive_cache, name, file_offset, realpath);
1020 }
1021
1022 if (fd == -1) {
1023 fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_CLOEXEC));
Simon Baldwinaef71952015-01-16 13:22:54 +00001024 if (fd != -1) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001025 *file_offset = 0;
1026 if (!realpath_fd(fd, realpath)) {
1027 PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.", name);
1028 *realpath = name;
1029 }
Simon Baldwinaef71952015-01-16 13:22:54 +00001030 }
1031 }
1032
Dmitriy Ivanove44fffd2015-03-17 17:12:18 -07001033 return fd;
Elliott Hughes124fae92012-10-31 14:20:03 -07001034 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001035
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001036 // Otherwise we try LD_LIBRARY_PATH first, and fall back to the default library path
1037 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 -07001038 if (fd == -1 && needed_by != nullptr) {
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001039 fd = open_library_on_paths(zip_archive_cache, name, file_offset, needed_by->get_dt_runpath(), realpath);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001040 // Check if the library is accessible
1041 if (fd != -1 && !ns->is_accessible(*realpath)) {
1042 fd = -1;
1043 }
Evgenii Stepanov68650822015-06-10 13:38:39 -07001044 }
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001045
Elliott Hughes124fae92012-10-31 14:20:03 -07001046 if (fd == -1) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001047 fd = open_library_on_paths(zip_archive_cache, name, file_offset, ns->get_default_library_paths(), realpath);
Elliott Hughes124fae92012-10-31 14:20:03 -07001048 }
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001049
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001050 // TODO(dimitry): workaround for http://b/26394120 (the grey-list)
1051 if (fd == -1 && ns != &g_default_namespace && is_greylisted(name, needed_by)) {
1052 // try searching for it on default_namespace default_library_path
1053 fd = open_library_on_paths(zip_archive_cache, name, file_offset,
1054 g_default_namespace.get_default_library_paths(), realpath);
1055 }
1056 // END OF WORKAROUND
1057
Elliott Hughes124fae92012-10-31 14:20:03 -07001058 return fd;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001059}
1060
Dimitry Ivanov3f660572016-09-09 10:00:39 -07001061const char* fix_dt_needed(const char* dt_needed, const char* sopath __unused) {
Dmitriy Ivanovd974e882015-05-27 18:29:41 -07001062#if !defined(__LP64__)
1063 // Work around incorrect DT_NEEDED entries for old apps: http://b/21364029
Elliott Hughes5bc78c82016-11-16 11:35:43 -08001064 if (get_application_target_sdk_version() < __ANDROID_API_M__) {
Dmitriy Ivanovd974e882015-05-27 18:29:41 -07001065 const char* bname = basename(dt_needed);
1066 if (bname != dt_needed) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001067 DL_WARN("library \"%s\" has invalid DT_NEEDED entry \"%s\"", sopath, dt_needed);
1068 add_dlwarning(sopath, "invalid DT_NEEDED entry", dt_needed);
Dmitriy Ivanovd974e882015-05-27 18:29:41 -07001069 }
1070
1071 return bname;
1072 }
1073#endif
1074 return dt_needed;
1075}
1076
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001077template<typename F>
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001078static void for_each_dt_needed(const ElfReader& elf_reader, F action) {
1079 for (const ElfW(Dyn)* d = elf_reader.dynamic(); d->d_tag != DT_NULL; ++d) {
1080 if (d->d_tag == DT_NEEDED) {
1081 action(fix_dt_needed(elf_reader.get_string(d->d_un.d_val), elf_reader.name()));
1082 }
1083 }
1084}
1085
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001086static bool load_library(android_namespace_t* ns,
1087 LoadTask* task,
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001088 LoadTaskList* load_tasks,
1089 int rtld_flags,
1090 const std::string& realpath) {
1091 off64_t file_offset = task->get_file_offset();
1092 const char* name = task->get_name();
1093 const android_dlextinfo* extinfo = task->get_extinfo();
1094
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001095 if ((file_offset % PAGE_SIZE) != 0) {
Dmitriy Ivanova6c12792014-10-21 12:09:18 -07001096 DL_ERR("file offset for the library \"%s\" is not page-aligned: %" PRId64, name, file_offset);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001097 return false;
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001098 }
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001099 if (file_offset < 0) {
1100 DL_ERR("file offset for the library \"%s\" is negative: %" PRId64, name, file_offset);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001101 return false;
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001102 }
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001103
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001104 struct stat file_stat;
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001105 if (TEMP_FAILURE_RETRY(fstat(task->get_fd(), &file_stat)) != 0) {
Dmitriy Ivanova6c12792014-10-21 12:09:18 -07001106 DL_ERR("unable to stat file for the library \"%s\": %s", name, strerror(errno));
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001107 return false;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001108 }
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001109 if (file_offset >= file_stat.st_size) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07001110 DL_ERR("file offset for the library \"%s\" >= file size: %" PRId64 " >= %" PRId64,
1111 name, file_offset, file_stat.st_size);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001112 return false;
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001113 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001114
1115 // Check for symlink and other situations where
Dmitriy Ivanov9b821362015-04-02 16:03:56 -07001116 // file can have different names, unless ANDROID_DLEXT_FORCE_LOAD is set
1117 if (extinfo == nullptr || (extinfo->flags & ANDROID_DLEXT_FORCE_LOAD) == 0) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001118 auto predicate = [&](soinfo* si) {
1119 return si->get_st_dev() != 0 &&
1120 si->get_st_ino() != 0 &&
1121 si->get_st_dev() == file_stat.st_dev &&
1122 si->get_st_ino() == file_stat.st_ino &&
1123 si->get_file_offset() == file_offset;
1124 };
1125
1126 soinfo* si = ns->soinfo_list().find_if(predicate);
1127
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001128 if (si != nullptr) {
1129 TRACE("library \"%s\" is already loaded under different name/path \"%s\" - "
1130 "will return existing soinfo", name, si->get_realpath());
1131 task->set_soinfo(si);
1132 return true;
1133 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001134 }
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07001135
Dmitriy Ivanove8ba50f2014-09-15 17:00:10 -07001136 if ((rtld_flags & RTLD_NOLOAD) != 0) {
Dmitriy Ivanova6ac54a2014-09-09 10:21:42 -07001137 DL_ERR("library \"%s\" wasn't loaded and RTLD_NOLOAD prevented it", name);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001138 return false;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001139 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001140
Dimitry Ivanov22840aa2015-12-04 18:28:49 -08001141 if (!ns->is_accessible(realpath)) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001142 // TODO(dimitry): workaround for http://b/26394120 - the grey-list
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001143
1144 // TODO(dimitry) before O release: add a namespace attribute to have this enabled
1145 // only for classloader-namespaces
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001146 const soinfo* needed_by = task->is_dt_needed() ? task->get_needed_by() : nullptr;
1147 if (is_greylisted(name, needed_by)) {
1148 // print warning only if needed by non-system library
1149 if (needed_by == nullptr || !is_system_library(needed_by->get_realpath())) {
1150 const soinfo* needed_or_dlopened_by = task->get_needed_by();
1151 const char* sopath = needed_or_dlopened_by == nullptr ? "(unknown)" :
1152 needed_or_dlopened_by->get_realpath();
1153 DL_WARN("library \"%s\" (\"%s\") needed or dlopened by \"%s\" is not accessible for the namespace \"%s\""
1154 " - the access is temporarily granted as a workaround for http://b/26394120, note that the access"
1155 " will be removed in future releases of Android.",
1156 name, realpath.c_str(), sopath, ns->get_name());
1157 add_dlwarning(sopath, "unauthorized access to", name);
1158 }
1159 } else {
1160 // do not load libraries if they are not accessible for the specified namespace.
1161 const char* needed_or_dlopened_by = task->get_needed_by() == nullptr ?
1162 "(unknown)" :
1163 task->get_needed_by()->get_realpath();
Dimitry Ivanovd17a3772016-03-01 13:11:28 -08001164
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001165 DL_ERR("library \"%s\" needed or dlopened by \"%s\" is not accessible for the namespace \"%s\"",
1166 name, needed_or_dlopened_by, ns->get_name());
Dimitry Ivanovd17a3772016-03-01 13:11:28 -08001167
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001168 PRINT("library \"%s\" (\"%s\") needed or dlopened by \"%s\" is not accessible for the"
1169 " namespace: [name=\"%s\", ld_library_paths=\"%s\", default_library_paths=\"%s\","
1170 " permitted_paths=\"%s\"]",
1171 name, realpath.c_str(),
1172 needed_or_dlopened_by,
1173 ns->get_name(),
1174 android::base::Join(ns->get_ld_library_paths(), ':').c_str(),
1175 android::base::Join(ns->get_default_library_paths(), ':').c_str(),
1176 android::base::Join(ns->get_permitted_paths(), ':').c_str());
1177 return false;
1178 }
Dimitry Ivanov22840aa2015-12-04 18:28:49 -08001179 }
1180
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001181 soinfo* si = soinfo_alloc(ns, realpath.c_str(), &file_stat, file_offset, rtld_flags);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001182 if (si == nullptr) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001183 return false;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001184 }
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07001185
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001186 task->set_soinfo(si);
1187
1188 // Read the ELF header and some of the segments.
1189 if (!task->read(realpath.c_str(), file_stat.st_size)) {
Dmitriy Ivanovfd7a91e2015-11-06 10:44:37 -08001190 soinfo_free(si);
1191 task->set_soinfo(nullptr);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001192 return false;
1193 }
1194
1195 // find and set DT_RUNPATH and dt_soname
1196 // Note that these field values are temporary and are
1197 // going to be overwritten on soinfo::prelink_image
1198 // with values from PT_LOAD segments.
1199 const ElfReader& elf_reader = task->get_elf_reader();
1200 for (const ElfW(Dyn)* d = elf_reader.dynamic(); d->d_tag != DT_NULL; ++d) {
1201 if (d->d_tag == DT_RUNPATH) {
1202 si->set_dt_runpath(elf_reader.get_string(d->d_un.d_val));
1203 }
1204 if (d->d_tag == DT_SONAME) {
1205 si->set_soname(elf_reader.get_string(d->d_un.d_val));
1206 }
1207 }
1208
1209 for_each_dt_needed(task->get_elf_reader(), [&](const char* name) {
1210 load_tasks->push_back(LoadTask::create(name, si, task->get_readers_map()));
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001211 });
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07001212
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001213 return true;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001214}
1215
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001216static bool load_library(android_namespace_t* ns,
1217 LoadTask* task,
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001218 ZipArchiveCache* zip_archive_cache,
1219 LoadTaskList* load_tasks,
1220 int rtld_flags) {
1221 const char* name = task->get_name();
1222 soinfo* needed_by = task->get_needed_by();
1223 const android_dlextinfo* extinfo = task->get_extinfo();
1224
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001225 off64_t file_offset;
1226 std::string realpath;
Spencer Low0346ad72015-04-22 18:06:51 -07001227 if (extinfo != nullptr && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) {
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001228 file_offset = 0;
Spencer Low0346ad72015-04-22 18:06:51 -07001229 if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
1230 file_offset = extinfo->library_fd_offset;
1231 }
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001232
1233 if (!realpath_fd(extinfo->library_fd, &realpath)) {
1234 PRINT("warning: unable to get realpath for the library \"%s\" by extinfo->library_fd. "
1235 "Will use given name.", name);
1236 realpath = name;
1237 }
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001238
1239 task->set_fd(extinfo->library_fd, false);
1240 task->set_file_offset(file_offset);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001241 return load_library(ns, task, load_tasks, rtld_flags, realpath);
Spencer Low0346ad72015-04-22 18:06:51 -07001242 }
1243
1244 // Open the file.
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001245 int fd = open_library(ns, zip_archive_cache, name, needed_by, &file_offset, &realpath);
Spencer Low0346ad72015-04-22 18:06:51 -07001246 if (fd == -1) {
1247 DL_ERR("library \"%s\" not found", name);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001248 return false;
Spencer Low0346ad72015-04-22 18:06:51 -07001249 }
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001250
1251 task->set_fd(fd, true);
1252 task->set_file_offset(file_offset);
1253
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001254 return load_library(ns, task, load_tasks, rtld_flags, realpath);
Spencer Low0346ad72015-04-22 18:06:51 -07001255}
1256
Dimitry Ivanov3bd90612017-02-01 08:54:43 -08001257// Returns true if library was found and false otherwise
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001258static bool find_loaded_library_by_soname(android_namespace_t* ns,
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -07001259 const char* name, soinfo** candidate) {
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001260 *candidate = nullptr;
1261
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07001262 // Ignore filename with path.
1263 if (strchr(name, '/') != nullptr) {
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001264 return false;
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07001265 }
1266
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001267 return !ns->soinfo_list().visit([&](soinfo* si) {
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07001268 const char* soname = si->get_soname();
1269 if (soname != nullptr && (strcmp(name, soname) == 0)) {
Dimitry Ivanov3bd90612017-02-01 08:54:43 -08001270 *candidate = si;
1271 return false;
Ard Biesheuvel12c78bb2012-08-14 12:30:09 +02001272 }
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001273
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001274 return true;
1275 });
Ard Biesheuvel12c78bb2012-08-14 12:30:09 +02001276}
1277
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001278static std::string resolve_soname(const std::string& name) {
1279 // We assume that soname equals to basename here
1280
1281 // TODO(dimitry): consider having honest absolute-path -> soname resolution
1282 // note that since we might end up refusing to load this library because
1283 // it is not in shared libs list we need to get the soname without actually loading
1284 // the library.
1285 //
1286 // On the other hand there are several places where we already assume that
1287 // soname == basename in particular for any not-loaded library mentioned
1288 // in DT_NEEDED list.
1289 return basename(name.c_str());
1290}
1291
1292
1293static bool find_library_in_linked_namespace(const android_namespace_link_t& namespace_link,
1294 LoadTask* task,
1295 int rtld_flags) {
1296 android_namespace_t* ns = namespace_link.linked_namespace();
1297
1298 soinfo* candidate;
1299 bool loaded = false;
1300
1301 std::string soname;
1302 if (find_loaded_library_by_soname(ns, task->get_name(), &candidate)) {
1303 loaded = true;
1304 soname = candidate->get_soname();
1305 } else {
1306 soname = resolve_soname(task->get_name());
1307 }
1308
1309 if (!namespace_link.is_accessible(soname.c_str())) {
1310 // the library is not accessible via namespace_link
1311 return false;
1312 }
1313
1314 // if library is already loaded - return it
1315 if (loaded) {
1316 task->set_soinfo(candidate);
1317 return true;
1318 }
1319
1320 // try to load the library - once namespace boundary is crossed
1321 // we need to load a library within separate load_group
1322 // to avoid using symbols from foreign namespace while.
1323 //
1324 // All symbols during relocation should be resolved within a
1325 // namespace to preserve library locality to a namespace.
1326 const char* name = task->get_name();
1327 if (find_libraries(ns,
1328 task->get_needed_by(),
1329 &name,
1330 1,
1331 &candidate,
1332 nullptr /* ld_preloads */,
1333 0 /* ld_preload_count*/,
1334 rtld_flags,
1335 nullptr /* extinfo*/,
1336 false /* add_as_children */,
1337 false /* search_linked_namespaces */)) {
1338 task->set_soinfo(candidate);
1339 return true;
1340 }
1341
1342 return false;
1343}
1344
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001345static bool find_library_internal(android_namespace_t* ns,
1346 LoadTask* task,
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001347 ZipArchiveCache* zip_archive_cache,
1348 LoadTaskList* load_tasks,
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001349 int rtld_flags,
1350 bool search_linked_namespaces) {
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001351 soinfo* candidate;
1352
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001353 if (find_loaded_library_by_soname(ns, task->get_name(), &candidate)) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001354 task->set_soinfo(candidate);
1355 return true;
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001356 }
Dmitriy Ivanovb648a8a2014-05-19 15:06:58 -07001357
1358 // Library might still be loaded, the accurate detection
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001359 // of this fact is done by load_library.
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001360 TRACE("[ \"%s\" find_loaded_library_by_soname failed (*candidate=%s@%p). Trying harder...]",
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001361 task->get_name(), candidate == nullptr ? "n/a" : candidate->get_realpath(), candidate);
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001362
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001363 if (load_library(ns, task, zip_archive_cache, load_tasks, rtld_flags)) {
1364 return true;
1365 }
1366
1367 if (search_linked_namespaces) {
1368 // if a library was not found - look into linked namespaces
1369 for (auto& linked_namespace : ns->linked_namespaces()) {
1370 if (find_library_in_linked_namespace(linked_namespace,
1371 task,
1372 rtld_flags)) {
1373 return true;
1374 }
1375 }
1376 }
1377
1378 return false;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001379}
1380
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001381static void soinfo_unload(soinfo* si);
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001382static void soinfo_unload(soinfo* soinfos[], size_t count);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001383
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001384// TODO: this is slightly unusual way to construct
1385// the global group for relocation. Not every RTLD_GLOBAL
1386// library is included in this group for backwards-compatibility
1387// reasons.
1388//
1389// This group consists of the main executable, LD_PRELOADs
1390// and libraries with the DF_1_GLOBAL flag set.
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001391static soinfo_list_t make_global_group(android_namespace_t* ns) {
1392 soinfo_list_t global_group;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001393 ns->soinfo_list().for_each([&](soinfo* si) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001394 if ((si->get_dt_flags_1() & DF_1_GLOBAL) != 0) {
1395 global_group.push_back(si);
1396 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001397 });
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001398
1399 return global_group;
1400}
1401
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07001402// This function provides a list of libraries to be shared
1403// by the namespace. For the default namespace this is the global
1404// group (see make_global_group). For all others this is a group
1405// of RTLD_GLOBAL libraries (which includes the global group from
1406// the default namespace).
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001407static soinfo_list_t get_shared_group(android_namespace_t* ns) {
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07001408 if (ns == &g_default_namespace) {
1409 return make_global_group(ns);
1410 }
1411
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001412 soinfo_list_t shared_group;
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07001413 ns->soinfo_list().for_each([&](soinfo* si) {
1414 if ((si->get_rtld_flags() & RTLD_GLOBAL) != 0) {
1415 shared_group.push_back(si);
1416 }
1417 });
1418
1419 return shared_group;
1420}
1421
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001422static void shuffle(std::vector<LoadTask*>* v) {
1423 for (size_t i = 0, size = v->size(); i < size; ++i) {
1424 size_t n = size - i;
1425 size_t r = arc4random_uniform(n);
1426 std::swap((*v)[n-1], (*v)[r]);
1427 }
1428}
1429
Evgenii Stepanov0cdef7e2015-07-06 17:56:31 -07001430// add_as_children - add first-level loaded libraries (i.e. library_names[], but
1431// not their transitive dependencies) as children of the start_with library.
1432// This is false when find_libraries is called for dlopen(), when newly loaded
1433// libraries must form a disjoint tree.
Dimitry Ivanov3f660572016-09-09 10:00:39 -07001434bool find_libraries(android_namespace_t* ns,
1435 soinfo* start_with,
1436 const char* const library_names[],
1437 size_t library_names_count,
1438 soinfo* soinfos[],
1439 std::vector<soinfo*>* ld_preloads,
1440 size_t ld_preloads_count,
1441 int rtld_flags,
1442 const android_dlextinfo* extinfo,
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001443 bool add_as_children,
1444 bool search_linked_namespaces) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001445 // Step 0: prepare.
1446 LoadTaskList load_tasks;
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001447 std::unordered_map<const soinfo*, ElfReader> readers_map;
1448
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001449 for (size_t i = 0; i < library_names_count; ++i) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001450 const char* name = library_names[i];
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001451 load_tasks.push_back(LoadTask::create(name, start_with, &readers_map));
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001452 }
1453
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001454 // Construct global_group.
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001455 soinfo_list_t global_group = make_global_group(ns);
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001456
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001457 // If soinfos array is null allocate one on stack.
1458 // The array is needed in case of failure; for example
1459 // when library_names[] = {libone.so, libtwo.so} and libone.so
1460 // is loaded correctly but libtwo.so failed for some reason.
1461 // In this case libone.so should be unloaded on return.
1462 // See also implementation of failure_guard below.
1463
1464 if (soinfos == nullptr) {
1465 size_t soinfos_size = sizeof(soinfo*)*library_names_count;
1466 soinfos = reinterpret_cast<soinfo**>(alloca(soinfos_size));
1467 memset(soinfos, 0, soinfos_size);
1468 }
1469
1470 // list of libraries to link - see step 2.
1471 size_t soinfos_count = 0;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001472
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001473 auto scope_guard = make_scope_guard([&]() {
1474 for (LoadTask* t : load_tasks) {
1475 LoadTask::deleter(t);
1476 }
1477 });
1478
Dmitriy Ivanovd9ff7222014-09-08 16:22:22 -07001479 auto failure_guard = make_scope_guard([&]() {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001480 // Housekeeping
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001481 soinfo_unload(soinfos, soinfos_count);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001482 });
1483
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001484 ZipArchiveCache zip_archive_cache;
1485
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001486 // Step 1: expand the list of load_tasks to include
1487 // all DT_NEEDED libraries (do not load them just yet)
1488 for (size_t i = 0; i<load_tasks.size(); ++i) {
1489 LoadTask* task = load_tasks[i];
Evgenii Stepanov68650822015-06-10 13:38:39 -07001490 soinfo* needed_by = task->get_needed_by();
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001491
Dmitriy Ivanovedfc9f62015-09-02 16:32:02 -07001492 bool is_dt_needed = needed_by != nullptr && (needed_by != start_with || add_as_children);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001493 task->set_extinfo(is_dt_needed ? nullptr : extinfo);
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001494 task->set_dt_needed(is_dt_needed);
Dmitriy Ivanovedfc9f62015-09-02 16:32:02 -07001495
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001496 if (!find_library_internal(ns,
1497 task,
1498 &zip_archive_cache,
1499 &load_tasks,
1500 rtld_flags,
1501 search_linked_namespaces || is_dt_needed)) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001502 return false;
1503 }
1504
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001505 soinfo* si = task->get_soinfo();
1506
Dmitriy Ivanovedfc9f62015-09-02 16:32:02 -07001507 if (is_dt_needed) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001508 needed_by->add_child(si);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001509
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001510 if (si->is_linked()) {
1511 si->increment_ref_count();
1512 }
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001513 }
1514
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001515 // When ld_preloads is not null, the first
1516 // ld_preloads_count libs are in fact ld_preloads.
1517 if (ld_preloads != nullptr && soinfos_count < ld_preloads_count) {
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07001518 ld_preloads->push_back(si);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001519 }
1520
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001521 if (soinfos_count < library_names_count) {
1522 soinfos[soinfos_count++] = si;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001523 }
1524 }
1525
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001526 // Step 2: Load libraries in random order (see b/24047022)
1527 LoadTaskList load_list;
1528 for (auto&& task : load_tasks) {
1529 soinfo* si = task->get_soinfo();
1530 auto pred = [&](const LoadTask* t) {
1531 return t->get_soinfo() == si;
1532 };
1533
1534 if (!si->is_linked() &&
1535 std::find_if(load_list.begin(), load_list.end(), pred) == load_list.end() ) {
1536 load_list.push_back(task);
1537 }
1538 }
1539 shuffle(&load_list);
1540
1541 for (auto&& task : load_list) {
1542 if (!task->load()) {
1543 return false;
1544 }
1545 }
1546
1547 // Step 3: pre-link all DT_NEEDED libraries in breadth first order.
1548 for (auto&& task : load_tasks) {
1549 soinfo* si = task->get_soinfo();
1550 if (!si->is_linked() && !si->prelink_image()) {
1551 return false;
1552 }
1553 }
1554
1555 // Step 4: Add LD_PRELOADed libraries to the global group for
1556 // future runs. There is no need to explicitly add them to
1557 // the global group for this run because they are going to
1558 // appear in the local group in the correct order.
1559 if (ld_preloads != nullptr) {
1560 for (auto&& si : *ld_preloads) {
1561 si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL);
1562 }
1563 }
1564
1565
1566 // Step 5: link libraries.
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001567 soinfo_list_t local_group;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001568 walk_dependencies_tree(
Evgenii Stepanov0cdef7e2015-07-06 17:56:31 -07001569 (start_with != nullptr && add_as_children) ? &start_with : soinfos,
1570 (start_with != nullptr && add_as_children) ? 1 : soinfos_count,
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001571 [&] (soinfo* si) {
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -08001572 if (ns->is_accessible(si)) {
1573 local_group.push_back(si);
1574 return kWalkContinue;
1575 } else {
1576 return kWalkSkip;
1577 }
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001578 });
1579
1580 bool linked = local_group.visit([&](soinfo* si) {
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001581 if (!si->is_linked()) {
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -07001582 if (!si->link_image(global_group, local_group, extinfo) ||
1583 !get_cfi_shadow()->AfterLoad(si, solist_get_head())) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001584 return false;
1585 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001586 }
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001587
1588 return true;
1589 });
1590
1591 if (linked) {
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001592 local_group.for_each([](soinfo* si) {
1593 if (!si->is_linked()) {
1594 si->set_linked();
1595 }
1596 });
1597
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001598 failure_guard.disable();
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001599 }
1600
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001601 return linked;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001602}
1603
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001604static soinfo* find_library(android_namespace_t* ns,
1605 const char* name, int rtld_flags,
Evgenii Stepanov0cdef7e2015-07-06 17:56:31 -07001606 const android_dlextinfo* extinfo,
1607 soinfo* needed_by) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001608 soinfo* si;
1609
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001610 if (name == nullptr) {
Dimitry Ivanov3f660572016-09-09 10:00:39 -07001611 si = solist_get_somain();
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001612 } else if (!find_libraries(ns,
1613 needed_by,
1614 &name,
1615 1,
1616 &si,
1617 nullptr,
1618 0,
1619 rtld_flags,
1620 extinfo,
1621 false /* add_as_children */,
1622 true /* search_linked_namespaces */)) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001623 return nullptr;
1624 }
1625
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001626 si->increment_ref_count();
1627
Elliott Hughesd23736e2012-11-01 15:16:56 -07001628 return si;
1629}
Elliott Hughesbedfe382012-08-14 14:07:59 -07001630
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001631static void soinfo_unload(soinfo* root) {
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001632 if (root->is_linked()) {
1633 root = root->get_local_group_root();
1634 }
1635
1636 if (!root->can_unload()) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001637 TRACE("not unloading \"%s\" - the binary is flagged with NODELETE", root->get_realpath());
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -07001638 return;
1639 }
1640
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001641 soinfo_unload(&root, 1);
1642}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001643
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001644static void soinfo_unload(soinfo* soinfos[], size_t count) {
1645 // Note that the library can be loaded but not linked;
1646 // in which case there is no root but we still need
1647 // to walk the tree and unload soinfos involved.
1648 //
1649 // This happens on unsuccessful dlopen, when one of
1650 // the DT_NEEDED libraries could not be linked/found.
1651 if (count == 0) {
1652 return;
1653 }
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001654
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001655 soinfo_list_t unload_list;
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001656 for (size_t i = 0; i < count; ++i) {
1657 soinfo* si = soinfos[i];
Dmitriy Ivanov5ae82cb2014-12-02 17:08:42 -08001658
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001659 if (si->can_unload()) {
1660 size_t ref_count = si->is_linked() ? si->decrement_ref_count() : 0;
1661 if (ref_count == 0) {
1662 unload_list.push_back(si);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001663 } else {
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001664 TRACE("not unloading '%s' group, decrementing ref_count to %zd",
1665 si->get_realpath(), ref_count);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001666 }
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001667 } else {
1668 TRACE("not unloading '%s' - the binary is flagged with NODELETE", si->get_realpath());
1669 return;
1670 }
1671 }
1672
1673 // This is used to identify soinfos outside of the load-group
1674 // note that we cannot have > 1 in the array and have any of them
1675 // linked. This is why we can safely use the first one.
1676 soinfo* root = soinfos[0];
1677
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001678 soinfo_list_t local_unload_list;
1679 soinfo_list_t external_unload_list;
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001680 soinfo* si = nullptr;
1681
1682 while ((si = unload_list.pop_front()) != nullptr) {
1683 if (local_unload_list.contains(si)) {
1684 continue;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001685 }
Elliott Hughesd23736e2012-11-01 15:16:56 -07001686
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001687 local_unload_list.push_back(si);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001688
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001689 if (si->has_min_version(0)) {
1690 soinfo* child = nullptr;
1691 while ((child = si->get_children().pop_front()) != nullptr) {
1692 TRACE("%s@%p needs to unload %s@%p", si->get_realpath(), si,
1693 child->get_realpath(), child);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001694
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001695 if (local_unload_list.contains(child)) {
1696 continue;
1697 } else if (child->is_linked() && child->get_local_group_root() != root) {
1698 external_unload_list.push_back(child);
1699 } else {
1700 unload_list.push_front(child);
1701 }
1702 }
1703 } else {
1704#if !defined(__work_around_b_24465209__)
1705 __libc_fatal("soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
1706#else
1707 PRINT("warning: soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
1708 for_each_dt_needed(si, [&] (const char* library_name) {
1709 TRACE("deprecated (old format of soinfo): %s needs to unload %s",
1710 si->get_realpath(), library_name);
1711
1712 soinfo* needed = find_library(si->get_primary_namespace(),
1713 library_name, RTLD_NOLOAD, nullptr, nullptr);
1714
1715 if (needed != nullptr) {
1716 // Not found: for example if symlink was deleted between dlopen and dlclose
1717 // Since we cannot really handle errors at this point - print and continue.
1718 PRINT("warning: couldn't find %s needed by %s on unload.",
1719 library_name, si->get_realpath());
1720 return;
1721 } else if (local_unload_list.contains(needed)) {
1722 // already visited
1723 return;
1724 } else if (needed->is_linked() && needed->get_local_group_root() != root) {
1725 // external group
1726 external_unload_list.push_back(needed);
1727 } else {
1728 // local group
1729 unload_list.push_front(needed);
1730 }
1731 });
1732#endif
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001733 }
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001734 }
1735
1736 local_unload_list.for_each([](soinfo* si) {
1737 si->call_destructors();
1738 });
1739
1740 while ((si = local_unload_list.pop_front()) != nullptr) {
1741 notify_gdb_of_unload(si);
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -07001742 get_cfi_shadow()->BeforeUnload(si);
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001743 soinfo_free(si);
1744 }
1745
1746 while ((si = external_unload_list.pop_front()) != nullptr) {
1747 soinfo_unload(si);
Dmitriy Ivanova2547052014-11-18 12:03:09 -08001748 }
1749}
1750
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001751static std::string symbol_display_name(const char* sym_name, const char* sym_ver) {
1752 if (sym_ver == nullptr) {
1753 return sym_name;
1754 }
1755
Dimitry Ivanov9cf99cb2015-12-11 14:22:24 -08001756 return std::string(sym_name) + ", version " + sym_ver;
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001757}
1758
Dimitry Ivanovaca299a2016-04-11 12:42:58 -07001759static android_namespace_t* get_caller_namespace(soinfo* caller) {
1760 return caller != nullptr ? caller->get_primary_namespace() : g_anonymous_namespace;
1761}
1762
Elliott Hughesa4aafd12014-01-13 16:37:47 -08001763void do_android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size) {
Christopher Ferris052fa3a2014-08-26 20:48:11 -07001764 // Use basic string manipulation calls to avoid snprintf.
1765 // snprintf indirectly calls pthread_getspecific to get the size of a buffer.
1766 // When debug malloc is enabled, this call returns 0. This in turn causes
1767 // snprintf to do nothing, which causes libraries to fail to load.
1768 // See b/17302493 for further details.
1769 // Once the above bug is fixed, this code can be modified to use
1770 // snprintf again.
Evgenii Stepanovd640b222015-07-10 17:54:01 -07001771 size_t required_len = 0;
1772 for (size_t i = 0; g_default_ld_paths[i] != nullptr; ++i) {
1773 required_len += strlen(g_default_ld_paths[i]) + 1;
1774 }
Christopher Ferris052fa3a2014-08-26 20:48:11 -07001775 if (buffer_size < required_len) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07001776 __libc_fatal("android_get_LD_LIBRARY_PATH failed, buffer too small: "
1777 "buffer len %zu, required len %zu", buffer_size, required_len);
Christopher Ferris052fa3a2014-08-26 20:48:11 -07001778 }
Evgenii Stepanovd640b222015-07-10 17:54:01 -07001779 char* end = buffer;
1780 for (size_t i = 0; g_default_ld_paths[i] != nullptr; ++i) {
1781 if (i > 0) *end++ = ':';
1782 end = stpcpy(end, g_default_ld_paths[i]);
1783 }
Elliott Hughesa4aafd12014-01-13 16:37:47 -08001784}
1785
Elliott Hughescade4c32012-12-20 14:42:14 -08001786void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path) {
Nick Kralevich6bb01b62015-03-07 13:37:05 -08001787 parse_LD_LIBRARY_PATH(ld_library_path);
Elliott Hughescade4c32012-12-20 14:42:14 -08001788}
1789
Dimitry Ivanovb996d602016-07-11 18:11:39 -07001790static std::string android_dlextinfo_to_string(const android_dlextinfo* info) {
1791 if (info == nullptr) {
1792 return "(null)";
1793 }
1794
1795 return android::base::StringPrintf("[flags=0x%" PRIx64 ","
1796 " reserved_addr=%p,"
1797 " reserved_size=0x%zx,"
1798 " relro_fd=%d,"
1799 " library_fd=%d,"
1800 " library_fd_offset=0x%" PRIx64 ","
1801 " library_namespace=%s@%p]",
1802 info->flags,
1803 info->reserved_addr,
1804 info->reserved_size,
1805 info->relro_fd,
1806 info->library_fd,
1807 info->library_fd_offset,
1808 (info->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0 ?
1809 (info->library_namespace != nullptr ?
1810 info->library_namespace->get_name() : "(null)") : "(n/a)",
1811 (info->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0 ?
1812 info->library_namespace : nullptr);
1813}
1814
Dimitry Ivanovd9e427c2016-11-22 16:55:25 -08001815void* do_dlopen(const char* name, int flags,
1816 const android_dlextinfo* extinfo,
1817 const void* caller_addr) {
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001818 soinfo* const caller = find_containing_library(caller_addr);
Dimitry Ivanovb996d602016-07-11 18:11:39 -07001819 android_namespace_t* ns = get_caller_namespace(caller);
1820
1821 LD_LOG(kLogDlopen,
1822 "dlopen(name=\"%s\", flags=0x%x, extinfo=%s, caller=\"%s\", caller_ns=%s@%p) ...",
1823 name,
1824 flags,
1825 android_dlextinfo_to_string(extinfo).c_str(),
1826 caller == nullptr ? "(null)" : caller->get_realpath(),
1827 ns == nullptr ? "(null)" : ns->get_name(),
1828 ns);
1829
1830 auto failure_guard = make_scope_guard([&]() {
1831 LD_LOG(kLogDlopen, "... dlopen failed: %s", linker_get_error_buffer());
1832 });
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001833
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -07001834 if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL|RTLD_NODELETE|RTLD_NOLOAD)) != 0) {
Elliott Hughese66190d2012-12-18 15:57:55 -08001835 DL_ERR("invalid flags to dlopen: %x", flags);
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07001836 return nullptr;
Elliott Hughese66190d2012-12-18 15:57:55 -08001837 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001838
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001839 if (extinfo != nullptr) {
1840 if ((extinfo->flags & ~(ANDROID_DLEXT_VALID_FLAG_BITS)) != 0) {
1841 DL_ERR("invalid extended flags to android_dlopen_ext: 0x%" PRIx64, extinfo->flags);
1842 return nullptr;
1843 }
Dmitriy Ivanov126af752015-10-07 16:34:20 -07001844
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001845 if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) == 0 &&
Dmitriy Ivanova6c12792014-10-21 12:09:18 -07001846 (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07001847 DL_ERR("invalid extended flag combination (ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET without "
1848 "ANDROID_DLEXT_USE_LIBRARY_FD): 0x%" PRIx64, extinfo->flags);
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001849 return nullptr;
1850 }
Dmitriy Ivanov126af752015-10-07 16:34:20 -07001851
1852 if ((extinfo->flags & ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS) != 0 &&
1853 (extinfo->flags & (ANDROID_DLEXT_RESERVED_ADDRESS | ANDROID_DLEXT_RESERVED_ADDRESS_HINT)) != 0) {
1854 DL_ERR("invalid extended flag combination: ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS is not "
1855 "compatible with ANDROID_DLEXT_RESERVED_ADDRESS/ANDROID_DLEXT_RESERVED_ADDRESS_HINT");
1856 return nullptr;
1857 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001858
1859 if ((extinfo->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0) {
1860 if (extinfo->library_namespace == nullptr) {
1861 DL_ERR("ANDROID_DLEXT_USE_NAMESPACE is set but extinfo->library_namespace is null");
1862 return nullptr;
1863 }
1864 ns = extinfo->library_namespace;
1865 }
Torne (Richard Coles)012cb452014-02-06 14:34:21 +00001866 }
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -08001867
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -07001868 std::string asan_name_holder;
1869
1870 const char* translated_name = name;
Dimitry Ivanov6c14f862016-12-05 13:35:47 -08001871 if (g_is_asan && translated_name != nullptr && translated_name[0] == '/') {
1872 char translated_path[PATH_MAX];
1873 if (realpath(translated_name, translated_path) != nullptr) {
1874 if (file_is_in_dir(translated_path, kSystemLibDir)) {
1875 asan_name_holder = std::string(kAsanSystemLibDir) + "/" + basename(translated_path);
1876 if (file_exists(asan_name_holder.c_str())) {
1877 translated_name = asan_name_holder.c_str();
1878 PRINT("linker_asan dlopen translating \"%s\" -> \"%s\"", name, translated_name);
1879 }
1880 } else if (file_is_in_dir(translated_path, kVendorLibDir)) {
1881 asan_name_holder = std::string(kAsanVendorLibDir) + "/" + basename(translated_path);
1882 if (file_exists(asan_name_holder.c_str())) {
1883 translated_name = asan_name_holder.c_str();
1884 PRINT("linker_asan dlopen translating \"%s\" -> \"%s\"", name, translated_name);
1885 }
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -07001886 }
1887 }
1888 }
1889
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -08001890 ProtectedDataGuard guard;
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -07001891 soinfo* si = find_library(ns, translated_name, flags, extinfo, caller);
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07001892 if (si != nullptr) {
Dimitry Ivanovb996d602016-07-11 18:11:39 -07001893 void* handle = si->to_handle();
1894 LD_LOG(kLogDlopen,
Dimitry Ivanovae4a0c12016-11-21 10:44:35 -08001895 "... dlopen calling constructors: realpath=\"%s\", soname=\"%s\", handle=%p",
1896 si->get_realpath(), si->get_soname(), handle);
1897 si->call_constructors();
1898 failure_guard.disable();
1899 LD_LOG(kLogDlopen,
Dimitry Ivanovb996d602016-07-11 18:11:39 -07001900 "... dlopen successful: realpath=\"%s\", soname=\"%s\", handle=%p",
1901 si->get_realpath(), si->get_soname(), handle);
1902 return handle;
Elliott Hughesd23736e2012-11-01 15:16:56 -07001903 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001904
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001905 return nullptr;
Elliott Hughesd23736e2012-11-01 15:16:56 -07001906}
1907
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001908int do_dladdr(const void* addr, Dl_info* info) {
1909 // Determine if this address can be found in any library currently mapped.
1910 soinfo* si = find_containing_library(addr);
1911 if (si == nullptr) {
1912 return 0;
1913 }
1914
1915 memset(info, 0, sizeof(Dl_info));
1916
1917 info->dli_fname = si->get_realpath();
1918 // Address at which the shared object is loaded.
1919 info->dli_fbase = reinterpret_cast<void*>(si->base);
1920
1921 // Determine if any symbol in the library contains the specified address.
1922 ElfW(Sym)* sym = si->find_symbol_by_address(addr);
1923 if (sym != nullptr) {
1924 info->dli_sname = si->get_string(sym->st_name);
1925 info->dli_saddr = reinterpret_cast<void*>(si->resolve_symbol_address(sym));
1926 }
1927
1928 return 1;
1929}
1930
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001931static soinfo* soinfo_from_handle(void* handle) {
1932 if ((reinterpret_cast<uintptr_t>(handle) & 1) != 0) {
1933 auto it = g_soinfo_handles_map.find(reinterpret_cast<uintptr_t>(handle));
1934 if (it == g_soinfo_handles_map.end()) {
1935 return nullptr;
1936 } else {
1937 return it->second;
1938 }
1939 }
1940
1941 return static_cast<soinfo*>(handle);
1942}
1943
Dimitry Ivanovd9e427c2016-11-22 16:55:25 -08001944bool do_dlsym(void* handle,
1945 const char* sym_name,
1946 const char* sym_ver,
1947 const void* caller_addr,
1948 void** symbol) {
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001949#if !defined(__LP64__)
1950 if (handle == nullptr) {
1951 DL_ERR("dlsym failed: library handle is null");
1952 return false;
1953 }
1954#endif
1955
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001956 soinfo* found = nullptr;
1957 const ElfW(Sym)* sym = nullptr;
1958 soinfo* caller = find_containing_library(caller_addr);
Dimitry Ivanovaca299a2016-04-11 12:42:58 -07001959 android_namespace_t* ns = get_caller_namespace(caller);
Dimitry Ivanov4742abd2016-12-12 16:30:15 -08001960 soinfo* si = nullptr;
1961 if (handle != RTLD_DEFAULT && handle != RTLD_NEXT) {
1962 si = soinfo_from_handle(handle);
1963 }
1964
1965 LD_LOG(kLogDlsym,
1966 "dlsym(handle=%p(\"%s\"), sym_name=\"%s\", sym_ver=\"%s\", caller=\"%s\", caller_ns=%s@%p) ...",
1967 handle,
1968 si != nullptr ? si->get_realpath() : "n/a",
1969 sym_name,
1970 sym_ver,
1971 caller == nullptr ? "(null)" : caller->get_realpath(),
1972 ns == nullptr ? "(null)" : ns->get_name(),
1973 ns);
1974
1975 auto failure_guard = make_scope_guard([&]() {
1976 LD_LOG(kLogDlsym, "... dlsym failed: %s", linker_get_error_buffer());
1977 });
1978
1979 if (sym_name == nullptr) {
1980 DL_ERR("dlsym failed: symbol name is null");
1981 return false;
1982 }
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001983
1984 version_info vi_instance;
1985 version_info* vi = nullptr;
1986
1987 if (sym_ver != nullptr) {
Dimitry Ivanov9cf99cb2015-12-11 14:22:24 -08001988 vi_instance.name = sym_ver;
1989 vi_instance.elf_hash = calculate_elf_hash(sym_ver);
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001990 vi = &vi_instance;
1991 }
1992
1993 if (handle == RTLD_DEFAULT || handle == RTLD_NEXT) {
1994 sym = dlsym_linear_lookup(ns, sym_name, vi, &found, caller, handle);
1995 } else {
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001996 if (si == nullptr) {
1997 DL_ERR("dlsym failed: invalid handle: %p", handle);
1998 return false;
1999 }
2000 sym = dlsym_handle_lookup(si, &found, sym_name, vi);
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08002001 }
2002
2003 if (sym != nullptr) {
2004 uint32_t bind = ELF_ST_BIND(sym->st_info);
2005
2006 if ((bind == STB_GLOBAL || bind == STB_WEAK) && sym->st_shndx != 0) {
2007 *symbol = reinterpret_cast<void*>(found->resolve_symbol_address(sym));
Dimitry Ivanov4742abd2016-12-12 16:30:15 -08002008 failure_guard.disable();
2009 LD_LOG(kLogDlsym,
2010 "... dlsym successful: sym_name=\"%s\", sym_ver=\"%s\", found in=\"%s\", address=%p",
2011 sym_name, sym_ver, found->get_soname(), *symbol);
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08002012 return true;
2013 }
2014
2015 DL_ERR("symbol \"%s\" found but not global", symbol_display_name(sym_name, sym_ver).c_str());
2016 return false;
2017 }
2018
2019 DL_ERR("undefined symbol: %s", symbol_display_name(sym_name, sym_ver).c_str());
2020 return false;
2021}
2022
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07002023int do_dlclose(void* handle) {
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -08002024 ProtectedDataGuard guard;
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07002025 soinfo* si = soinfo_from_handle(handle);
2026 if (si == nullptr) {
2027 DL_ERR("invalid handle: %p", handle);
2028 return -1;
2029 }
2030
Dmitriy Ivanovb648a8a2014-05-19 15:06:58 -07002031 soinfo_unload(si);
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07002032 return 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002033}
2034
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -08002035bool init_anonymous_namespace(const char* shared_lib_sonames, const char* library_search_path) {
2036 if (g_anonymous_namespace_initialized) {
2037 DL_ERR("anonymous namespace has already been initialized.");
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002038 return false;
2039 }
2040
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002041 ProtectedDataGuard guard;
2042
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -08002043 g_anonymous_namespace_initialized = true;
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002044
2045 // create anonymous namespace
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002046 // When the caller is nullptr - create_namespace will take global group
2047 // from the anonymous namespace, which is fine because anonymous namespace
2048 // is still pointing to the default one.
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002049 android_namespace_t* anon_ns =
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -08002050 create_namespace(nullptr,
2051 "(anonymous)",
2052 nullptr,
2053 library_search_path,
2054 // TODO (dimitry): change to isolated eventually.
2055 ANDROID_NAMESPACE_TYPE_REGULAR,
2056 nullptr,
2057 &g_default_namespace);
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002058
2059 if (anon_ns == nullptr) {
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -08002060 g_anonymous_namespace_initialized = false;
2061 return false;
2062 }
2063
2064 if (!link_namespaces(anon_ns, &g_default_namespace, shared_lib_sonames)) {
2065 g_anonymous_namespace_initialized = false;
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002066 return false;
2067 }
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08002068
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002069 g_anonymous_namespace = anon_ns;
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -08002070
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002071 return true;
2072}
2073
Dimitry Ivanovb943f302016-08-03 16:00:10 -07002074static void add_soinfos_to_namespace(const soinfo_list_t& soinfos, android_namespace_t* ns) {
2075 ns->add_soinfos(soinfos);
2076 for (auto si : soinfos) {
2077 si->add_secondary_namespace(ns);
2078 }
2079}
2080
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002081android_namespace_t* create_namespace(const void* caller_addr,
2082 const char* name,
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002083 const char* ld_library_path,
2084 const char* default_library_path,
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002085 uint64_t type,
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002086 const char* permitted_when_isolated_path,
2087 android_namespace_t* parent_namespace) {
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -08002088 if (!g_anonymous_namespace_initialized) {
2089 DL_ERR("cannot create namespace: anonymous namespace is not initialized.");
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002090 return nullptr;
2091 }
2092
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002093 if (parent_namespace == nullptr) {
Dimitry Ivanov52408632016-05-23 10:31:11 -07002094 // if parent_namespace is nullptr -> set it to the caller namespace
2095 soinfo* caller_soinfo = find_containing_library(caller_addr);
2096
2097 parent_namespace = caller_soinfo != nullptr ?
2098 caller_soinfo->get_primary_namespace() :
2099 g_anonymous_namespace;
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002100 }
2101
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002102 ProtectedDataGuard guard;
2103 std::vector<std::string> ld_library_paths;
2104 std::vector<std::string> default_library_paths;
Dimitry Ivanov284ae352015-12-08 10:47:13 -08002105 std::vector<std::string> permitted_paths;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002106
2107 parse_path(ld_library_path, ":", &ld_library_paths);
2108 parse_path(default_library_path, ":", &default_library_paths);
Dimitry Ivanov284ae352015-12-08 10:47:13 -08002109 parse_path(permitted_when_isolated_path, ":", &permitted_paths);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002110
2111 android_namespace_t* ns = new (g_namespace_allocator.alloc()) android_namespace_t();
2112 ns->set_name(name);
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002113 ns->set_isolated((type & ANDROID_NAMESPACE_TYPE_ISOLATED) != 0);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002114 ns->set_ld_library_paths(std::move(ld_library_paths));
2115 ns->set_default_library_paths(std::move(default_library_paths));
Dimitry Ivanov284ae352015-12-08 10:47:13 -08002116 ns->set_permitted_paths(std::move(permitted_paths));
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002117
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002118 if ((type & ANDROID_NAMESPACE_TYPE_SHARED) != 0) {
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002119 // If shared - clone the parent namespace
Dimitry Ivanovb943f302016-08-03 16:00:10 -07002120 add_soinfos_to_namespace(parent_namespace->soinfo_list(), ns);
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002121 } else {
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002122 // If not shared - copy only the shared group
Dimitry Ivanovb943f302016-08-03 16:00:10 -07002123 add_soinfos_to_namespace(get_shared_group(parent_namespace), ns);
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002124 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002125
2126 return ns;
2127}
2128
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -08002129bool link_namespaces(android_namespace_t* namespace_from,
2130 android_namespace_t* namespace_to,
2131 const char* shared_lib_sonames) {
2132 if (namespace_to == nullptr) {
2133 namespace_to = &g_default_namespace;
2134 }
2135
2136 if (namespace_from == nullptr) {
2137 DL_ERR("error linking namespaces: namespace_from is null.");
2138 return false;
2139 }
2140
2141 if (shared_lib_sonames == nullptr || shared_lib_sonames[0] == '\0') {
2142 DL_ERR("error linking namespaces \"%s\"->\"%s\": the list of shared libraries is empty.",
2143 namespace_from->get_name(), namespace_to->get_name());
2144 return false;
2145 }
2146
2147 auto sonames = android::base::Split(shared_lib_sonames, ":");
2148 std::unordered_set<std::string> sonames_set(sonames.begin(), sonames.end());
2149
2150 ProtectedDataGuard guard;
2151 namespace_from->add_linked_namespace(namespace_to, sonames_set);
2152
2153 return true;
2154}
2155
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002156ElfW(Addr) call_ifunc_resolver(ElfW(Addr) resolver_addr) {
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07002157 typedef ElfW(Addr) (*ifunc_resolver_t)(void);
2158 ifunc_resolver_t ifunc_resolver = reinterpret_cast<ifunc_resolver_t>(resolver_addr);
2159 ElfW(Addr) ifunc_addr = ifunc_resolver();
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002160 TRACE_TYPE(RELO, "Called ifunc_resolver@%p. The result is %p",
2161 ifunc_resolver, reinterpret_cast<void*>(ifunc_addr));
Brigid Smithc5a13ef2014-07-23 11:22:25 -07002162
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07002163 return ifunc_addr;
Brigid Smithc5a13ef2014-07-23 11:22:25 -07002164}
Brigid Smithc5a13ef2014-07-23 11:22:25 -07002165
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002166const version_info* VersionTracker::get_version_info(ElfW(Versym) source_symver) const {
2167 if (source_symver < 2 ||
2168 source_symver >= version_infos.size() ||
2169 version_infos[source_symver].name == nullptr) {
2170 return nullptr;
2171 }
2172
2173 return &version_infos[source_symver];
2174}
2175
2176void VersionTracker::add_version_info(size_t source_index,
2177 ElfW(Word) elf_hash,
2178 const char* ver_name,
2179 const soinfo* target_si) {
2180 if (source_index >= version_infos.size()) {
2181 version_infos.resize(source_index+1);
2182 }
2183
2184 version_infos[source_index].elf_hash = elf_hash;
2185 version_infos[source_index].name = ver_name;
2186 version_infos[source_index].target_si = target_si;
2187}
2188
2189bool VersionTracker::init_verneed(const soinfo* si_from) {
2190 uintptr_t verneed_ptr = si_from->get_verneed_ptr();
2191
2192 if (verneed_ptr == 0) {
2193 return true;
2194 }
2195
2196 size_t verneed_cnt = si_from->get_verneed_cnt();
2197
2198 for (size_t i = 0, offset = 0; i<verneed_cnt; ++i) {
2199 const ElfW(Verneed)* verneed = reinterpret_cast<ElfW(Verneed)*>(verneed_ptr + offset);
2200 size_t vernaux_offset = offset + verneed->vn_aux;
2201 offset += verneed->vn_next;
2202
2203 if (verneed->vn_version != 1) {
2204 DL_ERR("unsupported verneed[%zd] vn_version: %d (expected 1)", i, verneed->vn_version);
2205 return false;
2206 }
2207
2208 const char* target_soname = si_from->get_string(verneed->vn_file);
2209 // find it in dependencies
2210 soinfo* target_si = si_from->get_children().find_if([&](const soinfo* si) {
Dmitriy Ivanov406d9962015-05-06 11:05:27 -07002211 return si->get_soname() != nullptr && strcmp(si->get_soname(), target_soname) == 0;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002212 });
2213
2214 if (target_si == nullptr) {
2215 DL_ERR("cannot find \"%s\" from verneed[%zd] in DT_NEEDED list for \"%s\"",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002216 target_soname, i, si_from->get_realpath());
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002217 return false;
2218 }
2219
2220 for (size_t j = 0; j<verneed->vn_cnt; ++j) {
2221 const ElfW(Vernaux)* vernaux = reinterpret_cast<ElfW(Vernaux)*>(verneed_ptr + vernaux_offset);
2222 vernaux_offset += vernaux->vna_next;
2223
2224 const ElfW(Word) elf_hash = vernaux->vna_hash;
2225 const char* ver_name = si_from->get_string(vernaux->vna_name);
2226 ElfW(Half) source_index = vernaux->vna_other;
2227
2228 add_version_info(source_index, elf_hash, ver_name, target_si);
2229 }
2230 }
2231
2232 return true;
2233}
2234
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002235template <typename F>
2236static bool for_each_verdef(const soinfo* si, F functor) {
2237 if (!si->has_min_version(2)) {
2238 return true;
2239 }
2240
2241 uintptr_t verdef_ptr = si->get_verdef_ptr();
2242 if (verdef_ptr == 0) {
2243 return true;
2244 }
2245
2246 size_t offset = 0;
2247
2248 size_t verdef_cnt = si->get_verdef_cnt();
2249 for (size_t i = 0; i<verdef_cnt; ++i) {
2250 const ElfW(Verdef)* verdef = reinterpret_cast<ElfW(Verdef)*>(verdef_ptr + offset);
2251 size_t verdaux_offset = offset + verdef->vd_aux;
2252 offset += verdef->vd_next;
2253
2254 if (verdef->vd_version != 1) {
2255 DL_ERR("unsupported verdef[%zd] vd_version: %d (expected 1) library: %s",
2256 i, verdef->vd_version, si->get_realpath());
2257 return false;
2258 }
2259
2260 if ((verdef->vd_flags & VER_FLG_BASE) != 0) {
2261 // "this is the version of the file itself. It must not be used for
2262 // matching a symbol. It can be used to match references."
2263 //
2264 // http://www.akkadia.org/drepper/symbol-versioning
2265 continue;
2266 }
2267
2268 if (verdef->vd_cnt == 0) {
2269 DL_ERR("invalid verdef[%zd] vd_cnt == 0 (version without a name)", i);
2270 return false;
2271 }
2272
2273 const ElfW(Verdaux)* verdaux = reinterpret_cast<ElfW(Verdaux)*>(verdef_ptr + verdaux_offset);
2274
2275 if (functor(i, verdef, verdaux) == true) {
2276 break;
2277 }
2278 }
2279
2280 return true;
2281}
2282
2283bool find_verdef_version_index(const soinfo* si, const version_info* vi, ElfW(Versym)* versym) {
2284 if (vi == nullptr) {
2285 *versym = kVersymNotNeeded;
2286 return true;
2287 }
2288
2289 *versym = kVersymGlobal;
2290
2291 return for_each_verdef(si,
2292 [&](size_t, const ElfW(Verdef)* verdef, const ElfW(Verdaux)* verdaux) {
2293 if (verdef->vd_hash == vi->elf_hash &&
2294 strcmp(vi->name, si->get_string(verdaux->vda_name)) == 0) {
2295 *versym = verdef->vd_ndx;
2296 return true;
2297 }
2298
2299 return false;
2300 }
2301 );
2302}
2303
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002304bool VersionTracker::init_verdef(const soinfo* si_from) {
2305 return for_each_verdef(si_from,
2306 [&](size_t, const ElfW(Verdef)* verdef, const ElfW(Verdaux)* verdaux) {
2307 add_version_info(verdef->vd_ndx, verdef->vd_hash,
2308 si_from->get_string(verdaux->vda_name), si_from);
2309 return false;
2310 }
2311 );
2312}
2313
2314bool VersionTracker::init(const soinfo* si_from) {
2315 if (!si_from->has_min_version(2)) {
2316 return true;
2317 }
2318
2319 return init_verneed(si_from) && init_verdef(si_from);
2320}
2321
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002322// TODO (dimitry): Methods below need to be moved out of soinfo
2323// and in more isolated file in order minimize dependencies on
2324// unnecessary object in the linker binary. Consider making them
2325// independent from soinfo (?).
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002326bool soinfo::lookup_version_info(const VersionTracker& version_tracker, ElfW(Word) sym,
2327 const char* sym_name, const version_info** vi) {
2328 const ElfW(Versym)* sym_ver_ptr = get_versym(sym);
2329 ElfW(Versym) sym_ver = sym_ver_ptr == nullptr ? 0 : *sym_ver_ptr;
2330
2331 if (sym_ver != VER_NDX_LOCAL && sym_ver != VER_NDX_GLOBAL) {
2332 *vi = version_tracker.get_version_info(sym_ver);
2333
2334 if (*vi == nullptr) {
2335 DL_ERR("cannot find verneed/verdef for version index=%d "
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002336 "referenced by symbol \"%s\" at \"%s\"", sym_ver, sym_name, get_realpath());
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002337 return false;
2338 }
2339 } else {
2340 // there is no version info
2341 *vi = nullptr;
2342 }
2343
2344 return true;
2345}
2346
Dimitry Ivanov576a3752016-08-09 06:58:55 -07002347#if !defined(__mips__)
2348#if defined(USE_RELA)
2349static ElfW(Addr) get_addend(ElfW(Rela)* rela, ElfW(Addr) reloc_addr __unused) {
2350 return rela->r_addend;
2351}
2352#else
2353static ElfW(Addr) get_addend(ElfW(Rel)* rel, ElfW(Addr) reloc_addr) {
2354 if (ELFW(R_TYPE)(rel->r_info) == R_GENERIC_RELATIVE ||
2355 ELFW(R_TYPE)(rel->r_info) == R_GENERIC_IRELATIVE) {
2356 return *reinterpret_cast<ElfW(Addr)*>(reloc_addr);
2357 }
2358 return 0;
2359}
2360#endif
2361
Dmitriy Ivanovfa26eee2015-02-03 16:06:47 -08002362template<typename ElfRelIteratorT>
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07002363bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& rel_iterator,
2364 const soinfo_list_t& global_group, const soinfo_list_t& local_group) {
Dmitriy Ivanovfa26eee2015-02-03 16:06:47 -08002365 for (size_t idx = 0; rel_iterator.has_next(); ++idx) {
2366 const auto rel = rel_iterator.next();
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002367 if (rel == nullptr) {
2368 return false;
2369 }
2370
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002371 ElfW(Word) type = ELFW(R_TYPE)(rel->r_info);
2372 ElfW(Word) sym = ELFW(R_SYM)(rel->r_info);
2373
2374 ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rel->r_offset + load_bias);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002375 ElfW(Addr) sym_addr = 0;
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07002376 const char* sym_name = nullptr;
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002377 ElfW(Addr) addend = get_addend(rel, reloc);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002378
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07002379 DEBUG("Processing \"%s\" relocation at index %zd", get_realpath(), idx);
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002380 if (type == R_GENERIC_NONE) {
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002381 continue;
2382 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002383
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002384 const ElfW(Sym)* s = nullptr;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002385 soinfo* lsi = nullptr;
2386
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002387 if (sym != 0) {
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002388 sym_name = get_string(symtab_[sym].st_name);
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002389 const version_info* vi = nullptr;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002390
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002391 if (!lookup_version_info(version_tracker, sym, sym_name, &vi)) {
2392 return false;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002393 }
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002394
2395 if (!soinfo_do_lookup(this, sym_name, vi, &lsi, global_group, local_group, &s)) {
2396 return false;
2397 }
2398
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07002399 if (s == nullptr) {
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002400 // We only allow an undefined symbol if this is a weak reference...
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002401 s = &symtab_[sym];
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002402 if (ELF_ST_BIND(s->st_info) != STB_WEAK) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002403 DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, get_realpath());
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002404 return false;
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002405 }
2406
2407 /* IHI0044C AAELF 4.5.1.1:
2408
2409 Libraries are not searched to resolve weak references.
2410 It is not an error for a weak reference to remain unsatisfied.
2411
2412 During linking, the value of an undefined weak reference is:
2413 - Zero if the relocation type is absolute
2414 - The address of the place if the relocation is pc-relative
2415 - The address of nominal base address if the relocation
2416 type is base-relative.
2417 */
2418
2419 switch (type) {
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002420 case R_GENERIC_JUMP_SLOT:
2421 case R_GENERIC_GLOB_DAT:
2422 case R_GENERIC_RELATIVE:
2423 case R_GENERIC_IRELATIVE:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002424#if defined(__aarch64__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002425 case R_AARCH64_ABS64:
2426 case R_AARCH64_ABS32:
2427 case R_AARCH64_ABS16:
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002428#elif defined(__x86_64__)
2429 case R_X86_64_32:
2430 case R_X86_64_64:
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002431#elif defined(__arm__)
2432 case R_ARM_ABS32:
2433#elif defined(__i386__)
2434 case R_386_32:
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002435#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002436 /*
2437 * The sym_addr was initialized to be zero above, or the relocation
2438 * code below does not care about value of sym_addr.
2439 * No need to do anything.
2440 */
2441 break;
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002442#if defined(__x86_64__)
Dimitry Ivanovd338aac2015-01-13 22:31:54 +00002443 case R_X86_64_PC32:
2444 sym_addr = reloc;
2445 break;
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002446#elif defined(__i386__)
2447 case R_386_PC32:
2448 sym_addr = reloc;
2449 break;
2450#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002451 default:
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002452 DL_ERR("unknown weak reloc type %d @ %p (%zu)", type, rel, idx);
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002453 return false;
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002454 }
Dmitriy Ivanovec83a612015-07-26 07:37:09 -07002455 } else { // We got a definition.
2456#if !defined(__LP64__)
2457 // When relocating dso with text_relocation .text segment is
2458 // not executable. We need to restore elf flags before resolving
2459 // STT_GNU_IFUNC symbol.
2460 bool protect_segments = has_text_relocations &&
2461 lsi == this &&
2462 ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC;
2463 if (protect_segments) {
2464 if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
2465 DL_ERR("can't protect segments for \"%s\": %s",
2466 get_realpath(), strerror(errno));
2467 return false;
2468 }
2469 }
2470#endif
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07002471 sym_addr = lsi->resolve_symbol_address(s);
Dmitriy Ivanovec83a612015-07-26 07:37:09 -07002472#if !defined(__LP64__)
2473 if (protect_segments) {
2474 if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
2475 DL_ERR("can't unprotect loadable segments for \"%s\": %s",
2476 get_realpath(), strerror(errno));
2477 return false;
2478 }
2479 }
2480#endif
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002481 }
2482 count_relocation(kRelocSymbol);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002483 }
2484
2485 switch (type) {
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002486 case R_GENERIC_JUMP_SLOT:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002487 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002488 MARK(rel->r_offset);
2489 TRACE_TYPE(RELO, "RELO JMP_SLOT %16p <- %16p %s\n",
2490 reinterpret_cast<void*>(reloc),
2491 reinterpret_cast<void*>(sym_addr + addend), sym_name);
2492
2493 *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002494 break;
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002495 case R_GENERIC_GLOB_DAT:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002496 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002497 MARK(rel->r_offset);
2498 TRACE_TYPE(RELO, "RELO GLOB_DAT %16p <- %16p %s\n",
2499 reinterpret_cast<void*>(reloc),
2500 reinterpret_cast<void*>(sym_addr + addend), sym_name);
2501 *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002502 break;
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002503 case R_GENERIC_RELATIVE:
2504 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002505 MARK(rel->r_offset);
2506 TRACE_TYPE(RELO, "RELO RELATIVE %16p <- %16p\n",
2507 reinterpret_cast<void*>(reloc),
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002508 reinterpret_cast<void*>(load_bias + addend));
2509 *reinterpret_cast<ElfW(Addr)*>(reloc) = (load_bias + addend);
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002510 break;
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002511 case R_GENERIC_IRELATIVE:
2512 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002513 MARK(rel->r_offset);
2514 TRACE_TYPE(RELO, "RELO IRELATIVE %16p <- %16p\n",
2515 reinterpret_cast<void*>(reloc),
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002516 reinterpret_cast<void*>(load_bias + addend));
Dmitriy Ivanovec83a612015-07-26 07:37:09 -07002517 {
2518#if !defined(__LP64__)
2519 // When relocating dso with text_relocation .text segment is
2520 // not executable. We need to restore elf flags for this
2521 // particular call.
2522 if (has_text_relocations) {
2523 if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
2524 DL_ERR("can't protect segments for \"%s\": %s",
2525 get_realpath(), strerror(errno));
2526 return false;
2527 }
2528 }
2529#endif
2530 ElfW(Addr) ifunc_addr = call_ifunc_resolver(load_bias + addend);
2531#if !defined(__LP64__)
2532 // Unprotect it afterwards...
2533 if (has_text_relocations) {
2534 if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
2535 DL_ERR("can't unprotect loadable segments for \"%s\": %s",
2536 get_realpath(), strerror(errno));
2537 return false;
2538 }
2539 }
2540#endif
2541 *reinterpret_cast<ElfW(Addr)*>(reloc) = ifunc_addr;
2542 }
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002543 break;
2544
2545#if defined(__aarch64__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002546 case R_AARCH64_ABS64:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002547 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002548 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002549 TRACE_TYPE(RELO, "RELO ABS64 %16llx <- %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002550 reloc, sym_addr + addend, sym_name);
2551 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend;
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002552 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002553 case R_AARCH64_ABS32:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002554 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002555 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002556 TRACE_TYPE(RELO, "RELO ABS32 %16llx <- %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002557 reloc, sym_addr + addend, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002558 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002559 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT32_MIN);
2560 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT32_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002561 if ((min_value <= (sym_addr + addend)) &&
2562 ((sym_addr + addend) <= max_value)) {
2563 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend;
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002564 } else {
2565 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002566 sym_addr + addend, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002567 return false;
2568 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002569 }
2570 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002571 case R_AARCH64_ABS16:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002572 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002573 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002574 TRACE_TYPE(RELO, "RELO ABS16 %16llx <- %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002575 reloc, sym_addr + addend, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002576 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002577 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN);
2578 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT16_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002579 if ((min_value <= (sym_addr + addend)) &&
2580 ((sym_addr + addend) <= max_value)) {
2581 *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002582 } else {
2583 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002584 sym_addr + addend, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002585 return false;
2586 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002587 }
2588 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002589 case R_AARCH64_PREL64:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002590 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002591 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002592 TRACE_TYPE(RELO, "RELO REL64 %16llx <- %16llx - %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002593 reloc, sym_addr + addend, rel->r_offset, sym_name);
2594 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset;
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002595 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002596 case R_AARCH64_PREL32:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002597 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002598 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002599 TRACE_TYPE(RELO, "RELO REL32 %16llx <- %16llx - %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002600 reloc, sym_addr + addend, rel->r_offset, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002601 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002602 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT32_MIN);
2603 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT32_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002604 if ((min_value <= (sym_addr + addend - rel->r_offset)) &&
2605 ((sym_addr + addend - rel->r_offset) <= max_value)) {
2606 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset;
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002607 } else {
2608 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002609 sym_addr + addend - rel->r_offset, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002610 return false;
2611 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002612 }
2613 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002614 case R_AARCH64_PREL16:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002615 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002616 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002617 TRACE_TYPE(RELO, "RELO REL16 %16llx <- %16llx - %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002618 reloc, sym_addr + addend, rel->r_offset, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002619 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002620 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN);
2621 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT16_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002622 if ((min_value <= (sym_addr + addend - rel->r_offset)) &&
2623 ((sym_addr + addend - rel->r_offset) <= max_value)) {
2624 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset;
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002625 } else {
2626 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002627 sym_addr + addend - rel->r_offset, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002628 return false;
2629 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002630 }
2631 break;
2632
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002633 case R_AARCH64_COPY:
Nick Kralevich76e289c2014-07-03 12:04:31 -07002634 /*
2635 * ET_EXEC is not supported so this should not happen.
2636 *
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002637 * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0056b/IHI0056B_aaelf64.pdf
Nick Kralevich76e289c2014-07-03 12:04:31 -07002638 *
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002639 * Section 4.6.11 "Dynamic relocations"
Nick Kralevich76e289c2014-07-03 12:04:31 -07002640 * R_AARCH64_COPY may only appear in executable objects where e_type is
2641 * set to ET_EXEC.
2642 */
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002643 DL_ERR("%s R_AARCH64_COPY relocations are not supported", get_realpath());
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002644 return false;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002645 case R_AARCH64_TLS_TPREL64:
Elliott Hughes0266ae52014-02-10 17:46:57 -08002646 TRACE_TYPE(RELO, "RELO TLS_TPREL64 *** %16llx <- %16llx - %16llx\n",
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002647 reloc, (sym_addr + addend), rel->r_offset);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002648 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002649 case R_AARCH64_TLS_DTPREL32:
Elliott Hughes0266ae52014-02-10 17:46:57 -08002650 TRACE_TYPE(RELO, "RELO TLS_DTPREL32 *** %16llx <- %16llx - %16llx\n",
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002651 reloc, (sym_addr + addend), rel->r_offset);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002652 break;
2653#elif defined(__x86_64__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002654 case R_X86_64_32:
2655 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002656 MARK(rel->r_offset);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002657 TRACE_TYPE(RELO, "RELO R_X86_64_32 %08zx <- +%08zx %s", static_cast<size_t>(reloc),
2658 static_cast<size_t>(sym_addr), sym_name);
Junichi Uekawaff35b1e2015-11-18 10:18:59 +09002659 *reinterpret_cast<Elf32_Addr*>(reloc) = sym_addr + addend;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002660 break;
2661 case R_X86_64_64:
2662 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002663 MARK(rel->r_offset);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002664 TRACE_TYPE(RELO, "RELO R_X86_64_64 %08zx <- +%08zx %s", static_cast<size_t>(reloc),
2665 static_cast<size_t>(sym_addr), sym_name);
Junichi Uekawaff35b1e2015-11-18 10:18:59 +09002666 *reinterpret_cast<Elf64_Addr*>(reloc) = sym_addr + addend;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002667 break;
2668 case R_X86_64_PC32:
2669 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002670 MARK(rel->r_offset);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002671 TRACE_TYPE(RELO, "RELO R_X86_64_PC32 %08zx <- +%08zx (%08zx - %08zx) %s",
2672 static_cast<size_t>(reloc), static_cast<size_t>(sym_addr - reloc),
2673 static_cast<size_t>(sym_addr), static_cast<size_t>(reloc), sym_name);
Junichi Uekawaff35b1e2015-11-18 10:18:59 +09002674 *reinterpret_cast<Elf32_Addr*>(reloc) = sym_addr + addend - reloc;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002675 break;
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002676#elif defined(__arm__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002677 case R_ARM_ABS32:
2678 count_relocation(kRelocAbsolute);
2679 MARK(rel->r_offset);
2680 TRACE_TYPE(RELO, "RELO ABS %08x <- %08x %s", reloc, sym_addr, sym_name);
2681 *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
2682 break;
2683 case R_ARM_REL32:
2684 count_relocation(kRelocRelative);
2685 MARK(rel->r_offset);
2686 TRACE_TYPE(RELO, "RELO REL32 %08x <- %08x - %08x %s",
2687 reloc, sym_addr, rel->r_offset, sym_name);
2688 *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr - rel->r_offset;
2689 break;
2690 case R_ARM_COPY:
2691 /*
2692 * ET_EXEC is not supported so this should not happen.
2693 *
2694 * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044d/IHI0044D_aaelf.pdf
2695 *
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002696 * Section 4.6.1.10 "Dynamic relocations"
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002697 * R_ARM_COPY may only appear in executable objects where e_type is
2698 * set to ET_EXEC.
2699 */
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002700 DL_ERR("%s R_ARM_COPY relocations are not supported", get_realpath());
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002701 return false;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002702#elif defined(__i386__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002703 case R_386_32:
2704 count_relocation(kRelocRelative);
2705 MARK(rel->r_offset);
2706 TRACE_TYPE(RELO, "RELO R_386_32 %08x <- +%08x %s", reloc, sym_addr, sym_name);
2707 *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
2708 break;
2709 case R_386_PC32:
2710 count_relocation(kRelocRelative);
2711 MARK(rel->r_offset);
2712 TRACE_TYPE(RELO, "RELO R_386_PC32 %08x <- +%08x (%08x - %08x) %s",
2713 reloc, (sym_addr - reloc), sym_addr, reloc, sym_name);
2714 *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr - reloc);
2715 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002716#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002717 default:
2718 DL_ERR("unknown reloc type %d @ %p (%zu)", type, rel, idx);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002719 return false;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002720 }
2721 }
2722 return true;
Raghu Gandhamd7daacb2012-07-31 12:07:22 -07002723}
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002724#endif // !defined(__mips__)
Raghu Gandhamd7daacb2012-07-31 12:07:22 -07002725
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002726// An empty list of soinfos
Dimitry Ivanovb943f302016-08-03 16:00:10 -07002727static soinfo_list_t g_empty_list;
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07002728
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002729bool soinfo::prelink_image() {
Ningsheng Jiane93be992014-09-16 15:22:10 +08002730 /* Extract dynamic section */
2731 ElfW(Word) dynamic_flags = 0;
2732 phdr_table_get_dynamic_section(phdr, phnum, load_bias, &dynamic, &dynamic_flags);
Dmitriy Ivanov498eb182014-09-05 14:57:59 -07002733
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002734 /* We can't log anything until the linker is relocated */
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002735 bool relocating_linker = (flags_ & FLAG_LINKER) != 0;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002736 if (!relocating_linker) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07002737 INFO("[ Linking \"%s\" ]", get_realpath());
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002738 DEBUG("si->base = %p si->flags = 0x%08x", reinterpret_cast<void*>(base), flags_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002739 }
2740
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002741 if (dynamic == nullptr) {
David 'Digit' Turnerb52e4382012-06-19 01:24:17 +02002742 if (!relocating_linker) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002743 DL_ERR("missing PT_DYNAMIC in \"%s\"", get_realpath());
David 'Digit' Turnerb52e4382012-06-19 01:24:17 +02002744 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002745 return false;
2746 } else {
2747 if (!relocating_linker) {
2748 DEBUG("dynamic = %p", dynamic);
David 'Digit' Turner63f99f42012-06-19 00:08:39 +02002749 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002750 }
David 'Digit' Turner63f99f42012-06-19 00:08:39 +02002751
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07002752#if defined(__arm__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002753 (void) phdr_table_get_arm_exidx(phdr, phnum, load_bias,
2754 &ARM_exidx, &ARM_exidx_count);
David 'Digit' Turner63f99f42012-06-19 00:08:39 +02002755#endif
2756
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002757 // Extract useful information from dynamic section.
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07002758 // Note that: "Except for the DT_NULL element at the end of the array,
2759 // and the relative order of DT_NEEDED elements, entries may appear in any order."
2760 //
2761 // source: http://www.sco.com/developers/gabi/1998-04-29/ch5.dynamic.html
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002762 uint32_t needed_count = 0;
2763 for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
2764 DEBUG("d = %p, d[0](tag) = %p d[1](val) = %p",
2765 d, reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
2766 switch (d->d_tag) {
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002767 case DT_SONAME:
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07002768 // this is parsed after we have strtab initialized (see below).
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002769 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002770
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002771 case DT_HASH:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002772 nbucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0];
2773 nchain_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
2774 bucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8);
2775 chain_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8 + nbucket_ * 4);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002776 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002777
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002778 case DT_GNU_HASH:
Dmitriy Ivanov3597b802015-03-09 12:02:02 -07002779 gnu_nbucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0];
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002780 // skip symndx
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002781 gnu_maskwords_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[2];
2782 gnu_shift2_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[3];
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002783
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002784 gnu_bloom_filter_ = reinterpret_cast<ElfW(Addr)*>(load_bias + d->d_un.d_ptr + 16);
Dmitriy Ivanov3597b802015-03-09 12:02:02 -07002785 gnu_bucket_ = reinterpret_cast<uint32_t*>(gnu_bloom_filter_ + gnu_maskwords_);
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002786 // amend chain for symndx = header[1]
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002787 gnu_chain_ = gnu_bucket_ + gnu_nbucket_ -
2788 reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002789
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002790 if (!powerof2(gnu_maskwords_)) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002791 DL_ERR("invalid maskwords for gnu_hash = 0x%x, in \"%s\" expecting power to two",
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002792 gnu_maskwords_, get_realpath());
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002793 return false;
2794 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002795 --gnu_maskwords_;
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002796
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002797 flags_ |= FLAG_GNU_HASH;
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002798 break;
2799
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002800 case DT_STRTAB:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002801 strtab_ = reinterpret_cast<const char*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002802 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002803
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07002804 case DT_STRSZ:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002805 strtab_size_ = d->d_un.d_val;
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07002806 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002807
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002808 case DT_SYMTAB:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002809 symtab_ = reinterpret_cast<ElfW(Sym)*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002810 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002811
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002812 case DT_SYMENT:
2813 if (d->d_un.d_val != sizeof(ElfW(Sym))) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002814 DL_ERR("invalid DT_SYMENT: %zd in \"%s\"",
2815 static_cast<size_t>(d->d_un.d_val), get_realpath());
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002816 return false;
2817 }
2818 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002819
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002820 case DT_PLTREL:
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002821#if defined(USE_RELA)
2822 if (d->d_un.d_val != DT_RELA) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002823 DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_RELA", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002824 return false;
2825 }
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002826#else
2827 if (d->d_un.d_val != DT_REL) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002828 DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_REL", get_realpath());
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002829 return false;
2830 }
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002831#endif
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002832 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002833
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002834 case DT_JMPREL:
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07002835#if defined(USE_RELA)
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002836 plt_rela_ = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002837#else
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002838 plt_rel_ = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002839#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002840 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002841
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002842 case DT_PLTRELSZ:
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07002843#if defined(USE_RELA)
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002844 plt_rela_count_ = d->d_un.d_val / sizeof(ElfW(Rela));
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002845#else
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002846 plt_rel_count_ = d->d_un.d_val / sizeof(ElfW(Rel));
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002847#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002848 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002849
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002850 case DT_PLTGOT:
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002851#if defined(__mips__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002852 // Used by mips and mips64.
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002853 plt_got_ = reinterpret_cast<ElfW(Addr)**>(load_bias + d->d_un.d_ptr);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002854#endif
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002855 // Ignore for other platforms... (because RTLD_LAZY is not supported)
2856 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002857
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002858 case DT_DEBUG:
2859 // Set the DT_DEBUG entry to the address of _r_debug for GDB
2860 // if the dynamic table is writable
Chris Dearman99186652014-02-06 20:36:51 -08002861// FIXME: not working currently for N64
2862// The flags for the LOAD and DYNAMIC program headers do not agree.
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002863// The LOAD section containing the dynamic table has been mapped as
Chris Dearman99186652014-02-06 20:36:51 -08002864// read-only, but the DYNAMIC header claims it is writable.
2865#if !(defined(__mips__) && defined(__LP64__))
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002866 if ((dynamic_flags & PF_W) != 0) {
2867 d->d_un.d_val = reinterpret_cast<uintptr_t>(&_r_debug);
2868 }
Chris Dearman99186652014-02-06 20:36:51 -08002869#endif
Dmitriy Ivanovc6292ea2015-02-13 16:29:50 -08002870 break;
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07002871#if defined(USE_RELA)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002872 case DT_RELA:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002873 rela_ = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002874 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002875
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002876 case DT_RELASZ:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002877 rela_count_ = d->d_un.d_val / sizeof(ElfW(Rela));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002878 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002879
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002880 case DT_ANDROID_RELA:
2881 android_relocs_ = reinterpret_cast<uint8_t*>(load_bias + d->d_un.d_ptr);
2882 break;
2883
2884 case DT_ANDROID_RELASZ:
2885 android_relocs_size_ = d->d_un.d_val;
2886 break;
2887
2888 case DT_ANDROID_REL:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002889 DL_ERR("unsupported DT_ANDROID_REL in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002890 return false;
2891
2892 case DT_ANDROID_RELSZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002893 DL_ERR("unsupported DT_ANDROID_RELSZ in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002894 return false;
2895
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002896 case DT_RELAENT:
2897 if (d->d_un.d_val != sizeof(ElfW(Rela))) {
Dmitriy Ivanovf240aa82014-09-16 23:34:20 -07002898 DL_ERR("invalid DT_RELAENT: %zd", static_cast<size_t>(d->d_un.d_val));
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002899 return false;
2900 }
2901 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002902
2903 // ignored (see DT_RELCOUNT comments for details)
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002904 case DT_RELACOUNT:
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002905 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002906
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002907 case DT_REL:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002908 DL_ERR("unsupported DT_REL in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002909 return false;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002910
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002911 case DT_RELSZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002912 DL_ERR("unsupported DT_RELSZ in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002913 return false;
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002914
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002915#else
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002916 case DT_REL:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002917 rel_ = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002918 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002919
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002920 case DT_RELSZ:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002921 rel_count_ = d->d_un.d_val / sizeof(ElfW(Rel));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002922 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002923
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002924 case DT_RELENT:
2925 if (d->d_un.d_val != sizeof(ElfW(Rel))) {
Dmitriy Ivanovf240aa82014-09-16 23:34:20 -07002926 DL_ERR("invalid DT_RELENT: %zd", static_cast<size_t>(d->d_un.d_val));
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002927 return false;
2928 }
2929 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002930
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002931 case DT_ANDROID_REL:
2932 android_relocs_ = reinterpret_cast<uint8_t*>(load_bias + d->d_un.d_ptr);
2933 break;
2934
2935 case DT_ANDROID_RELSZ:
2936 android_relocs_size_ = d->d_un.d_val;
2937 break;
2938
2939 case DT_ANDROID_RELA:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002940 DL_ERR("unsupported DT_ANDROID_RELA in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002941 return false;
2942
2943 case DT_ANDROID_RELASZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002944 DL_ERR("unsupported DT_ANDROID_RELASZ in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002945 return false;
2946
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002947 // "Indicates that all RELATIVE relocations have been concatenated together,
2948 // and specifies the RELATIVE relocation count."
2949 //
2950 // TODO: Spec also mentions that this can be used to optimize relocation process;
2951 // Not currently used by bionic linker - ignored.
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002952 case DT_RELCOUNT:
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002953 break;
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002954
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002955 case DT_RELA:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002956 DL_ERR("unsupported DT_RELA in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002957 return false;
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002958
2959 case DT_RELASZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002960 DL_ERR("unsupported DT_RELASZ in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002961 return false;
2962
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002963#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002964 case DT_INIT:
Dimitry Ivanov55437462016-07-20 15:33:07 -07002965 init_func_ = reinterpret_cast<linker_ctor_function_t>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002966 DEBUG("%s constructors (DT_INIT) found at %p", get_realpath(), init_func_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002967 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002968
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002969 case DT_FINI:
Dimitry Ivanov55437462016-07-20 15:33:07 -07002970 fini_func_ = reinterpret_cast<linker_dtor_function_t>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002971 DEBUG("%s destructors (DT_FINI) found at %p", get_realpath(), fini_func_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002972 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002973
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002974 case DT_INIT_ARRAY:
Dimitry Ivanov55437462016-07-20 15:33:07 -07002975 init_array_ = reinterpret_cast<linker_ctor_function_t*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002976 DEBUG("%s constructors (DT_INIT_ARRAY) found at %p", get_realpath(), init_array_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002977 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002978
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002979 case DT_INIT_ARRAYSZ:
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -08002980 init_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002981 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002982
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002983 case DT_FINI_ARRAY:
Dimitry Ivanov55437462016-07-20 15:33:07 -07002984 fini_array_ = reinterpret_cast<linker_dtor_function_t*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002985 DEBUG("%s destructors (DT_FINI_ARRAY) found at %p", get_realpath(), fini_array_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002986 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002987
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002988 case DT_FINI_ARRAYSZ:
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -08002989 fini_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002990 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002991
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002992 case DT_PREINIT_ARRAY:
Dimitry Ivanov55437462016-07-20 15:33:07 -07002993 preinit_array_ = reinterpret_cast<linker_ctor_function_t*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002994 DEBUG("%s constructors (DT_PREINIT_ARRAY) found at %p", get_realpath(), preinit_array_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002995 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002996
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002997 case DT_PREINIT_ARRAYSZ:
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -08002998 preinit_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002999 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003000
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003001 case DT_TEXTREL:
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003002#if defined(__LP64__)
Dimitry Ivanov816676e2016-10-19 11:00:28 -07003003 DL_ERR("\"%s\" has text relocations", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003004 return false;
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003005#else
3006 has_text_relocations = true;
3007 break;
3008#endif
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003009
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003010 case DT_SYMBOLIC:
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -07003011 has_DT_SYMBOLIC = true;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003012 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003013
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003014 case DT_NEEDED:
3015 ++needed_count;
3016 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003017
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003018 case DT_FLAGS:
3019 if (d->d_un.d_val & DF_TEXTREL) {
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003020#if defined(__LP64__)
Dimitry Ivanov816676e2016-10-19 11:00:28 -07003021 DL_ERR("\"%s\" has text relocations", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003022 return false;
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003023#else
3024 has_text_relocations = true;
3025#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003026 }
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -07003027 if (d->d_un.d_val & DF_SYMBOLIC) {
3028 has_DT_SYMBOLIC = true;
3029 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003030 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003031
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07003032 case DT_FLAGS_1:
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07003033 set_dt_flags_1(d->d_un.d_val);
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -07003034
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07003035 if ((d->d_un.d_val & ~SUPPORTED_DT_FLAGS_1) != 0) {
Dimitry Ivanov816676e2016-10-19 11:00:28 -07003036 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 -07003037 }
3038 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003039#if defined(__mips__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003040 case DT_MIPS_RLD_MAP:
3041 // Set the DT_MIPS_RLD_MAP entry to the address of _r_debug for GDB.
3042 {
3043 r_debug** dp = reinterpret_cast<r_debug**>(load_bias + d->d_un.d_ptr);
3044 *dp = &_r_debug;
3045 }
3046 break;
Lazar Trsic83b44a92016-04-06 13:39:17 +02003047 case DT_MIPS_RLD_MAP_REL:
3048 // Set the DT_MIPS_RLD_MAP_REL entry to the address of _r_debug for GDB.
Raghu Gandham68815722014-12-18 19:12:19 -08003049 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07003050 r_debug** dp = reinterpret_cast<r_debug**>(
3051 reinterpret_cast<ElfW(Addr)>(d) + d->d_un.d_val);
Raghu Gandham68815722014-12-18 19:12:19 -08003052 *dp = &_r_debug;
3053 }
3054 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003055
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003056 case DT_MIPS_RLD_VERSION:
3057 case DT_MIPS_FLAGS:
3058 case DT_MIPS_BASE_ADDRESS:
3059 case DT_MIPS_UNREFEXTNO:
3060 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003061
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003062 case DT_MIPS_SYMTABNO:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003063 mips_symtabno_ = d->d_un.d_val;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003064 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003065
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003066 case DT_MIPS_LOCAL_GOTNO:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003067 mips_local_gotno_ = d->d_un.d_val;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003068 break;
3069
3070 case DT_MIPS_GOTSYM:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003071 mips_gotsym_ = d->d_un.d_val;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003072 break;
3073#endif
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003074 // Ignored: "Its use has been superseded by the DF_BIND_NOW flag"
3075 case DT_BIND_NOW:
3076 break;
3077
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003078 case DT_VERSYM:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003079 versym_ = reinterpret_cast<ElfW(Versym)*>(load_bias + d->d_un.d_ptr);
3080 break;
3081
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003082 case DT_VERDEF:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003083 verdef_ptr_ = load_bias + d->d_un.d_ptr;
3084 break;
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003085 case DT_VERDEFNUM:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003086 verdef_cnt_ = d->d_un.d_val;
3087 break;
3088
Alexander Ivchenkoe8314332014-12-02 15:32:25 +03003089 case DT_VERNEED:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003090 verneed_ptr_ = load_bias + d->d_un.d_ptr;
3091 break;
3092
Alexander Ivchenkoe8314332014-12-02 15:32:25 +03003093 case DT_VERNEEDNUM:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003094 verneed_cnt_ = d->d_un.d_val;
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003095 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003096
Evgenii Stepanov68650822015-06-10 13:38:39 -07003097 case DT_RUNPATH:
3098 // this is parsed after we have strtab initialized (see below).
3099 break;
3100
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003101 default:
Dmitriy Ivanov8f61d992014-09-16 14:31:06 -07003102 if (!relocating_linker) {
Dimitry Ivanov816676e2016-10-19 11:00:28 -07003103 DL_WARN("\"%s\" unused DT entry: type %p arg %p", get_realpath(),
Dmitriy Ivanov8f61d992014-09-16 14:31:06 -07003104 reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
3105 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003106 break;
Brian Carlstromd4ee82d2013-02-28 15:58:45 -08003107 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003108 }
3109
Duane Sandbc425c72015-06-01 16:29:14 -07003110#if defined(__mips__) && !defined(__LP64__)
3111 if (!mips_check_and_adjust_fp_modes()) {
3112 return false;
3113 }
3114#endif
3115
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003116 DEBUG("si->base = %p, si->strtab = %p, si->symtab = %p",
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003117 reinterpret_cast<void*>(base), strtab_, symtab_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003118
3119 // Sanity checks.
3120 if (relocating_linker && needed_count != 0) {
3121 DL_ERR("linker cannot have DT_NEEDED dependencies on other libraries");
3122 return false;
3123 }
Dmitriy Ivanov3597b802015-03-09 12:02:02 -07003124 if (nbucket_ == 0 && gnu_nbucket_ == 0) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003125 DL_ERR("empty/missing DT_HASH/DT_GNU_HASH in \"%s\" "
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003126 "(new hash type from the future?)", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003127 return false;
3128 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003129 if (strtab_ == 0) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003130 DL_ERR("empty/missing DT_STRTAB in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003131 return false;
3132 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003133 if (symtab_ == 0) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003134 DL_ERR("empty/missing DT_SYMTAB in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003135 return false;
3136 }
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003137
Dmitriy Ivanov624b8f12015-06-08 10:41:33 -07003138 // second pass - parse entries relying on strtab
3139 for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
Evgenii Stepanov68650822015-06-10 13:38:39 -07003140 switch (d->d_tag) {
3141 case DT_SONAME:
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07003142 set_soname(get_string(d->d_un.d_val));
Evgenii Stepanov68650822015-06-10 13:38:39 -07003143 break;
3144 case DT_RUNPATH:
Evgenii Stepanov68650822015-06-10 13:38:39 -07003145 set_dt_runpath(get_string(d->d_un.d_val));
3146 break;
Dmitriy Ivanov624b8f12015-06-08 10:41:33 -07003147 }
3148 }
3149
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003150 // Before M release linker was using basename in place of soname.
Dmitriy Ivanov19133522015-06-02 17:36:54 -07003151 // In the case when dt_soname is absent some apps stop working
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003152 // because they can't find dt_needed library by soname.
3153 // This workaround should keep them working. (applies only
Elliott Hughes5bc78c82016-11-16 11:35:43 -08003154 // for apps targeting sdk version < M). Make an exception for
Dmitriy Ivanov19133522015-06-02 17:36:54 -07003155 // the main executable and linker; they do not need to have dt_soname
Dimitry Ivanov3f660572016-09-09 10:00:39 -07003156 if (soname_ == nullptr &&
3157 this != solist_get_somain() &&
3158 (flags_ & FLAG_LINKER) == 0 &&
Elliott Hughes5bc78c82016-11-16 11:35:43 -08003159 get_application_target_sdk_version() < __ANDROID_API_M__) {
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003160 soname_ = basename(realpath_.c_str());
3161 DL_WARN("%s: is missing DT_SONAME will use basename as a replacement: \"%s\"",
3162 get_realpath(), soname_);
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07003163 // 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 -07003164 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003165 return true;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07003166}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003167
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003168bool soinfo::link_image(const soinfo_list_t& global_group, const soinfo_list_t& local_group,
3169 const android_dlextinfo* extinfo) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003170
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08003171 local_group_root_ = local_group.front();
3172 if (local_group_root_ == nullptr) {
3173 local_group_root_ = this;
3174 }
3175
Dmitriy Ivanov19133522015-06-02 17:36:54 -07003176 if ((flags_ & FLAG_LINKER) == 0 && local_group_root_ == this) {
3177 target_sdk_version_ = get_application_target_sdk_version();
3178 }
3179
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003180 VersionTracker version_tracker;
3181
3182 if (!version_tracker.init(this)) {
3183 return false;
3184 }
3185
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003186#if !defined(__LP64__)
3187 if (has_text_relocations) {
Elliott Hughes5bc78c82016-11-16 11:35:43 -08003188 // Fail if app is targeting M or above.
3189 if (get_application_target_sdk_version() >= __ANDROID_API_M__) {
Dimitry Ivanov816676e2016-10-19 11:00:28 -07003190 DL_ERR_AND_LOG("\"%s\" has text relocations", get_realpath());
Dmitriy Ivanove4ad91f2015-06-12 15:00:31 -07003191 return false;
3192 }
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003193 // Make segments writable to allow text relocations to work properly. We will later call
Dmitriy Ivanov7e039932015-10-01 14:02:19 -07003194 // phdr_table_protect_segments() after all of them are applied.
Dimitry Ivanov816676e2016-10-19 11:00:28 -07003195 DL_WARN("\"%s\" has text relocations. This is wasting memory and prevents "
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003196 "security hardening. Please fix.", get_realpath());
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07003197 add_dlwarning(get_realpath(), "text relocations");
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003198 if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
3199 DL_ERR("can't unprotect loadable segments for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003200 get_realpath(), strerror(errno));
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003201 return false;
3202 }
3203 }
3204#endif
3205
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003206 if (android_relocs_ != nullptr) {
3207 // check signature
3208 if (android_relocs_size_ > 3 &&
3209 android_relocs_[0] == 'A' &&
3210 android_relocs_[1] == 'P' &&
Dmitriy Ivanov18870d32015-04-22 13:10:04 -07003211 android_relocs_[2] == 'S' &&
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003212 android_relocs_[3] == '2') {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003213 DEBUG("[ android relocating %s ]", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003214
3215 bool relocated = false;
3216 const uint8_t* packed_relocs = android_relocs_ + 4;
3217 const size_t packed_relocs_size = android_relocs_size_ - 4;
3218
Dmitriy Ivanov18870d32015-04-22 13:10:04 -07003219 relocated = relocate(
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003220 version_tracker,
Dmitriy Ivanov18870d32015-04-22 13:10:04 -07003221 packed_reloc_iterator<sleb128_decoder>(
3222 sleb128_decoder(packed_relocs, packed_relocs_size)),
3223 global_group, local_group);
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003224
3225 if (!relocated) {
3226 return false;
3227 }
3228 } else {
3229 DL_ERR("bad android relocation header.");
3230 return false;
3231 }
3232 }
3233
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07003234#if defined(USE_RELA)
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003235 if (rela_ != nullptr) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003236 DEBUG("[ relocating %s ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003237 if (!relocate(version_tracker,
3238 plain_reloc_iterator(rela_, rela_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003239 return false;
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07003240 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003241 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003242 if (plt_rela_ != nullptr) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003243 DEBUG("[ relocating %s plt ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003244 if (!relocate(version_tracker,
3245 plain_reloc_iterator(plt_rela_, plt_rela_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003246 return false;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003247 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003248 }
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07003249#else
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003250 if (rel_ != nullptr) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003251 DEBUG("[ relocating %s ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003252 if (!relocate(version_tracker,
3253 plain_reloc_iterator(rel_, rel_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003254 return false;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003255 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003256 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003257 if (plt_rel_ != nullptr) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003258 DEBUG("[ relocating %s plt ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003259 if (!relocate(version_tracker,
3260 plain_reloc_iterator(plt_rel_, plt_rel_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003261 return false;
Brigid Smithc5a13ef2014-07-23 11:22:25 -07003262 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003263 }
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07003264#endif
Brigid Smithc5a13ef2014-07-23 11:22:25 -07003265
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07003266#if defined(__mips__)
Dmitriy Ivanovf39cb632015-04-30 20:17:03 -07003267 if (!mips_relocate_got(version_tracker, global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003268 return false;
3269 }
Raghu Gandhamd7daacb2012-07-31 12:07:22 -07003270#endif
3271
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003272 DEBUG("[ finished linking %s ]", get_realpath());
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003273
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003274#if !defined(__LP64__)
3275 if (has_text_relocations) {
3276 // All relocations are done, we can protect our segments back to read-only.
3277 if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
3278 DL_ERR("can't protect segments for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003279 get_realpath(), strerror(errno));
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003280 return false;
3281 }
3282 }
3283#endif
3284
Mingwei Shibe910522015-11-12 07:02:14 +00003285 // We can also turn on GNU RELRO protection if we're not linking the dynamic linker
3286 // itself --- it can't make system calls yet, and will have to call protect_relro later.
3287 if (!is_linker() && !protect_relro()) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003288 return false;
3289 }
Nick Kralevich9ec0f032012-02-28 10:40:00 -08003290
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003291 /* Handle serializing/sharing the RELRO segment */
3292 if (extinfo && (extinfo->flags & ANDROID_DLEXT_WRITE_RELRO)) {
3293 if (phdr_table_serialize_gnu_relro(phdr, phnum, load_bias,
3294 extinfo->relro_fd) < 0) {
3295 DL_ERR("failed serializing GNU RELRO section for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003296 get_realpath(), strerror(errno));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003297 return false;
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +00003298 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003299 } else if (extinfo && (extinfo->flags & ANDROID_DLEXT_USE_RELRO)) {
3300 if (phdr_table_map_gnu_relro(phdr, phnum, load_bias,
3301 extinfo->relro_fd) < 0) {
3302 DL_ERR("failed mapping GNU RELRO section for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003303 get_realpath(), strerror(errno));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003304 return false;
3305 }
3306 }
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +00003307
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003308 notify_gdb_of_load(this);
3309 return true;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003310}
3311
Mingwei Shibe910522015-11-12 07:02:14 +00003312bool soinfo::protect_relro() {
3313 if (phdr_table_protect_gnu_relro(phdr, phnum, load_bias) < 0) {
3314 DL_ERR("can't enable GNU RELRO protection for \"%s\": %s",
3315 get_realpath(), strerror(errno));
3316 return false;
3317 }
3318 return true;
3319}
3320
Dimitry Ivanov3f660572016-09-09 10:00:39 -07003321void init_default_namespace() {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003322 g_default_namespace.set_name("(default)");
3323 g_default_namespace.set_isolated(false);
3324
Dimitry Ivanov3f660572016-09-09 10:00:39 -07003325 soinfo* somain = solist_get_somain();
3326
Evgenii Stepanovd640b222015-07-10 17:54:01 -07003327 const char *interp = phdr_table_get_interpreter_name(somain->phdr, somain->phnum,
3328 somain->load_bias);
3329 const char* bname = basename(interp);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003330 if (bname && (strcmp(bname, "linker_asan") == 0 || strcmp(bname, "linker_asan64") == 0)) {
Evgenii Stepanovd640b222015-07-10 17:54:01 -07003331 g_default_ld_paths = kAsanDefaultLdPaths;
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -07003332 g_is_asan = true;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003333 } else {
Evgenii Stepanovd640b222015-07-10 17:54:01 -07003334 g_default_ld_paths = kDefaultLdPaths;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003335 }
3336
neo.chae2589f9d2016-10-04 11:00:27 +09003337 char real_path[PATH_MAX];
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003338 std::vector<std::string> ld_default_paths;
3339 for (size_t i = 0; g_default_ld_paths[i] != nullptr; ++i) {
neo.chae2589f9d2016-10-04 11:00:27 +09003340 if (realpath(g_default_ld_paths[i], real_path) != nullptr) {
3341 ld_default_paths.push_back(real_path);
3342 } else {
3343 ld_default_paths.push_back(g_default_ld_paths[i]);
3344 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003345 }
3346
3347 g_default_namespace.set_default_library_paths(std::move(ld_default_paths));
Evgenii Stepanovd640b222015-07-10 17:54:01 -07003348};