blob: 136c2b6e8290a717b85fcbbd1729cf96daa12e13 [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 Ivanovec90e242017-02-10 11:04:20 -08001695 child->get_parents().remove(si);
1696
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001697 if (local_unload_list.contains(child)) {
1698 continue;
1699 } else if (child->is_linked() && child->get_local_group_root() != root) {
1700 external_unload_list.push_back(child);
Dimitry Ivanovec90e242017-02-10 11:04:20 -08001701 } else if (child->get_parents().empty()) {
1702 unload_list.push_back(child);
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001703 }
1704 }
1705 } else {
1706#if !defined(__work_around_b_24465209__)
1707 __libc_fatal("soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
1708#else
1709 PRINT("warning: soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
1710 for_each_dt_needed(si, [&] (const char* library_name) {
1711 TRACE("deprecated (old format of soinfo): %s needs to unload %s",
1712 si->get_realpath(), library_name);
1713
1714 soinfo* needed = find_library(si->get_primary_namespace(),
1715 library_name, RTLD_NOLOAD, nullptr, nullptr);
1716
1717 if (needed != nullptr) {
1718 // Not found: for example if symlink was deleted between dlopen and dlclose
1719 // Since we cannot really handle errors at this point - print and continue.
1720 PRINT("warning: couldn't find %s needed by %s on unload.",
1721 library_name, si->get_realpath());
1722 return;
1723 } else if (local_unload_list.contains(needed)) {
1724 // already visited
1725 return;
1726 } else if (needed->is_linked() && needed->get_local_group_root() != root) {
1727 // external group
1728 external_unload_list.push_back(needed);
1729 } else {
1730 // local group
1731 unload_list.push_front(needed);
1732 }
1733 });
1734#endif
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001735 }
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001736 }
1737
1738 local_unload_list.for_each([](soinfo* si) {
1739 si->call_destructors();
1740 });
1741
1742 while ((si = local_unload_list.pop_front()) != nullptr) {
1743 notify_gdb_of_unload(si);
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -07001744 get_cfi_shadow()->BeforeUnload(si);
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001745 soinfo_free(si);
1746 }
1747
1748 while ((si = external_unload_list.pop_front()) != nullptr) {
1749 soinfo_unload(si);
Dmitriy Ivanova2547052014-11-18 12:03:09 -08001750 }
1751}
1752
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001753static std::string symbol_display_name(const char* sym_name, const char* sym_ver) {
1754 if (sym_ver == nullptr) {
1755 return sym_name;
1756 }
1757
Dimitry Ivanov9cf99cb2015-12-11 14:22:24 -08001758 return std::string(sym_name) + ", version " + sym_ver;
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001759}
1760
Dimitry Ivanovaca299a2016-04-11 12:42:58 -07001761static android_namespace_t* get_caller_namespace(soinfo* caller) {
1762 return caller != nullptr ? caller->get_primary_namespace() : g_anonymous_namespace;
1763}
1764
Elliott Hughesa4aafd12014-01-13 16:37:47 -08001765void do_android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size) {
Christopher Ferris052fa3a2014-08-26 20:48:11 -07001766 // Use basic string manipulation calls to avoid snprintf.
1767 // snprintf indirectly calls pthread_getspecific to get the size of a buffer.
1768 // When debug malloc is enabled, this call returns 0. This in turn causes
1769 // snprintf to do nothing, which causes libraries to fail to load.
1770 // See b/17302493 for further details.
1771 // Once the above bug is fixed, this code can be modified to use
1772 // snprintf again.
Evgenii Stepanovd640b222015-07-10 17:54:01 -07001773 size_t required_len = 0;
1774 for (size_t i = 0; g_default_ld_paths[i] != nullptr; ++i) {
1775 required_len += strlen(g_default_ld_paths[i]) + 1;
1776 }
Christopher Ferris052fa3a2014-08-26 20:48:11 -07001777 if (buffer_size < required_len) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07001778 __libc_fatal("android_get_LD_LIBRARY_PATH failed, buffer too small: "
1779 "buffer len %zu, required len %zu", buffer_size, required_len);
Christopher Ferris052fa3a2014-08-26 20:48:11 -07001780 }
Evgenii Stepanovd640b222015-07-10 17:54:01 -07001781 char* end = buffer;
1782 for (size_t i = 0; g_default_ld_paths[i] != nullptr; ++i) {
1783 if (i > 0) *end++ = ':';
1784 end = stpcpy(end, g_default_ld_paths[i]);
1785 }
Elliott Hughesa4aafd12014-01-13 16:37:47 -08001786}
1787
Elliott Hughescade4c32012-12-20 14:42:14 -08001788void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path) {
Nick Kralevich6bb01b62015-03-07 13:37:05 -08001789 parse_LD_LIBRARY_PATH(ld_library_path);
Elliott Hughescade4c32012-12-20 14:42:14 -08001790}
1791
Dimitry Ivanovb996d602016-07-11 18:11:39 -07001792static std::string android_dlextinfo_to_string(const android_dlextinfo* info) {
1793 if (info == nullptr) {
1794 return "(null)";
1795 }
1796
1797 return android::base::StringPrintf("[flags=0x%" PRIx64 ","
1798 " reserved_addr=%p,"
1799 " reserved_size=0x%zx,"
1800 " relro_fd=%d,"
1801 " library_fd=%d,"
1802 " library_fd_offset=0x%" PRIx64 ","
1803 " library_namespace=%s@%p]",
1804 info->flags,
1805 info->reserved_addr,
1806 info->reserved_size,
1807 info->relro_fd,
1808 info->library_fd,
1809 info->library_fd_offset,
1810 (info->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0 ?
1811 (info->library_namespace != nullptr ?
1812 info->library_namespace->get_name() : "(null)") : "(n/a)",
1813 (info->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0 ?
1814 info->library_namespace : nullptr);
1815}
1816
Dimitry Ivanovd9e427c2016-11-22 16:55:25 -08001817void* do_dlopen(const char* name, int flags,
1818 const android_dlextinfo* extinfo,
1819 const void* caller_addr) {
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001820 soinfo* const caller = find_containing_library(caller_addr);
Dimitry Ivanovb996d602016-07-11 18:11:39 -07001821 android_namespace_t* ns = get_caller_namespace(caller);
1822
1823 LD_LOG(kLogDlopen,
1824 "dlopen(name=\"%s\", flags=0x%x, extinfo=%s, caller=\"%s\", caller_ns=%s@%p) ...",
1825 name,
1826 flags,
1827 android_dlextinfo_to_string(extinfo).c_str(),
1828 caller == nullptr ? "(null)" : caller->get_realpath(),
1829 ns == nullptr ? "(null)" : ns->get_name(),
1830 ns);
1831
1832 auto failure_guard = make_scope_guard([&]() {
1833 LD_LOG(kLogDlopen, "... dlopen failed: %s", linker_get_error_buffer());
1834 });
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001835
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -07001836 if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL|RTLD_NODELETE|RTLD_NOLOAD)) != 0) {
Elliott Hughese66190d2012-12-18 15:57:55 -08001837 DL_ERR("invalid flags to dlopen: %x", flags);
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07001838 return nullptr;
Elliott Hughese66190d2012-12-18 15:57:55 -08001839 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001840
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001841 if (extinfo != nullptr) {
1842 if ((extinfo->flags & ~(ANDROID_DLEXT_VALID_FLAG_BITS)) != 0) {
1843 DL_ERR("invalid extended flags to android_dlopen_ext: 0x%" PRIx64, extinfo->flags);
1844 return nullptr;
1845 }
Dmitriy Ivanov126af752015-10-07 16:34:20 -07001846
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001847 if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) == 0 &&
Dmitriy Ivanova6c12792014-10-21 12:09:18 -07001848 (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07001849 DL_ERR("invalid extended flag combination (ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET without "
1850 "ANDROID_DLEXT_USE_LIBRARY_FD): 0x%" PRIx64, extinfo->flags);
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001851 return nullptr;
1852 }
Dmitriy Ivanov126af752015-10-07 16:34:20 -07001853
1854 if ((extinfo->flags & ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS) != 0 &&
1855 (extinfo->flags & (ANDROID_DLEXT_RESERVED_ADDRESS | ANDROID_DLEXT_RESERVED_ADDRESS_HINT)) != 0) {
1856 DL_ERR("invalid extended flag combination: ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS is not "
1857 "compatible with ANDROID_DLEXT_RESERVED_ADDRESS/ANDROID_DLEXT_RESERVED_ADDRESS_HINT");
1858 return nullptr;
1859 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001860
1861 if ((extinfo->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0) {
1862 if (extinfo->library_namespace == nullptr) {
1863 DL_ERR("ANDROID_DLEXT_USE_NAMESPACE is set but extinfo->library_namespace is null");
1864 return nullptr;
1865 }
1866 ns = extinfo->library_namespace;
1867 }
Torne (Richard Coles)012cb452014-02-06 14:34:21 +00001868 }
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -08001869
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -07001870 std::string asan_name_holder;
1871
1872 const char* translated_name = name;
Dimitry Ivanov6c14f862016-12-05 13:35:47 -08001873 if (g_is_asan && translated_name != nullptr && translated_name[0] == '/') {
1874 char translated_path[PATH_MAX];
1875 if (realpath(translated_name, translated_path) != nullptr) {
1876 if (file_is_in_dir(translated_path, kSystemLibDir)) {
1877 asan_name_holder = std::string(kAsanSystemLibDir) + "/" + basename(translated_path);
1878 if (file_exists(asan_name_holder.c_str())) {
1879 translated_name = asan_name_holder.c_str();
1880 PRINT("linker_asan dlopen translating \"%s\" -> \"%s\"", name, translated_name);
1881 }
1882 } else if (file_is_in_dir(translated_path, kVendorLibDir)) {
1883 asan_name_holder = std::string(kAsanVendorLibDir) + "/" + basename(translated_path);
1884 if (file_exists(asan_name_holder.c_str())) {
1885 translated_name = asan_name_holder.c_str();
1886 PRINT("linker_asan dlopen translating \"%s\" -> \"%s\"", name, translated_name);
1887 }
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -07001888 }
1889 }
1890 }
1891
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -08001892 ProtectedDataGuard guard;
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -07001893 soinfo* si = find_library(ns, translated_name, flags, extinfo, caller);
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07001894 if (si != nullptr) {
Dimitry Ivanovb996d602016-07-11 18:11:39 -07001895 void* handle = si->to_handle();
1896 LD_LOG(kLogDlopen,
Dimitry Ivanovae4a0c12016-11-21 10:44:35 -08001897 "... dlopen calling constructors: realpath=\"%s\", soname=\"%s\", handle=%p",
1898 si->get_realpath(), si->get_soname(), handle);
1899 si->call_constructors();
1900 failure_guard.disable();
1901 LD_LOG(kLogDlopen,
Dimitry Ivanovb996d602016-07-11 18:11:39 -07001902 "... dlopen successful: realpath=\"%s\", soname=\"%s\", handle=%p",
1903 si->get_realpath(), si->get_soname(), handle);
1904 return handle;
Elliott Hughesd23736e2012-11-01 15:16:56 -07001905 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001906
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001907 return nullptr;
Elliott Hughesd23736e2012-11-01 15:16:56 -07001908}
1909
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001910int do_dladdr(const void* addr, Dl_info* info) {
1911 // Determine if this address can be found in any library currently mapped.
1912 soinfo* si = find_containing_library(addr);
1913 if (si == nullptr) {
1914 return 0;
1915 }
1916
1917 memset(info, 0, sizeof(Dl_info));
1918
1919 info->dli_fname = si->get_realpath();
1920 // Address at which the shared object is loaded.
1921 info->dli_fbase = reinterpret_cast<void*>(si->base);
1922
1923 // Determine if any symbol in the library contains the specified address.
1924 ElfW(Sym)* sym = si->find_symbol_by_address(addr);
1925 if (sym != nullptr) {
1926 info->dli_sname = si->get_string(sym->st_name);
1927 info->dli_saddr = reinterpret_cast<void*>(si->resolve_symbol_address(sym));
1928 }
1929
1930 return 1;
1931}
1932
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001933static soinfo* soinfo_from_handle(void* handle) {
1934 if ((reinterpret_cast<uintptr_t>(handle) & 1) != 0) {
1935 auto it = g_soinfo_handles_map.find(reinterpret_cast<uintptr_t>(handle));
1936 if (it == g_soinfo_handles_map.end()) {
1937 return nullptr;
1938 } else {
1939 return it->second;
1940 }
1941 }
1942
1943 return static_cast<soinfo*>(handle);
1944}
1945
Dimitry Ivanovd9e427c2016-11-22 16:55:25 -08001946bool do_dlsym(void* handle,
1947 const char* sym_name,
1948 const char* sym_ver,
1949 const void* caller_addr,
1950 void** symbol) {
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001951#if !defined(__LP64__)
1952 if (handle == nullptr) {
1953 DL_ERR("dlsym failed: library handle is null");
1954 return false;
1955 }
1956#endif
1957
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001958 soinfo* found = nullptr;
1959 const ElfW(Sym)* sym = nullptr;
1960 soinfo* caller = find_containing_library(caller_addr);
Dimitry Ivanovaca299a2016-04-11 12:42:58 -07001961 android_namespace_t* ns = get_caller_namespace(caller);
Dimitry Ivanov4742abd2016-12-12 16:30:15 -08001962 soinfo* si = nullptr;
1963 if (handle != RTLD_DEFAULT && handle != RTLD_NEXT) {
1964 si = soinfo_from_handle(handle);
1965 }
1966
1967 LD_LOG(kLogDlsym,
1968 "dlsym(handle=%p(\"%s\"), sym_name=\"%s\", sym_ver=\"%s\", caller=\"%s\", caller_ns=%s@%p) ...",
1969 handle,
1970 si != nullptr ? si->get_realpath() : "n/a",
1971 sym_name,
1972 sym_ver,
1973 caller == nullptr ? "(null)" : caller->get_realpath(),
1974 ns == nullptr ? "(null)" : ns->get_name(),
1975 ns);
1976
1977 auto failure_guard = make_scope_guard([&]() {
1978 LD_LOG(kLogDlsym, "... dlsym failed: %s", linker_get_error_buffer());
1979 });
1980
1981 if (sym_name == nullptr) {
1982 DL_ERR("dlsym failed: symbol name is null");
1983 return false;
1984 }
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001985
1986 version_info vi_instance;
1987 version_info* vi = nullptr;
1988
1989 if (sym_ver != nullptr) {
Dimitry Ivanov9cf99cb2015-12-11 14:22:24 -08001990 vi_instance.name = sym_ver;
1991 vi_instance.elf_hash = calculate_elf_hash(sym_ver);
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001992 vi = &vi_instance;
1993 }
1994
1995 if (handle == RTLD_DEFAULT || handle == RTLD_NEXT) {
1996 sym = dlsym_linear_lookup(ns, sym_name, vi, &found, caller, handle);
1997 } else {
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001998 if (si == nullptr) {
1999 DL_ERR("dlsym failed: invalid handle: %p", handle);
2000 return false;
2001 }
2002 sym = dlsym_handle_lookup(si, &found, sym_name, vi);
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08002003 }
2004
2005 if (sym != nullptr) {
2006 uint32_t bind = ELF_ST_BIND(sym->st_info);
2007
2008 if ((bind == STB_GLOBAL || bind == STB_WEAK) && sym->st_shndx != 0) {
2009 *symbol = reinterpret_cast<void*>(found->resolve_symbol_address(sym));
Dimitry Ivanov4742abd2016-12-12 16:30:15 -08002010 failure_guard.disable();
2011 LD_LOG(kLogDlsym,
2012 "... dlsym successful: sym_name=\"%s\", sym_ver=\"%s\", found in=\"%s\", address=%p",
2013 sym_name, sym_ver, found->get_soname(), *symbol);
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08002014 return true;
2015 }
2016
2017 DL_ERR("symbol \"%s\" found but not global", symbol_display_name(sym_name, sym_ver).c_str());
2018 return false;
2019 }
2020
2021 DL_ERR("undefined symbol: %s", symbol_display_name(sym_name, sym_ver).c_str());
2022 return false;
2023}
2024
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07002025int do_dlclose(void* handle) {
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -08002026 ProtectedDataGuard guard;
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07002027 soinfo* si = soinfo_from_handle(handle);
2028 if (si == nullptr) {
2029 DL_ERR("invalid handle: %p", handle);
2030 return -1;
2031 }
2032
Dmitriy Ivanovb648a8a2014-05-19 15:06:58 -07002033 soinfo_unload(si);
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07002034 return 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002035}
2036
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -08002037bool init_anonymous_namespace(const char* shared_lib_sonames, const char* library_search_path) {
2038 if (g_anonymous_namespace_initialized) {
2039 DL_ERR("anonymous namespace has already been initialized.");
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002040 return false;
2041 }
2042
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002043 ProtectedDataGuard guard;
2044
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -08002045 g_anonymous_namespace_initialized = true;
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002046
2047 // create anonymous namespace
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002048 // When the caller is nullptr - create_namespace will take global group
2049 // from the anonymous namespace, which is fine because anonymous namespace
2050 // is still pointing to the default one.
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002051 android_namespace_t* anon_ns =
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -08002052 create_namespace(nullptr,
2053 "(anonymous)",
2054 nullptr,
2055 library_search_path,
2056 // TODO (dimitry): change to isolated eventually.
2057 ANDROID_NAMESPACE_TYPE_REGULAR,
2058 nullptr,
2059 &g_default_namespace);
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002060
2061 if (anon_ns == nullptr) {
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -08002062 g_anonymous_namespace_initialized = false;
2063 return false;
2064 }
2065
2066 if (!link_namespaces(anon_ns, &g_default_namespace, shared_lib_sonames)) {
2067 g_anonymous_namespace_initialized = false;
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002068 return false;
2069 }
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08002070
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002071 g_anonymous_namespace = anon_ns;
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -08002072
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002073 return true;
2074}
2075
Dimitry Ivanovb943f302016-08-03 16:00:10 -07002076static void add_soinfos_to_namespace(const soinfo_list_t& soinfos, android_namespace_t* ns) {
2077 ns->add_soinfos(soinfos);
2078 for (auto si : soinfos) {
2079 si->add_secondary_namespace(ns);
2080 }
2081}
2082
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002083android_namespace_t* create_namespace(const void* caller_addr,
2084 const char* name,
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002085 const char* ld_library_path,
2086 const char* default_library_path,
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002087 uint64_t type,
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002088 const char* permitted_when_isolated_path,
2089 android_namespace_t* parent_namespace) {
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -08002090 if (!g_anonymous_namespace_initialized) {
2091 DL_ERR("cannot create namespace: anonymous namespace is not initialized.");
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002092 return nullptr;
2093 }
2094
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002095 if (parent_namespace == nullptr) {
Dimitry Ivanov52408632016-05-23 10:31:11 -07002096 // if parent_namespace is nullptr -> set it to the caller namespace
2097 soinfo* caller_soinfo = find_containing_library(caller_addr);
2098
2099 parent_namespace = caller_soinfo != nullptr ?
2100 caller_soinfo->get_primary_namespace() :
2101 g_anonymous_namespace;
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002102 }
2103
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002104 ProtectedDataGuard guard;
2105 std::vector<std::string> ld_library_paths;
2106 std::vector<std::string> default_library_paths;
Dimitry Ivanov284ae352015-12-08 10:47:13 -08002107 std::vector<std::string> permitted_paths;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002108
2109 parse_path(ld_library_path, ":", &ld_library_paths);
2110 parse_path(default_library_path, ":", &default_library_paths);
Dimitry Ivanov284ae352015-12-08 10:47:13 -08002111 parse_path(permitted_when_isolated_path, ":", &permitted_paths);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002112
2113 android_namespace_t* ns = new (g_namespace_allocator.alloc()) android_namespace_t();
2114 ns->set_name(name);
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002115 ns->set_isolated((type & ANDROID_NAMESPACE_TYPE_ISOLATED) != 0);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002116 ns->set_ld_library_paths(std::move(ld_library_paths));
2117 ns->set_default_library_paths(std::move(default_library_paths));
Dimitry Ivanov284ae352015-12-08 10:47:13 -08002118 ns->set_permitted_paths(std::move(permitted_paths));
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002119
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002120 if ((type & ANDROID_NAMESPACE_TYPE_SHARED) != 0) {
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002121 // If shared - clone the parent namespace
Dimitry Ivanovb943f302016-08-03 16:00:10 -07002122 add_soinfos_to_namespace(parent_namespace->soinfo_list(), ns);
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002123 } else {
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002124 // If not shared - copy only the shared group
Dimitry Ivanovb943f302016-08-03 16:00:10 -07002125 add_soinfos_to_namespace(get_shared_group(parent_namespace), ns);
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002126 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002127
2128 return ns;
2129}
2130
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -08002131bool link_namespaces(android_namespace_t* namespace_from,
2132 android_namespace_t* namespace_to,
2133 const char* shared_lib_sonames) {
2134 if (namespace_to == nullptr) {
2135 namespace_to = &g_default_namespace;
2136 }
2137
2138 if (namespace_from == nullptr) {
2139 DL_ERR("error linking namespaces: namespace_from is null.");
2140 return false;
2141 }
2142
2143 if (shared_lib_sonames == nullptr || shared_lib_sonames[0] == '\0') {
2144 DL_ERR("error linking namespaces \"%s\"->\"%s\": the list of shared libraries is empty.",
2145 namespace_from->get_name(), namespace_to->get_name());
2146 return false;
2147 }
2148
2149 auto sonames = android::base::Split(shared_lib_sonames, ":");
2150 std::unordered_set<std::string> sonames_set(sonames.begin(), sonames.end());
2151
2152 ProtectedDataGuard guard;
2153 namespace_from->add_linked_namespace(namespace_to, sonames_set);
2154
2155 return true;
2156}
2157
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002158ElfW(Addr) call_ifunc_resolver(ElfW(Addr) resolver_addr) {
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07002159 typedef ElfW(Addr) (*ifunc_resolver_t)(void);
2160 ifunc_resolver_t ifunc_resolver = reinterpret_cast<ifunc_resolver_t>(resolver_addr);
2161 ElfW(Addr) ifunc_addr = ifunc_resolver();
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002162 TRACE_TYPE(RELO, "Called ifunc_resolver@%p. The result is %p",
2163 ifunc_resolver, reinterpret_cast<void*>(ifunc_addr));
Brigid Smithc5a13ef2014-07-23 11:22:25 -07002164
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07002165 return ifunc_addr;
Brigid Smithc5a13ef2014-07-23 11:22:25 -07002166}
Brigid Smithc5a13ef2014-07-23 11:22:25 -07002167
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002168const version_info* VersionTracker::get_version_info(ElfW(Versym) source_symver) const {
2169 if (source_symver < 2 ||
2170 source_symver >= version_infos.size() ||
2171 version_infos[source_symver].name == nullptr) {
2172 return nullptr;
2173 }
2174
2175 return &version_infos[source_symver];
2176}
2177
2178void VersionTracker::add_version_info(size_t source_index,
2179 ElfW(Word) elf_hash,
2180 const char* ver_name,
2181 const soinfo* target_si) {
2182 if (source_index >= version_infos.size()) {
2183 version_infos.resize(source_index+1);
2184 }
2185
2186 version_infos[source_index].elf_hash = elf_hash;
2187 version_infos[source_index].name = ver_name;
2188 version_infos[source_index].target_si = target_si;
2189}
2190
2191bool VersionTracker::init_verneed(const soinfo* si_from) {
2192 uintptr_t verneed_ptr = si_from->get_verneed_ptr();
2193
2194 if (verneed_ptr == 0) {
2195 return true;
2196 }
2197
2198 size_t verneed_cnt = si_from->get_verneed_cnt();
2199
2200 for (size_t i = 0, offset = 0; i<verneed_cnt; ++i) {
2201 const ElfW(Verneed)* verneed = reinterpret_cast<ElfW(Verneed)*>(verneed_ptr + offset);
2202 size_t vernaux_offset = offset + verneed->vn_aux;
2203 offset += verneed->vn_next;
2204
2205 if (verneed->vn_version != 1) {
2206 DL_ERR("unsupported verneed[%zd] vn_version: %d (expected 1)", i, verneed->vn_version);
2207 return false;
2208 }
2209
2210 const char* target_soname = si_from->get_string(verneed->vn_file);
2211 // find it in dependencies
2212 soinfo* target_si = si_from->get_children().find_if([&](const soinfo* si) {
Dmitriy Ivanov406d9962015-05-06 11:05:27 -07002213 return si->get_soname() != nullptr && strcmp(si->get_soname(), target_soname) == 0;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002214 });
2215
2216 if (target_si == nullptr) {
2217 DL_ERR("cannot find \"%s\" from verneed[%zd] in DT_NEEDED list for \"%s\"",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002218 target_soname, i, si_from->get_realpath());
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002219 return false;
2220 }
2221
2222 for (size_t j = 0; j<verneed->vn_cnt; ++j) {
2223 const ElfW(Vernaux)* vernaux = reinterpret_cast<ElfW(Vernaux)*>(verneed_ptr + vernaux_offset);
2224 vernaux_offset += vernaux->vna_next;
2225
2226 const ElfW(Word) elf_hash = vernaux->vna_hash;
2227 const char* ver_name = si_from->get_string(vernaux->vna_name);
2228 ElfW(Half) source_index = vernaux->vna_other;
2229
2230 add_version_info(source_index, elf_hash, ver_name, target_si);
2231 }
2232 }
2233
2234 return true;
2235}
2236
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002237template <typename F>
2238static bool for_each_verdef(const soinfo* si, F functor) {
2239 if (!si->has_min_version(2)) {
2240 return true;
2241 }
2242
2243 uintptr_t verdef_ptr = si->get_verdef_ptr();
2244 if (verdef_ptr == 0) {
2245 return true;
2246 }
2247
2248 size_t offset = 0;
2249
2250 size_t verdef_cnt = si->get_verdef_cnt();
2251 for (size_t i = 0; i<verdef_cnt; ++i) {
2252 const ElfW(Verdef)* verdef = reinterpret_cast<ElfW(Verdef)*>(verdef_ptr + offset);
2253 size_t verdaux_offset = offset + verdef->vd_aux;
2254 offset += verdef->vd_next;
2255
2256 if (verdef->vd_version != 1) {
2257 DL_ERR("unsupported verdef[%zd] vd_version: %d (expected 1) library: %s",
2258 i, verdef->vd_version, si->get_realpath());
2259 return false;
2260 }
2261
2262 if ((verdef->vd_flags & VER_FLG_BASE) != 0) {
2263 // "this is the version of the file itself. It must not be used for
2264 // matching a symbol. It can be used to match references."
2265 //
2266 // http://www.akkadia.org/drepper/symbol-versioning
2267 continue;
2268 }
2269
2270 if (verdef->vd_cnt == 0) {
2271 DL_ERR("invalid verdef[%zd] vd_cnt == 0 (version without a name)", i);
2272 return false;
2273 }
2274
2275 const ElfW(Verdaux)* verdaux = reinterpret_cast<ElfW(Verdaux)*>(verdef_ptr + verdaux_offset);
2276
2277 if (functor(i, verdef, verdaux) == true) {
2278 break;
2279 }
2280 }
2281
2282 return true;
2283}
2284
2285bool find_verdef_version_index(const soinfo* si, const version_info* vi, ElfW(Versym)* versym) {
2286 if (vi == nullptr) {
2287 *versym = kVersymNotNeeded;
2288 return true;
2289 }
2290
2291 *versym = kVersymGlobal;
2292
2293 return for_each_verdef(si,
2294 [&](size_t, const ElfW(Verdef)* verdef, const ElfW(Verdaux)* verdaux) {
2295 if (verdef->vd_hash == vi->elf_hash &&
2296 strcmp(vi->name, si->get_string(verdaux->vda_name)) == 0) {
2297 *versym = verdef->vd_ndx;
2298 return true;
2299 }
2300
2301 return false;
2302 }
2303 );
2304}
2305
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002306bool VersionTracker::init_verdef(const soinfo* si_from) {
2307 return for_each_verdef(si_from,
2308 [&](size_t, const ElfW(Verdef)* verdef, const ElfW(Verdaux)* verdaux) {
2309 add_version_info(verdef->vd_ndx, verdef->vd_hash,
2310 si_from->get_string(verdaux->vda_name), si_from);
2311 return false;
2312 }
2313 );
2314}
2315
2316bool VersionTracker::init(const soinfo* si_from) {
2317 if (!si_from->has_min_version(2)) {
2318 return true;
2319 }
2320
2321 return init_verneed(si_from) && init_verdef(si_from);
2322}
2323
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002324// TODO (dimitry): Methods below need to be moved out of soinfo
2325// and in more isolated file in order minimize dependencies on
2326// unnecessary object in the linker binary. Consider making them
2327// independent from soinfo (?).
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002328bool soinfo::lookup_version_info(const VersionTracker& version_tracker, ElfW(Word) sym,
2329 const char* sym_name, const version_info** vi) {
2330 const ElfW(Versym)* sym_ver_ptr = get_versym(sym);
2331 ElfW(Versym) sym_ver = sym_ver_ptr == nullptr ? 0 : *sym_ver_ptr;
2332
2333 if (sym_ver != VER_NDX_LOCAL && sym_ver != VER_NDX_GLOBAL) {
2334 *vi = version_tracker.get_version_info(sym_ver);
2335
2336 if (*vi == nullptr) {
2337 DL_ERR("cannot find verneed/verdef for version index=%d "
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002338 "referenced by symbol \"%s\" at \"%s\"", sym_ver, sym_name, get_realpath());
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002339 return false;
2340 }
2341 } else {
2342 // there is no version info
2343 *vi = nullptr;
2344 }
2345
2346 return true;
2347}
2348
Dimitry Ivanov576a3752016-08-09 06:58:55 -07002349#if !defined(__mips__)
2350#if defined(USE_RELA)
2351static ElfW(Addr) get_addend(ElfW(Rela)* rela, ElfW(Addr) reloc_addr __unused) {
2352 return rela->r_addend;
2353}
2354#else
2355static ElfW(Addr) get_addend(ElfW(Rel)* rel, ElfW(Addr) reloc_addr) {
2356 if (ELFW(R_TYPE)(rel->r_info) == R_GENERIC_RELATIVE ||
2357 ELFW(R_TYPE)(rel->r_info) == R_GENERIC_IRELATIVE) {
2358 return *reinterpret_cast<ElfW(Addr)*>(reloc_addr);
2359 }
2360 return 0;
2361}
2362#endif
2363
Dmitriy Ivanovfa26eee2015-02-03 16:06:47 -08002364template<typename ElfRelIteratorT>
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07002365bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& rel_iterator,
2366 const soinfo_list_t& global_group, const soinfo_list_t& local_group) {
Dmitriy Ivanovfa26eee2015-02-03 16:06:47 -08002367 for (size_t idx = 0; rel_iterator.has_next(); ++idx) {
2368 const auto rel = rel_iterator.next();
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002369 if (rel == nullptr) {
2370 return false;
2371 }
2372
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002373 ElfW(Word) type = ELFW(R_TYPE)(rel->r_info);
2374 ElfW(Word) sym = ELFW(R_SYM)(rel->r_info);
2375
2376 ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rel->r_offset + load_bias);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002377 ElfW(Addr) sym_addr = 0;
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07002378 const char* sym_name = nullptr;
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002379 ElfW(Addr) addend = get_addend(rel, reloc);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002380
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07002381 DEBUG("Processing \"%s\" relocation at index %zd", get_realpath(), idx);
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002382 if (type == R_GENERIC_NONE) {
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002383 continue;
2384 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002385
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002386 const ElfW(Sym)* s = nullptr;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002387 soinfo* lsi = nullptr;
2388
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002389 if (sym != 0) {
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002390 sym_name = get_string(symtab_[sym].st_name);
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002391 const version_info* vi = nullptr;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002392
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002393 if (!lookup_version_info(version_tracker, sym, sym_name, &vi)) {
2394 return false;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002395 }
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002396
2397 if (!soinfo_do_lookup(this, sym_name, vi, &lsi, global_group, local_group, &s)) {
2398 return false;
2399 }
2400
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07002401 if (s == nullptr) {
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002402 // We only allow an undefined symbol if this is a weak reference...
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002403 s = &symtab_[sym];
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002404 if (ELF_ST_BIND(s->st_info) != STB_WEAK) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002405 DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, get_realpath());
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002406 return false;
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002407 }
2408
2409 /* IHI0044C AAELF 4.5.1.1:
2410
2411 Libraries are not searched to resolve weak references.
2412 It is not an error for a weak reference to remain unsatisfied.
2413
2414 During linking, the value of an undefined weak reference is:
2415 - Zero if the relocation type is absolute
2416 - The address of the place if the relocation is pc-relative
2417 - The address of nominal base address if the relocation
2418 type is base-relative.
2419 */
2420
2421 switch (type) {
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002422 case R_GENERIC_JUMP_SLOT:
2423 case R_GENERIC_GLOB_DAT:
2424 case R_GENERIC_RELATIVE:
2425 case R_GENERIC_IRELATIVE:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002426#if defined(__aarch64__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002427 case R_AARCH64_ABS64:
2428 case R_AARCH64_ABS32:
2429 case R_AARCH64_ABS16:
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002430#elif defined(__x86_64__)
2431 case R_X86_64_32:
2432 case R_X86_64_64:
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002433#elif defined(__arm__)
2434 case R_ARM_ABS32:
2435#elif defined(__i386__)
2436 case R_386_32:
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002437#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002438 /*
2439 * The sym_addr was initialized to be zero above, or the relocation
2440 * code below does not care about value of sym_addr.
2441 * No need to do anything.
2442 */
2443 break;
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002444#if defined(__x86_64__)
Dimitry Ivanovd338aac2015-01-13 22:31:54 +00002445 case R_X86_64_PC32:
2446 sym_addr = reloc;
2447 break;
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002448#elif defined(__i386__)
2449 case R_386_PC32:
2450 sym_addr = reloc;
2451 break;
2452#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002453 default:
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002454 DL_ERR("unknown weak reloc type %d @ %p (%zu)", type, rel, idx);
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002455 return false;
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002456 }
Dmitriy Ivanovec83a612015-07-26 07:37:09 -07002457 } else { // We got a definition.
2458#if !defined(__LP64__)
2459 // When relocating dso with text_relocation .text segment is
2460 // not executable. We need to restore elf flags before resolving
2461 // STT_GNU_IFUNC symbol.
2462 bool protect_segments = has_text_relocations &&
2463 lsi == this &&
2464 ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC;
2465 if (protect_segments) {
2466 if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
2467 DL_ERR("can't protect segments for \"%s\": %s",
2468 get_realpath(), strerror(errno));
2469 return false;
2470 }
2471 }
2472#endif
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07002473 sym_addr = lsi->resolve_symbol_address(s);
Dmitriy Ivanovec83a612015-07-26 07:37:09 -07002474#if !defined(__LP64__)
2475 if (protect_segments) {
2476 if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
2477 DL_ERR("can't unprotect loadable segments for \"%s\": %s",
2478 get_realpath(), strerror(errno));
2479 return false;
2480 }
2481 }
2482#endif
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002483 }
2484 count_relocation(kRelocSymbol);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002485 }
2486
2487 switch (type) {
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002488 case R_GENERIC_JUMP_SLOT:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002489 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002490 MARK(rel->r_offset);
2491 TRACE_TYPE(RELO, "RELO JMP_SLOT %16p <- %16p %s\n",
2492 reinterpret_cast<void*>(reloc),
2493 reinterpret_cast<void*>(sym_addr + addend), sym_name);
2494
2495 *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002496 break;
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002497 case R_GENERIC_GLOB_DAT:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002498 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002499 MARK(rel->r_offset);
2500 TRACE_TYPE(RELO, "RELO GLOB_DAT %16p <- %16p %s\n",
2501 reinterpret_cast<void*>(reloc),
2502 reinterpret_cast<void*>(sym_addr + addend), sym_name);
2503 *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002504 break;
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002505 case R_GENERIC_RELATIVE:
2506 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002507 MARK(rel->r_offset);
2508 TRACE_TYPE(RELO, "RELO RELATIVE %16p <- %16p\n",
2509 reinterpret_cast<void*>(reloc),
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002510 reinterpret_cast<void*>(load_bias + addend));
2511 *reinterpret_cast<ElfW(Addr)*>(reloc) = (load_bias + addend);
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002512 break;
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002513 case R_GENERIC_IRELATIVE:
2514 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002515 MARK(rel->r_offset);
2516 TRACE_TYPE(RELO, "RELO IRELATIVE %16p <- %16p\n",
2517 reinterpret_cast<void*>(reloc),
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002518 reinterpret_cast<void*>(load_bias + addend));
Dmitriy Ivanovec83a612015-07-26 07:37:09 -07002519 {
2520#if !defined(__LP64__)
2521 // When relocating dso with text_relocation .text segment is
2522 // not executable. We need to restore elf flags for this
2523 // particular call.
2524 if (has_text_relocations) {
2525 if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
2526 DL_ERR("can't protect segments for \"%s\": %s",
2527 get_realpath(), strerror(errno));
2528 return false;
2529 }
2530 }
2531#endif
2532 ElfW(Addr) ifunc_addr = call_ifunc_resolver(load_bias + addend);
2533#if !defined(__LP64__)
2534 // Unprotect it afterwards...
2535 if (has_text_relocations) {
2536 if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
2537 DL_ERR("can't unprotect loadable segments for \"%s\": %s",
2538 get_realpath(), strerror(errno));
2539 return false;
2540 }
2541 }
2542#endif
2543 *reinterpret_cast<ElfW(Addr)*>(reloc) = ifunc_addr;
2544 }
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002545 break;
2546
2547#if defined(__aarch64__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002548 case R_AARCH64_ABS64:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002549 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002550 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002551 TRACE_TYPE(RELO, "RELO ABS64 %16llx <- %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002552 reloc, sym_addr + addend, sym_name);
2553 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend;
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002554 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002555 case R_AARCH64_ABS32:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002556 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002557 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002558 TRACE_TYPE(RELO, "RELO ABS32 %16llx <- %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002559 reloc, sym_addr + addend, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002560 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002561 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT32_MIN);
2562 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT32_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002563 if ((min_value <= (sym_addr + addend)) &&
2564 ((sym_addr + addend) <= max_value)) {
2565 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend;
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002566 } else {
2567 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002568 sym_addr + addend, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002569 return false;
2570 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002571 }
2572 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002573 case R_AARCH64_ABS16:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002574 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002575 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002576 TRACE_TYPE(RELO, "RELO ABS16 %16llx <- %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002577 reloc, sym_addr + addend, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002578 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002579 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN);
2580 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT16_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002581 if ((min_value <= (sym_addr + addend)) &&
2582 ((sym_addr + addend) <= max_value)) {
2583 *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002584 } else {
2585 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002586 sym_addr + addend, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002587 return false;
2588 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002589 }
2590 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002591 case R_AARCH64_PREL64:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002592 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002593 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002594 TRACE_TYPE(RELO, "RELO REL64 %16llx <- %16llx - %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002595 reloc, sym_addr + addend, rel->r_offset, sym_name);
2596 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset;
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002597 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002598 case R_AARCH64_PREL32:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002599 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002600 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002601 TRACE_TYPE(RELO, "RELO REL32 %16llx <- %16llx - %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002602 reloc, sym_addr + addend, rel->r_offset, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002603 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002604 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT32_MIN);
2605 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT32_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002606 if ((min_value <= (sym_addr + addend - rel->r_offset)) &&
2607 ((sym_addr + addend - rel->r_offset) <= max_value)) {
2608 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset;
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002609 } else {
2610 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002611 sym_addr + addend - rel->r_offset, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002612 return false;
2613 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002614 }
2615 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002616 case R_AARCH64_PREL16:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002617 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002618 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002619 TRACE_TYPE(RELO, "RELO REL16 %16llx <- %16llx - %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002620 reloc, sym_addr + addend, rel->r_offset, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002621 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002622 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN);
2623 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT16_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002624 if ((min_value <= (sym_addr + addend - rel->r_offset)) &&
2625 ((sym_addr + addend - rel->r_offset) <= max_value)) {
2626 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset;
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002627 } else {
2628 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002629 sym_addr + addend - rel->r_offset, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002630 return false;
2631 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002632 }
2633 break;
2634
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002635 case R_AARCH64_COPY:
Nick Kralevich76e289c2014-07-03 12:04:31 -07002636 /*
2637 * ET_EXEC is not supported so this should not happen.
2638 *
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002639 * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0056b/IHI0056B_aaelf64.pdf
Nick Kralevich76e289c2014-07-03 12:04:31 -07002640 *
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002641 * Section 4.6.11 "Dynamic relocations"
Nick Kralevich76e289c2014-07-03 12:04:31 -07002642 * R_AARCH64_COPY may only appear in executable objects where e_type is
2643 * set to ET_EXEC.
2644 */
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002645 DL_ERR("%s R_AARCH64_COPY relocations are not supported", get_realpath());
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002646 return false;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002647 case R_AARCH64_TLS_TPREL64:
Elliott Hughes0266ae52014-02-10 17:46:57 -08002648 TRACE_TYPE(RELO, "RELO TLS_TPREL64 *** %16llx <- %16llx - %16llx\n",
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002649 reloc, (sym_addr + addend), rel->r_offset);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002650 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002651 case R_AARCH64_TLS_DTPREL32:
Elliott Hughes0266ae52014-02-10 17:46:57 -08002652 TRACE_TYPE(RELO, "RELO TLS_DTPREL32 *** %16llx <- %16llx - %16llx\n",
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002653 reloc, (sym_addr + addend), rel->r_offset);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002654 break;
2655#elif defined(__x86_64__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002656 case R_X86_64_32:
2657 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002658 MARK(rel->r_offset);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002659 TRACE_TYPE(RELO, "RELO R_X86_64_32 %08zx <- +%08zx %s", static_cast<size_t>(reloc),
2660 static_cast<size_t>(sym_addr), sym_name);
Junichi Uekawaff35b1e2015-11-18 10:18:59 +09002661 *reinterpret_cast<Elf32_Addr*>(reloc) = sym_addr + addend;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002662 break;
2663 case R_X86_64_64:
2664 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002665 MARK(rel->r_offset);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002666 TRACE_TYPE(RELO, "RELO R_X86_64_64 %08zx <- +%08zx %s", static_cast<size_t>(reloc),
2667 static_cast<size_t>(sym_addr), sym_name);
Junichi Uekawaff35b1e2015-11-18 10:18:59 +09002668 *reinterpret_cast<Elf64_Addr*>(reloc) = sym_addr + addend;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002669 break;
2670 case R_X86_64_PC32:
2671 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002672 MARK(rel->r_offset);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002673 TRACE_TYPE(RELO, "RELO R_X86_64_PC32 %08zx <- +%08zx (%08zx - %08zx) %s",
2674 static_cast<size_t>(reloc), static_cast<size_t>(sym_addr - reloc),
2675 static_cast<size_t>(sym_addr), static_cast<size_t>(reloc), sym_name);
Junichi Uekawaff35b1e2015-11-18 10:18:59 +09002676 *reinterpret_cast<Elf32_Addr*>(reloc) = sym_addr + addend - reloc;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002677 break;
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002678#elif defined(__arm__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002679 case R_ARM_ABS32:
2680 count_relocation(kRelocAbsolute);
2681 MARK(rel->r_offset);
2682 TRACE_TYPE(RELO, "RELO ABS %08x <- %08x %s", reloc, sym_addr, sym_name);
2683 *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
2684 break;
2685 case R_ARM_REL32:
2686 count_relocation(kRelocRelative);
2687 MARK(rel->r_offset);
2688 TRACE_TYPE(RELO, "RELO REL32 %08x <- %08x - %08x %s",
2689 reloc, sym_addr, rel->r_offset, sym_name);
2690 *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr - rel->r_offset;
2691 break;
2692 case R_ARM_COPY:
2693 /*
2694 * ET_EXEC is not supported so this should not happen.
2695 *
2696 * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044d/IHI0044D_aaelf.pdf
2697 *
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002698 * Section 4.6.1.10 "Dynamic relocations"
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002699 * R_ARM_COPY may only appear in executable objects where e_type is
2700 * set to ET_EXEC.
2701 */
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002702 DL_ERR("%s R_ARM_COPY relocations are not supported", get_realpath());
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002703 return false;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002704#elif defined(__i386__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002705 case R_386_32:
2706 count_relocation(kRelocRelative);
2707 MARK(rel->r_offset);
2708 TRACE_TYPE(RELO, "RELO R_386_32 %08x <- +%08x %s", reloc, sym_addr, sym_name);
2709 *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
2710 break;
2711 case R_386_PC32:
2712 count_relocation(kRelocRelative);
2713 MARK(rel->r_offset);
2714 TRACE_TYPE(RELO, "RELO R_386_PC32 %08x <- +%08x (%08x - %08x) %s",
2715 reloc, (sym_addr - reloc), sym_addr, reloc, sym_name);
2716 *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr - reloc);
2717 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002718#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002719 default:
2720 DL_ERR("unknown reloc type %d @ %p (%zu)", type, rel, idx);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002721 return false;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002722 }
2723 }
2724 return true;
Raghu Gandhamd7daacb2012-07-31 12:07:22 -07002725}
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002726#endif // !defined(__mips__)
Raghu Gandhamd7daacb2012-07-31 12:07:22 -07002727
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002728// An empty list of soinfos
Dimitry Ivanovb943f302016-08-03 16:00:10 -07002729static soinfo_list_t g_empty_list;
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07002730
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002731bool soinfo::prelink_image() {
Ningsheng Jiane93be992014-09-16 15:22:10 +08002732 /* Extract dynamic section */
2733 ElfW(Word) dynamic_flags = 0;
2734 phdr_table_get_dynamic_section(phdr, phnum, load_bias, &dynamic, &dynamic_flags);
Dmitriy Ivanov498eb182014-09-05 14:57:59 -07002735
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002736 /* We can't log anything until the linker is relocated */
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002737 bool relocating_linker = (flags_ & FLAG_LINKER) != 0;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002738 if (!relocating_linker) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07002739 INFO("[ Linking \"%s\" ]", get_realpath());
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002740 DEBUG("si->base = %p si->flags = 0x%08x", reinterpret_cast<void*>(base), flags_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002741 }
2742
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002743 if (dynamic == nullptr) {
David 'Digit' Turnerb52e4382012-06-19 01:24:17 +02002744 if (!relocating_linker) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002745 DL_ERR("missing PT_DYNAMIC in \"%s\"", get_realpath());
David 'Digit' Turnerb52e4382012-06-19 01:24:17 +02002746 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002747 return false;
2748 } else {
2749 if (!relocating_linker) {
2750 DEBUG("dynamic = %p", dynamic);
David 'Digit' Turner63f99f42012-06-19 00:08:39 +02002751 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002752 }
David 'Digit' Turner63f99f42012-06-19 00:08:39 +02002753
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07002754#if defined(__arm__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002755 (void) phdr_table_get_arm_exidx(phdr, phnum, load_bias,
2756 &ARM_exidx, &ARM_exidx_count);
David 'Digit' Turner63f99f42012-06-19 00:08:39 +02002757#endif
2758
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002759 // Extract useful information from dynamic section.
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07002760 // Note that: "Except for the DT_NULL element at the end of the array,
2761 // and the relative order of DT_NEEDED elements, entries may appear in any order."
2762 //
2763 // source: http://www.sco.com/developers/gabi/1998-04-29/ch5.dynamic.html
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002764 uint32_t needed_count = 0;
2765 for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
2766 DEBUG("d = %p, d[0](tag) = %p d[1](val) = %p",
2767 d, reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
2768 switch (d->d_tag) {
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002769 case DT_SONAME:
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07002770 // this is parsed after we have strtab initialized (see below).
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002771 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002772
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002773 case DT_HASH:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002774 nbucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0];
2775 nchain_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
2776 bucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8);
2777 chain_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8 + nbucket_ * 4);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002778 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002779
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002780 case DT_GNU_HASH:
Dmitriy Ivanov3597b802015-03-09 12:02:02 -07002781 gnu_nbucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0];
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002782 // skip symndx
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002783 gnu_maskwords_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[2];
2784 gnu_shift2_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[3];
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002785
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002786 gnu_bloom_filter_ = reinterpret_cast<ElfW(Addr)*>(load_bias + d->d_un.d_ptr + 16);
Dmitriy Ivanov3597b802015-03-09 12:02:02 -07002787 gnu_bucket_ = reinterpret_cast<uint32_t*>(gnu_bloom_filter_ + gnu_maskwords_);
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002788 // amend chain for symndx = header[1]
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002789 gnu_chain_ = gnu_bucket_ + gnu_nbucket_ -
2790 reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002791
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002792 if (!powerof2(gnu_maskwords_)) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002793 DL_ERR("invalid maskwords for gnu_hash = 0x%x, in \"%s\" expecting power to two",
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002794 gnu_maskwords_, get_realpath());
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002795 return false;
2796 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002797 --gnu_maskwords_;
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002798
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002799 flags_ |= FLAG_GNU_HASH;
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002800 break;
2801
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002802 case DT_STRTAB:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002803 strtab_ = reinterpret_cast<const char*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002804 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002805
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07002806 case DT_STRSZ:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002807 strtab_size_ = d->d_un.d_val;
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07002808 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002809
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002810 case DT_SYMTAB:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002811 symtab_ = reinterpret_cast<ElfW(Sym)*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002812 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002813
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002814 case DT_SYMENT:
2815 if (d->d_un.d_val != sizeof(ElfW(Sym))) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002816 DL_ERR("invalid DT_SYMENT: %zd in \"%s\"",
2817 static_cast<size_t>(d->d_un.d_val), get_realpath());
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002818 return false;
2819 }
2820 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002821
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002822 case DT_PLTREL:
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002823#if defined(USE_RELA)
2824 if (d->d_un.d_val != DT_RELA) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002825 DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_RELA", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002826 return false;
2827 }
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002828#else
2829 if (d->d_un.d_val != DT_REL) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002830 DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_REL", get_realpath());
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002831 return false;
2832 }
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002833#endif
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002834 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002835
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002836 case DT_JMPREL:
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07002837#if defined(USE_RELA)
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002838 plt_rela_ = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002839#else
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002840 plt_rel_ = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002841#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002842 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002843
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002844 case DT_PLTRELSZ:
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07002845#if defined(USE_RELA)
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002846 plt_rela_count_ = d->d_un.d_val / sizeof(ElfW(Rela));
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002847#else
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002848 plt_rel_count_ = d->d_un.d_val / sizeof(ElfW(Rel));
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002849#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002850 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002851
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002852 case DT_PLTGOT:
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002853#if defined(__mips__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002854 // Used by mips and mips64.
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002855 plt_got_ = reinterpret_cast<ElfW(Addr)**>(load_bias + d->d_un.d_ptr);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002856#endif
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002857 // Ignore for other platforms... (because RTLD_LAZY is not supported)
2858 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002859
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002860 case DT_DEBUG:
2861 // Set the DT_DEBUG entry to the address of _r_debug for GDB
2862 // if the dynamic table is writable
Chris Dearman99186652014-02-06 20:36:51 -08002863// FIXME: not working currently for N64
2864// The flags for the LOAD and DYNAMIC program headers do not agree.
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002865// The LOAD section containing the dynamic table has been mapped as
Chris Dearman99186652014-02-06 20:36:51 -08002866// read-only, but the DYNAMIC header claims it is writable.
2867#if !(defined(__mips__) && defined(__LP64__))
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002868 if ((dynamic_flags & PF_W) != 0) {
2869 d->d_un.d_val = reinterpret_cast<uintptr_t>(&_r_debug);
2870 }
Chris Dearman99186652014-02-06 20:36:51 -08002871#endif
Dmitriy Ivanovc6292ea2015-02-13 16:29:50 -08002872 break;
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07002873#if defined(USE_RELA)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002874 case DT_RELA:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002875 rela_ = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002876 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002877
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002878 case DT_RELASZ:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002879 rela_count_ = d->d_un.d_val / sizeof(ElfW(Rela));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002880 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002881
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002882 case DT_ANDROID_RELA:
2883 android_relocs_ = reinterpret_cast<uint8_t*>(load_bias + d->d_un.d_ptr);
2884 break;
2885
2886 case DT_ANDROID_RELASZ:
2887 android_relocs_size_ = d->d_un.d_val;
2888 break;
2889
2890 case DT_ANDROID_REL:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002891 DL_ERR("unsupported DT_ANDROID_REL in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002892 return false;
2893
2894 case DT_ANDROID_RELSZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002895 DL_ERR("unsupported DT_ANDROID_RELSZ in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002896 return false;
2897
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002898 case DT_RELAENT:
2899 if (d->d_un.d_val != sizeof(ElfW(Rela))) {
Dmitriy Ivanovf240aa82014-09-16 23:34:20 -07002900 DL_ERR("invalid DT_RELAENT: %zd", static_cast<size_t>(d->d_un.d_val));
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002901 return false;
2902 }
2903 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002904
2905 // ignored (see DT_RELCOUNT comments for details)
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002906 case DT_RELACOUNT:
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002907 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002908
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002909 case DT_REL:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002910 DL_ERR("unsupported DT_REL in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002911 return false;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002912
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002913 case DT_RELSZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002914 DL_ERR("unsupported DT_RELSZ in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002915 return false;
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002916
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002917#else
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002918 case DT_REL:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002919 rel_ = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002920 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002921
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002922 case DT_RELSZ:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002923 rel_count_ = d->d_un.d_val / sizeof(ElfW(Rel));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002924 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002925
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002926 case DT_RELENT:
2927 if (d->d_un.d_val != sizeof(ElfW(Rel))) {
Dmitriy Ivanovf240aa82014-09-16 23:34:20 -07002928 DL_ERR("invalid DT_RELENT: %zd", static_cast<size_t>(d->d_un.d_val));
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002929 return false;
2930 }
2931 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002932
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002933 case DT_ANDROID_REL:
2934 android_relocs_ = reinterpret_cast<uint8_t*>(load_bias + d->d_un.d_ptr);
2935 break;
2936
2937 case DT_ANDROID_RELSZ:
2938 android_relocs_size_ = d->d_un.d_val;
2939 break;
2940
2941 case DT_ANDROID_RELA:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002942 DL_ERR("unsupported DT_ANDROID_RELA in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002943 return false;
2944
2945 case DT_ANDROID_RELASZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002946 DL_ERR("unsupported DT_ANDROID_RELASZ in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002947 return false;
2948
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002949 // "Indicates that all RELATIVE relocations have been concatenated together,
2950 // and specifies the RELATIVE relocation count."
2951 //
2952 // TODO: Spec also mentions that this can be used to optimize relocation process;
2953 // Not currently used by bionic linker - ignored.
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002954 case DT_RELCOUNT:
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002955 break;
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002956
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002957 case DT_RELA:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002958 DL_ERR("unsupported DT_RELA in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002959 return false;
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002960
2961 case DT_RELASZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002962 DL_ERR("unsupported DT_RELASZ in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002963 return false;
2964
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002965#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002966 case DT_INIT:
Dimitry Ivanov55437462016-07-20 15:33:07 -07002967 init_func_ = reinterpret_cast<linker_ctor_function_t>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002968 DEBUG("%s constructors (DT_INIT) found at %p", get_realpath(), init_func_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002969 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002970
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002971 case DT_FINI:
Dimitry Ivanov55437462016-07-20 15:33:07 -07002972 fini_func_ = reinterpret_cast<linker_dtor_function_t>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002973 DEBUG("%s destructors (DT_FINI) found at %p", get_realpath(), fini_func_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002974 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002975
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002976 case DT_INIT_ARRAY:
Dimitry Ivanov55437462016-07-20 15:33:07 -07002977 init_array_ = reinterpret_cast<linker_ctor_function_t*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002978 DEBUG("%s constructors (DT_INIT_ARRAY) found at %p", get_realpath(), init_array_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002979 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002980
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002981 case DT_INIT_ARRAYSZ:
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -08002982 init_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002983 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002984
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002985 case DT_FINI_ARRAY:
Dimitry Ivanov55437462016-07-20 15:33:07 -07002986 fini_array_ = reinterpret_cast<linker_dtor_function_t*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002987 DEBUG("%s destructors (DT_FINI_ARRAY) found at %p", get_realpath(), fini_array_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002988 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002989
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002990 case DT_FINI_ARRAYSZ:
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -08002991 fini_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002992 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002993
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002994 case DT_PREINIT_ARRAY:
Dimitry Ivanov55437462016-07-20 15:33:07 -07002995 preinit_array_ = reinterpret_cast<linker_ctor_function_t*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002996 DEBUG("%s constructors (DT_PREINIT_ARRAY) found at %p", get_realpath(), preinit_array_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002997 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002998
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002999 case DT_PREINIT_ARRAYSZ:
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -08003000 preinit_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003001 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003002
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003003 case DT_TEXTREL:
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003004#if defined(__LP64__)
Dimitry Ivanov816676e2016-10-19 11:00:28 -07003005 DL_ERR("\"%s\" has text relocations", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003006 return false;
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003007#else
3008 has_text_relocations = true;
3009 break;
3010#endif
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003011
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003012 case DT_SYMBOLIC:
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -07003013 has_DT_SYMBOLIC = true;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003014 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003015
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003016 case DT_NEEDED:
3017 ++needed_count;
3018 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003019
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003020 case DT_FLAGS:
3021 if (d->d_un.d_val & DF_TEXTREL) {
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003022#if defined(__LP64__)
Dimitry Ivanov816676e2016-10-19 11:00:28 -07003023 DL_ERR("\"%s\" has text relocations", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003024 return false;
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003025#else
3026 has_text_relocations = true;
3027#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003028 }
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -07003029 if (d->d_un.d_val & DF_SYMBOLIC) {
3030 has_DT_SYMBOLIC = true;
3031 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003032 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003033
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07003034 case DT_FLAGS_1:
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07003035 set_dt_flags_1(d->d_un.d_val);
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -07003036
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07003037 if ((d->d_un.d_val & ~SUPPORTED_DT_FLAGS_1) != 0) {
Dimitry Ivanov816676e2016-10-19 11:00:28 -07003038 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 -07003039 }
3040 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003041#if defined(__mips__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003042 case DT_MIPS_RLD_MAP:
3043 // Set the DT_MIPS_RLD_MAP entry to the address of _r_debug for GDB.
3044 {
3045 r_debug** dp = reinterpret_cast<r_debug**>(load_bias + d->d_un.d_ptr);
3046 *dp = &_r_debug;
3047 }
3048 break;
Lazar Trsic83b44a92016-04-06 13:39:17 +02003049 case DT_MIPS_RLD_MAP_REL:
3050 // Set the DT_MIPS_RLD_MAP_REL entry to the address of _r_debug for GDB.
Raghu Gandham68815722014-12-18 19:12:19 -08003051 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07003052 r_debug** dp = reinterpret_cast<r_debug**>(
3053 reinterpret_cast<ElfW(Addr)>(d) + d->d_un.d_val);
Raghu Gandham68815722014-12-18 19:12:19 -08003054 *dp = &_r_debug;
3055 }
3056 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003057
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003058 case DT_MIPS_RLD_VERSION:
3059 case DT_MIPS_FLAGS:
3060 case DT_MIPS_BASE_ADDRESS:
3061 case DT_MIPS_UNREFEXTNO:
3062 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003063
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003064 case DT_MIPS_SYMTABNO:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003065 mips_symtabno_ = d->d_un.d_val;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003066 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003067
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003068 case DT_MIPS_LOCAL_GOTNO:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003069 mips_local_gotno_ = d->d_un.d_val;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003070 break;
3071
3072 case DT_MIPS_GOTSYM:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003073 mips_gotsym_ = d->d_un.d_val;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003074 break;
3075#endif
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003076 // Ignored: "Its use has been superseded by the DF_BIND_NOW flag"
3077 case DT_BIND_NOW:
3078 break;
3079
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003080 case DT_VERSYM:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003081 versym_ = reinterpret_cast<ElfW(Versym)*>(load_bias + d->d_un.d_ptr);
3082 break;
3083
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003084 case DT_VERDEF:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003085 verdef_ptr_ = load_bias + d->d_un.d_ptr;
3086 break;
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003087 case DT_VERDEFNUM:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003088 verdef_cnt_ = d->d_un.d_val;
3089 break;
3090
Alexander Ivchenkoe8314332014-12-02 15:32:25 +03003091 case DT_VERNEED:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003092 verneed_ptr_ = load_bias + d->d_un.d_ptr;
3093 break;
3094
Alexander Ivchenkoe8314332014-12-02 15:32:25 +03003095 case DT_VERNEEDNUM:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003096 verneed_cnt_ = d->d_un.d_val;
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003097 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003098
Evgenii Stepanov68650822015-06-10 13:38:39 -07003099 case DT_RUNPATH:
3100 // this is parsed after we have strtab initialized (see below).
3101 break;
3102
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003103 default:
Dmitriy Ivanov8f61d992014-09-16 14:31:06 -07003104 if (!relocating_linker) {
Dimitry Ivanov816676e2016-10-19 11:00:28 -07003105 DL_WARN("\"%s\" unused DT entry: type %p arg %p", get_realpath(),
Dmitriy Ivanov8f61d992014-09-16 14:31:06 -07003106 reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
3107 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003108 break;
Brian Carlstromd4ee82d2013-02-28 15:58:45 -08003109 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003110 }
3111
Duane Sandbc425c72015-06-01 16:29:14 -07003112#if defined(__mips__) && !defined(__LP64__)
3113 if (!mips_check_and_adjust_fp_modes()) {
3114 return false;
3115 }
3116#endif
3117
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003118 DEBUG("si->base = %p, si->strtab = %p, si->symtab = %p",
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003119 reinterpret_cast<void*>(base), strtab_, symtab_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003120
3121 // Sanity checks.
3122 if (relocating_linker && needed_count != 0) {
3123 DL_ERR("linker cannot have DT_NEEDED dependencies on other libraries");
3124 return false;
3125 }
Dmitriy Ivanov3597b802015-03-09 12:02:02 -07003126 if (nbucket_ == 0 && gnu_nbucket_ == 0) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003127 DL_ERR("empty/missing DT_HASH/DT_GNU_HASH in \"%s\" "
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003128 "(new hash type from the future?)", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003129 return false;
3130 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003131 if (strtab_ == 0) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003132 DL_ERR("empty/missing DT_STRTAB in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003133 return false;
3134 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003135 if (symtab_ == 0) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003136 DL_ERR("empty/missing DT_SYMTAB in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003137 return false;
3138 }
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003139
Dmitriy Ivanov624b8f12015-06-08 10:41:33 -07003140 // second pass - parse entries relying on strtab
3141 for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
Evgenii Stepanov68650822015-06-10 13:38:39 -07003142 switch (d->d_tag) {
3143 case DT_SONAME:
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07003144 set_soname(get_string(d->d_un.d_val));
Evgenii Stepanov68650822015-06-10 13:38:39 -07003145 break;
3146 case DT_RUNPATH:
Evgenii Stepanov68650822015-06-10 13:38:39 -07003147 set_dt_runpath(get_string(d->d_un.d_val));
3148 break;
Dmitriy Ivanov624b8f12015-06-08 10:41:33 -07003149 }
3150 }
3151
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003152 // Before M release linker was using basename in place of soname.
Dmitriy Ivanov19133522015-06-02 17:36:54 -07003153 // In the case when dt_soname is absent some apps stop working
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003154 // because they can't find dt_needed library by soname.
3155 // This workaround should keep them working. (applies only
Elliott Hughes5bc78c82016-11-16 11:35:43 -08003156 // for apps targeting sdk version < M). Make an exception for
Dmitriy Ivanov19133522015-06-02 17:36:54 -07003157 // the main executable and linker; they do not need to have dt_soname
Dimitry Ivanov3f660572016-09-09 10:00:39 -07003158 if (soname_ == nullptr &&
3159 this != solist_get_somain() &&
3160 (flags_ & FLAG_LINKER) == 0 &&
Elliott Hughes5bc78c82016-11-16 11:35:43 -08003161 get_application_target_sdk_version() < __ANDROID_API_M__) {
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003162 soname_ = basename(realpath_.c_str());
3163 DL_WARN("%s: is missing DT_SONAME will use basename as a replacement: \"%s\"",
3164 get_realpath(), soname_);
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07003165 // 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 -07003166 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003167 return true;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07003168}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003169
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003170bool soinfo::link_image(const soinfo_list_t& global_group, const soinfo_list_t& local_group,
3171 const android_dlextinfo* extinfo) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003172
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08003173 local_group_root_ = local_group.front();
3174 if (local_group_root_ == nullptr) {
3175 local_group_root_ = this;
3176 }
3177
Dmitriy Ivanov19133522015-06-02 17:36:54 -07003178 if ((flags_ & FLAG_LINKER) == 0 && local_group_root_ == this) {
3179 target_sdk_version_ = get_application_target_sdk_version();
3180 }
3181
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003182 VersionTracker version_tracker;
3183
3184 if (!version_tracker.init(this)) {
3185 return false;
3186 }
3187
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003188#if !defined(__LP64__)
3189 if (has_text_relocations) {
Elliott Hughes5bc78c82016-11-16 11:35:43 -08003190 // Fail if app is targeting M or above.
3191 if (get_application_target_sdk_version() >= __ANDROID_API_M__) {
Dimitry Ivanov816676e2016-10-19 11:00:28 -07003192 DL_ERR_AND_LOG("\"%s\" has text relocations", get_realpath());
Dmitriy Ivanove4ad91f2015-06-12 15:00:31 -07003193 return false;
3194 }
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003195 // Make segments writable to allow text relocations to work properly. We will later call
Dmitriy Ivanov7e039932015-10-01 14:02:19 -07003196 // phdr_table_protect_segments() after all of them are applied.
Dimitry Ivanov816676e2016-10-19 11:00:28 -07003197 DL_WARN("\"%s\" has text relocations. This is wasting memory and prevents "
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003198 "security hardening. Please fix.", get_realpath());
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07003199 add_dlwarning(get_realpath(), "text relocations");
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003200 if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
3201 DL_ERR("can't unprotect loadable segments for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003202 get_realpath(), strerror(errno));
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003203 return false;
3204 }
3205 }
3206#endif
3207
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003208 if (android_relocs_ != nullptr) {
3209 // check signature
3210 if (android_relocs_size_ > 3 &&
3211 android_relocs_[0] == 'A' &&
3212 android_relocs_[1] == 'P' &&
Dmitriy Ivanov18870d32015-04-22 13:10:04 -07003213 android_relocs_[2] == 'S' &&
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003214 android_relocs_[3] == '2') {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003215 DEBUG("[ android relocating %s ]", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003216
3217 bool relocated = false;
3218 const uint8_t* packed_relocs = android_relocs_ + 4;
3219 const size_t packed_relocs_size = android_relocs_size_ - 4;
3220
Dmitriy Ivanov18870d32015-04-22 13:10:04 -07003221 relocated = relocate(
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003222 version_tracker,
Dmitriy Ivanov18870d32015-04-22 13:10:04 -07003223 packed_reloc_iterator<sleb128_decoder>(
3224 sleb128_decoder(packed_relocs, packed_relocs_size)),
3225 global_group, local_group);
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003226
3227 if (!relocated) {
3228 return false;
3229 }
3230 } else {
3231 DL_ERR("bad android relocation header.");
3232 return false;
3233 }
3234 }
3235
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07003236#if defined(USE_RELA)
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003237 if (rela_ != nullptr) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003238 DEBUG("[ relocating %s ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003239 if (!relocate(version_tracker,
3240 plain_reloc_iterator(rela_, rela_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003241 return false;
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07003242 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003243 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003244 if (plt_rela_ != nullptr) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003245 DEBUG("[ relocating %s plt ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003246 if (!relocate(version_tracker,
3247 plain_reloc_iterator(plt_rela_, plt_rela_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003248 return false;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003249 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003250 }
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07003251#else
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003252 if (rel_ != nullptr) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003253 DEBUG("[ relocating %s ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003254 if (!relocate(version_tracker,
3255 plain_reloc_iterator(rel_, rel_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003256 return false;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003257 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003258 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003259 if (plt_rel_ != nullptr) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003260 DEBUG("[ relocating %s plt ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003261 if (!relocate(version_tracker,
3262 plain_reloc_iterator(plt_rel_, plt_rel_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003263 return false;
Brigid Smithc5a13ef2014-07-23 11:22:25 -07003264 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003265 }
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07003266#endif
Brigid Smithc5a13ef2014-07-23 11:22:25 -07003267
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07003268#if defined(__mips__)
Dmitriy Ivanovf39cb632015-04-30 20:17:03 -07003269 if (!mips_relocate_got(version_tracker, global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003270 return false;
3271 }
Raghu Gandhamd7daacb2012-07-31 12:07:22 -07003272#endif
3273
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003274 DEBUG("[ finished linking %s ]", get_realpath());
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003275
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003276#if !defined(__LP64__)
3277 if (has_text_relocations) {
3278 // All relocations are done, we can protect our segments back to read-only.
3279 if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
3280 DL_ERR("can't protect segments for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003281 get_realpath(), strerror(errno));
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003282 return false;
3283 }
3284 }
3285#endif
3286
Mingwei Shibe910522015-11-12 07:02:14 +00003287 // We can also turn on GNU RELRO protection if we're not linking the dynamic linker
3288 // itself --- it can't make system calls yet, and will have to call protect_relro later.
3289 if (!is_linker() && !protect_relro()) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003290 return false;
3291 }
Nick Kralevich9ec0f032012-02-28 10:40:00 -08003292
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003293 /* Handle serializing/sharing the RELRO segment */
3294 if (extinfo && (extinfo->flags & ANDROID_DLEXT_WRITE_RELRO)) {
3295 if (phdr_table_serialize_gnu_relro(phdr, phnum, load_bias,
3296 extinfo->relro_fd) < 0) {
3297 DL_ERR("failed serializing GNU RELRO section for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003298 get_realpath(), strerror(errno));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003299 return false;
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +00003300 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003301 } else if (extinfo && (extinfo->flags & ANDROID_DLEXT_USE_RELRO)) {
3302 if (phdr_table_map_gnu_relro(phdr, phnum, load_bias,
3303 extinfo->relro_fd) < 0) {
3304 DL_ERR("failed mapping GNU RELRO section for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003305 get_realpath(), strerror(errno));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003306 return false;
3307 }
3308 }
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +00003309
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003310 notify_gdb_of_load(this);
3311 return true;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003312}
3313
Mingwei Shibe910522015-11-12 07:02:14 +00003314bool soinfo::protect_relro() {
3315 if (phdr_table_protect_gnu_relro(phdr, phnum, load_bias) < 0) {
3316 DL_ERR("can't enable GNU RELRO protection for \"%s\": %s",
3317 get_realpath(), strerror(errno));
3318 return false;
3319 }
3320 return true;
3321}
3322
Dimitry Ivanov3f660572016-09-09 10:00:39 -07003323void init_default_namespace() {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003324 g_default_namespace.set_name("(default)");
3325 g_default_namespace.set_isolated(false);
3326
Dimitry Ivanov3f660572016-09-09 10:00:39 -07003327 soinfo* somain = solist_get_somain();
3328
Evgenii Stepanovd640b222015-07-10 17:54:01 -07003329 const char *interp = phdr_table_get_interpreter_name(somain->phdr, somain->phnum,
3330 somain->load_bias);
3331 const char* bname = basename(interp);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003332 if (bname && (strcmp(bname, "linker_asan") == 0 || strcmp(bname, "linker_asan64") == 0)) {
Evgenii Stepanovd640b222015-07-10 17:54:01 -07003333 g_default_ld_paths = kAsanDefaultLdPaths;
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -07003334 g_is_asan = true;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003335 } else {
Evgenii Stepanovd640b222015-07-10 17:54:01 -07003336 g_default_ld_paths = kDefaultLdPaths;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003337 }
3338
neo.chae2589f9d2016-10-04 11:00:27 +09003339 char real_path[PATH_MAX];
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003340 std::vector<std::string> ld_default_paths;
3341 for (size_t i = 0; g_default_ld_paths[i] != nullptr; ++i) {
neo.chae2589f9d2016-10-04 11:00:27 +09003342 if (realpath(g_default_ld_paths[i], real_path) != nullptr) {
3343 ld_default_paths.push_back(real_path);
3344 } else {
3345 ld_default_paths.push_back(g_default_ld_paths[i]);
3346 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003347 }
3348
3349 g_default_namespace.set_default_library_paths(std::move(ld_default_paths));
Evgenii Stepanovd640b222015-07-10 17:54:01 -07003350};