blob: 79c3ac54ec059cba448ed19d7015cbc4a0edec92 [file] [log] [blame]
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001/*
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002 * Copyright (C) 2008 The Android Open Source Project
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
Dmitriy Ivanov19133522015-06-02 17:36:54 -070029#include <android/api-level.h>
Elliott Hughes46882792012-08-03 16:49:39 -070030#include <errno.h>
31#include <fcntl.h>
Elliott Hughes0266ae52014-02-10 17:46:57 -080032#include <inttypes.h>
Elliott Hughes46882792012-08-03 16:49:39 -070033#include <pthread.h>
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080034#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
Elliott Hughes46882792012-08-03 16:49:39 -070037#include <sys/mman.h>
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -080038#include <sys/param.h>
Elliott Hughes46882792012-08-03 16:49:39 -070039#include <unistd.h>
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080040
Dmitriy Ivanov0d150942014-08-22 12:25:04 -070041#include <new>
Dmitriy Ivanovd165f562015-03-23 18:43:02 -070042#include <string>
Dmitriy Ivanovb4827502015-09-28 16:38:31 -070043#include <unordered_map>
Dmitriy Ivanovd165f562015-03-23 18:43:02 -070044#include <vector>
Dmitriy Ivanov0d150942014-08-22 12:25:04 -070045
Elliott Hughes46882792012-08-03 16:49:39 -070046// Private C library headers.
Dmitriy Ivanov14669a92014-09-05 16:42:53 -070047#include "private/ScopeGuard.h"
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080048
49#include "linker.h"
Dmitriy Ivanovc9ce70d2015-03-10 15:30:26 -070050#include "linker_block_allocator.h"
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -070051#include "linker_cfi.h"
Dimitry Ivanov6b788ee2016-02-17 16:08:03 -080052#include "linker_gdb_support.h"
Dimitry Ivanov48ec2882016-08-04 11:50:36 -070053#include "linker_globals.h"
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080054#include "linker_debug.h"
Dimitry Ivanov769b33f2016-07-21 11:33:40 -070055#include "linker_dlwarning.h"
Dimitry Ivanov3f660572016-09-09 10:00:39 -070056#include "linker_main.h"
Dimitry Ivanovb943f302016-08-03 16:00:10 -070057#include "linker_namespaces.h"
Dmitriy Ivanov18870d32015-04-22 13:10:04 -070058#include "linker_sleb128.h"
David 'Digit' Turner23363ed2012-06-18 18:13:49 +020059#include "linker_phdr.h"
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -080060#include "linker_relocs.h"
Dmitriy Ivanovfa26eee2015-02-03 16:06:47 -080061#include "linker_reloc_iterators.h"
Dmitriy Ivanova1feb112015-10-01 18:41:57 -070062#include "linker_utils.h"
tony.ys_liub4474402015-07-29 18:00:22 +080063
Elliott Hughes939a7e02015-12-04 15:27:46 -080064#include "android-base/strings.h"
Dimitry Ivanovb996d602016-07-11 18:11:39 -070065#include "android-base/stringprintf.h"
Simon Baldwinaef71952015-01-16 13:22:54 +000066#include "ziparchive/zip_archive.h"
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080067
Elliott Hughes1801db32015-06-08 18:04:00 -070068// Override macros to use C++ style casts.
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -080069#undef ELF_ST_TYPE
70#define ELF_ST_TYPE(x) (static_cast<uint32_t>(x) & 0xf)
71
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -070072static android_namespace_t* g_anonymous_namespace = &g_default_namespace;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -070073
Dmitriy Ivanov600bc3c2015-03-10 15:43:50 -070074static LinkerTypeAllocator<soinfo> g_soinfo_allocator;
75static LinkerTypeAllocator<LinkedListEntry<soinfo>> g_soinfo_links_allocator;
Magnus Malmbornba98d922012-09-12 13:00:55 +020076
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -070077static LinkerTypeAllocator<android_namespace_t> g_namespace_allocator;
Dimitry Ivanovaca299a2016-04-11 12:42:58 -070078static LinkerTypeAllocator<LinkedListEntry<android_namespace_t>> g_namespace_list_allocator;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -070079
Elliott Hughes4eeb1f12013-10-25 17:38:02 -070080#if defined(__LP64__)
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -070081static const char* const kSystemLibDir = "/system/lib64";
82static const char* const kVendorLibDir = "/vendor/lib64";
83static const char* const kAsanSystemLibDir = "/data/lib64";
84static const char* const kAsanVendorLibDir = "/data/vendor/lib64";
Elliott Hughes011bc0b2013-10-08 14:27:10 -070085#else
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -070086static const char* const kSystemLibDir = "/system/lib";
87static const char* const kVendorLibDir = "/vendor/lib";
88static const char* const kAsanSystemLibDir = "/data/lib";
89static const char* const kAsanVendorLibDir = "/data/vendor/lib";
Elliott Hughes011bc0b2013-10-08 14:27:10 -070090#endif
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -070091
92static const char* const kDefaultLdPaths[] = {
93 kSystemLibDir,
94 kVendorLibDir,
Dmitriy Ivanov851135b2014-08-29 12:02:36 -070095 nullptr
Elliott Hughes124fae92012-10-31 14:20:03 -070096};
David Bartleybc3a5c22009-06-02 18:27:28 -070097
Evgenii Stepanovd640b222015-07-10 17:54:01 -070098static const char* const kAsanDefaultLdPaths[] = {
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -070099 kAsanSystemLibDir,
100 kSystemLibDir,
101 kAsanVendorLibDir,
102 kVendorLibDir,
Evgenii Stepanovd640b222015-07-10 17:54:01 -0700103 nullptr
104};
105
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700106// Is ASAN enabled?
107static bool g_is_asan = false;
108
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -0700109static CFIShadowWriter g_cfi_shadow;
110
111CFIShadowWriter* get_cfi_shadow() {
112 return &g_cfi_shadow;
113}
114
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700115static bool is_system_library(const std::string& realpath) {
116 for (const auto& dir : g_default_namespace.get_default_library_paths()) {
117 if (file_is_in_dir(realpath, dir)) {
118 return true;
119 }
120 }
121 return false;
122}
123
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700124// Checks if the file exists and not a directory.
125static bool file_exists(const char* path) {
Dimitry Ivanov4cf70242016-08-11 11:11:52 -0700126 struct stat s;
127
128 if (stat(path, &s) != 0) {
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700129 return false;
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700130 }
Dimitry Ivanov4cf70242016-08-11 11:11:52 -0700131
132 return S_ISREG(s.st_mode);
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700133}
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700134
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700135// TODO(dimitry): The grey-list is a workaround for http://b/26394120 ---
136// gradually remove libraries from this list until it is gone.
137static bool is_greylisted(const char* name, const soinfo* needed_by) {
138 static const char* const kLibraryGreyList[] = {
139 "libandroid_runtime.so",
140 "libbinder.so",
141 "libcrypto.so",
142 "libcutils.so",
143 "libexpat.so",
144 "libgui.so",
145 "libmedia.so",
146 "libnativehelper.so",
147 "libskia.so",
148 "libssl.so",
149 "libstagefright.so",
150 "libsqlite.so",
151 "libui.so",
152 "libutils.so",
153 "libvorbisidec.so",
154 nullptr
155 };
156
Elliott Hughes5bc78c82016-11-16 11:35:43 -0800157 // If you're targeting N, you don't get the greylist.
158 if (get_application_target_sdk_version() >= __ANDROID_API_N__) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700159 return false;
160 }
161
162 // if the library needed by a system library - implicitly assume it
163 // is greylisted
164
165 if (needed_by != nullptr && is_system_library(needed_by->get_realpath())) {
166 return true;
167 }
168
169 // if this is an absolute path - make sure it points to /system/lib(64)
170 if (name[0] == '/' && dirname(name) == kSystemLibDir) {
171 // and reduce the path to basename
172 name = basename(name);
173 }
174
175 for (size_t i = 0; kLibraryGreyList[i] != nullptr; ++i) {
176 if (strcmp(name, kLibraryGreyList[i]) == 0) {
177 return true;
178 }
179 }
180
181 return false;
182}
183// END OF WORKAROUND
184
Evgenii Stepanovd640b222015-07-10 17:54:01 -0700185static const char* const* g_default_ld_paths;
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700186static std::vector<std::string> g_ld_preload_names;
Elliott Hughesa4aafd12014-01-13 16:37:47 -0800187
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700188static bool g_public_namespace_initialized;
Dimitry Ivanovb943f302016-08-03 16:00:10 -0700189static soinfo_list_t g_public_namespace;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700190
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800191#if STATS
Elliott Hughesbedfe382012-08-14 14:07:59 -0700192struct linker_stats_t {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700193 int count[kRelocMax];
Elliott Hughesbedfe382012-08-14 14:07:59 -0700194};
195
196static linker_stats_t linker_stats;
197
Dmitriy Ivanov114ff692015-01-14 11:36:38 -0800198void count_relocation(RelocationKind kind) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700199 ++linker_stats.count[kind];
Elliott Hughesbedfe382012-08-14 14:07:59 -0700200}
201#else
Dmitriy Ivanov114ff692015-01-14 11:36:38 -0800202void count_relocation(RelocationKind) {
Elliott Hughesbedfe382012-08-14 14:07:59 -0700203}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800204#endif
205
206#if COUNT_PAGES
Dmitriy Ivanov114ff692015-01-14 11:36:38 -0800207uint32_t bitmask[4096];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800208#endif
209
Elliott Hughesbedfe382012-08-14 14:07:59 -0700210static void notify_gdb_of_load(soinfo* info) {
Dimitry Ivanove97d8ed2016-03-01 15:55:56 -0800211 if (info->is_linker() || info->is_main_executable()) {
212 // gdb already knows about the linker and the main executable.
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700213 return;
214 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800215
Dimitry Ivanov6b788ee2016-02-17 16:08:03 -0800216 link_map* map = &(info->link_map_head);
Nicolas Geoffray0fa54102016-02-18 09:31:24 +0000217
Dimitry Ivanov6b788ee2016-02-17 16:08:03 -0800218 map->l_addr = info->load_bias;
219 // link_map l_name field is not const.
220 map->l_name = const_cast<char*>(info->get_realpath());
221 map->l_ld = info->dynamic;
Nicolas Geoffray0fa54102016-02-18 09:31:24 +0000222
Dimitry Ivanove97d8ed2016-03-01 15:55:56 -0800223 CHECK(map->l_name != nullptr);
224 CHECK(map->l_name[0] != '\0');
225
Dimitry Ivanov6b788ee2016-02-17 16:08:03 -0800226 notify_gdb_of_load(map);
Iliyan Malchev5e12d7e2009-03-24 19:02:00 -0700227}
228
Elliott Hughesbedfe382012-08-14 14:07:59 -0700229static void notify_gdb_of_unload(soinfo* info) {
Dimitry Ivanov6b788ee2016-02-17 16:08:03 -0800230 notify_gdb_of_unload(&(info->link_map_head));
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800231}
232
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -0700233LinkedListEntry<soinfo>* SoinfoListAllocator::alloc() {
234 return g_soinfo_links_allocator.alloc();
235}
236
237void SoinfoListAllocator::free(LinkedListEntry<soinfo>* entry) {
238 g_soinfo_links_allocator.free(entry);
239}
240
Dimitry Ivanovaca299a2016-04-11 12:42:58 -0700241LinkedListEntry<android_namespace_t>* NamespaceListAllocator::alloc() {
242 return g_namespace_list_allocator.alloc();
243}
244
245void NamespaceListAllocator::free(LinkedListEntry<android_namespace_t>* entry) {
246 g_namespace_list_allocator.free(entry);
247}
248
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700249soinfo* soinfo_alloc(android_namespace_t* ns, const char* name,
250 struct stat* file_stat, off64_t file_offset,
251 uint32_t rtld_flags) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700252 if (strlen(name) >= PATH_MAX) {
Magnus Malmbornba98d922012-09-12 13:00:55 +0200253 DL_ERR("library name \"%s\" too long", name);
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700254 return nullptr;
Magnus Malmbornba98d922012-09-12 13:00:55 +0200255 }
256
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700257 TRACE("name %s: allocating soinfo for ns=%p", name, ns);
258
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700259 soinfo* si = new (g_soinfo_allocator.alloc()) soinfo(ns, name, file_stat,
260 file_offset, rtld_flags);
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -0700261
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700262 solist_add_soinfo(si);
Magnus Malmbornba98d922012-09-12 13:00:55 +0200263
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -0700264 si->generate_handle();
265 ns->add_soinfo(si);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700266
Elliott Hughesca0c11b2013-03-12 10:40:45 -0700267 TRACE("name %s: allocated soinfo @ %p", name, si);
Magnus Malmbornba98d922012-09-12 13:00:55 +0200268 return si;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800269}
270
Elliott Hughesfaf05ba2014-02-11 16:59:37 -0800271static void soinfo_free(soinfo* si) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700272 if (si == nullptr) {
273 return;
274 }
275
276 if (si->base != 0 && si->size != 0) {
Dimitry Ivanovf45b0e92016-01-15 11:13:35 -0800277 if (!si->is_mapped_by_caller()) {
278 munmap(reinterpret_cast<void*>(si->base), si->size);
279 } else {
280 // remap the region as PROT_NONE, MAP_ANONYMOUS | MAP_NORESERVE
281 mmap(reinterpret_cast<void*>(si->base), si->size, PROT_NONE,
282 MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
283 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700284 }
285
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700286 TRACE("name %s: freeing soinfo @ %p", si->get_realpath(), si);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700287
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700288 if (!solist_remove_soinfo(si)) {
289 // TODO (dimitry): revisit this - for now preserving the logic
290 // but it does not look right, abort if soinfo is not in the list instead?
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700291 return;
292 }
Elliott Hughes46882792012-08-03 16:49:39 -0700293
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700294 // clear links to/from si
295 si->remove_all_links();
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -0700296
Dmitriy Ivanov609f11b2015-07-08 15:26:46 -0700297 si->~soinfo();
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700298 g_soinfo_allocator.free(si);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800299}
300
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700301static void parse_path(const char* path, const char* delimiters,
302 std::vector<std::string>* resolved_paths) {
303 std::vector<std::string> paths;
304 split_path(path, delimiters, &paths);
305 resolve_paths(paths, resolved_paths);
306}
307
Elliott Hughescade4c32012-12-20 14:42:14 -0800308static void parse_LD_LIBRARY_PATH(const char* path) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700309 std::vector<std::string> ld_libary_paths;
310 parse_path(path, ":", &ld_libary_paths);
311 g_default_namespace.set_ld_library_paths(std::move(ld_libary_paths));
Elliott Hughescade4c32012-12-20 14:42:14 -0800312}
313
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700314static bool realpath_fd(int fd, std::string* realpath) {
315 std::vector<char> buf(PATH_MAX), proc_self_fd(PATH_MAX);
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700316 __libc_format_buffer(&proc_self_fd[0], proc_self_fd.size(), "/proc/self/fd/%d", fd);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700317 if (readlink(&proc_self_fd[0], &buf[0], buf.size()) == -1) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700318 PRINT("readlink(\"%s\") failed: %s [fd=%d]", &proc_self_fd[0], strerror(errno), fd);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700319 return false;
320 }
321
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700322 *realpath = &buf[0];
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700323 return true;
324}
325
Elliott Hughes4eeb1f12013-10-25 17:38:02 -0700326#if defined(__arm__)
Elliott Hughes46882792012-08-03 16:49:39 -0700327
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700328// For a given PC, find the .so that it belongs to.
329// Returns the base address of the .ARM.exidx section
330// for that .so, and the number of 8-byte entries
331// in that section (via *pcount).
332//
333// Intended to be called by libc's __gnu_Unwind_Find_exidx().
Dimitry Ivanovd9e427c2016-11-22 16:55:25 -0800334_Unwind_Ptr do_dl_unwind_find_exidx(_Unwind_Ptr pc, int* pcount) {
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -0800335 uintptr_t addr = reinterpret_cast<uintptr_t>(pc);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800336
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700337 for (soinfo* si = solist_get_head(); si != 0; si = si->next) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700338 if ((addr >= si->base) && (addr < (si->base + si->size))) {
339 *pcount = si->ARM_exidx_count;
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -0800340 return reinterpret_cast<_Unwind_Ptr>(si->ARM_exidx);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800341 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700342 }
343 *pcount = 0;
344 return nullptr;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800345}
Elliott Hughes46882792012-08-03 16:49:39 -0700346
Christopher Ferris24053a42013-08-19 17:45:09 -0700347#endif
Elliott Hughes46882792012-08-03 16:49:39 -0700348
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700349// Here, we only have to provide a callback to iterate across all the
350// loaded libraries. gcc_eh does the rest.
Dmitriy Ivanov7271caf2015-06-29 14:48:25 -0700351int do_dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void* data) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700352 int rv = 0;
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700353 for (soinfo* si = solist_get_head(); si != nullptr; si = si->next) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700354 dl_phdr_info dl_info;
355 dl_info.dlpi_addr = si->link_map_head.l_addr;
356 dl_info.dlpi_name = si->link_map_head.l_name;
357 dl_info.dlpi_phdr = si->phdr;
358 dl_info.dlpi_phnum = si->phnum;
359 rv = cb(&dl_info, sizeof(dl_phdr_info), data);
360 if (rv != 0) {
361 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800362 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700363 }
364 return rv;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800365}
Elliott Hughes46882792012-08-03 16:49:39 -0700366
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800367
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700368bool soinfo_do_lookup(soinfo* si_from, const char* name, const version_info* vi,
Dimitry Ivanovb943f302016-08-03 16:00:10 -0700369 soinfo** si_found_in, const soinfo_list_t& global_group,
370 const soinfo_list_t& local_group, const ElfW(Sym)** symbol) {
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800371 SymbolName symbol_name(name);
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700372 const ElfW(Sym)* s = nullptr;
Iliyan Malchev6ed80c82009-09-28 19:38:04 -0700373
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -0700374 /* "This element's presence in a shared object library alters the dynamic linker's
375 * symbol resolution algorithm for references within the library. Instead of starting
376 * a symbol search with the executable file, the dynamic linker starts from the shared
377 * object itself. If the shared object fails to supply the referenced symbol, the
378 * dynamic linker then searches the executable file and other shared objects as usual."
379 *
380 * http://www.sco.com/developers/gabi/2012-12-31/ch5.dynamic.html
381 *
382 * Note that this is unlikely since static linker avoids generating
383 * relocations for -Bsymbolic linked dynamic executables.
384 */
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700385 if (si_from->has_DT_SYMBOLIC) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700386 DEBUG("%s: looking up %s in local scope (DT_SYMBOLIC)", si_from->get_realpath(), name);
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700387 if (!si_from->find_symbol_by_name(symbol_name, vi, &s)) {
388 return false;
389 }
390
Dmitriy Ivanov8f61d992014-09-16 14:31:06 -0700391 if (s != nullptr) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700392 *si_found_in = si_from;
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -0700393 }
394 }
395
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700396 // 1. Look for it in global_group
397 if (s == nullptr) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700398 bool error = false;
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700399 global_group.visit([&](soinfo* global_si) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700400 DEBUG("%s: looking up %s in %s (from global group)",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700401 si_from->get_realpath(), name, global_si->get_realpath());
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700402 if (!global_si->find_symbol_by_name(symbol_name, vi, &s)) {
403 error = true;
404 return false;
405 }
406
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -0700407 if (s != nullptr) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700408 *si_found_in = global_si;
409 return false;
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -0700410 }
Dmitriy Ivanovc2048942014-08-29 10:15:25 -0700411
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700412 return true;
413 });
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700414
415 if (error) {
416 return false;
417 }
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -0700418 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700419
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700420 // 2. Look for it in the local group
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700421 if (s == nullptr) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700422 bool error = false;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700423 local_group.visit([&](soinfo* local_si) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700424 if (local_si == si_from && si_from->has_DT_SYMBOLIC) {
Dmitriy Ivanove47b3f82014-10-23 14:19:07 -0700425 // we already did this - skip
426 return true;
427 }
428
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700429 DEBUG("%s: looking up %s in %s (from local group)",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700430 si_from->get_realpath(), name, local_si->get_realpath());
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700431 if (!local_si->find_symbol_by_name(symbol_name, vi, &s)) {
432 error = true;
433 return false;
434 }
435
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700436 if (s != nullptr) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700437 *si_found_in = local_si;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700438 return false;
439 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700440
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700441 return true;
442 });
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700443
444 if (error) {
445 return false;
446 }
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700447 }
448
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700449 if (s != nullptr) {
450 TRACE_TYPE(LOOKUP, "si %s sym %s s->st_value = %p, "
451 "found in %s, base = %p, load bias = %p",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700452 si_from->get_realpath(), name, reinterpret_cast<void*>(s->st_value),
453 (*si_found_in)->get_realpath(), reinterpret_cast<void*>((*si_found_in)->base),
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700454 reinterpret_cast<void*>((*si_found_in)->load_bias));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700455 }
Iliyan Malchev6ed80c82009-09-28 19:38:04 -0700456
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700457 *symbol = s;
458 return true;
Iliyan Malchev6ed80c82009-09-28 19:38:04 -0700459}
460
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700461ProtectedDataGuard::ProtectedDataGuard() {
462 if (ref_count_++ == 0) {
463 protect_data(PROT_READ | PROT_WRITE);
464 }
465}
466
467ProtectedDataGuard::~ProtectedDataGuard() {
468 if (ref_count_ == 0) { // overflow
469 __libc_fatal("Too many nested calls to dlopen()");
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -0800470 }
471
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700472 if (--ref_count_ == 0) {
473 protect_data(PROT_READ);
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -0800474 }
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700475}
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -0800476
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700477void ProtectedDataGuard::protect_data(int protection) {
478 g_soinfo_allocator.protect_all(protection);
479 g_soinfo_links_allocator.protect_all(protection);
480 g_namespace_allocator.protect_all(protection);
481 g_namespace_list_allocator.protect_all(protection);
482}
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -0800483
484size_t ProtectedDataGuard::ref_count_ = 0;
485
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700486// Each size has it's own allocator.
487template<size_t size>
488class SizeBasedAllocator {
489 public:
490 static void* alloc() {
491 return allocator_.alloc();
492 }
Dmitriy Ivanov4bea4982014-08-29 14:01:48 -0700493
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700494 static void free(void* ptr) {
495 allocator_.free(ptr);
496 }
Dmitriy Ivanov4bea4982014-08-29 14:01:48 -0700497
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700498 private:
499 static LinkerBlockAllocator allocator_;
500};
501
502template<size_t size>
503LinkerBlockAllocator SizeBasedAllocator<size>::allocator_(size);
504
505template<typename T>
506class TypeBasedAllocator {
507 public:
508 static T* alloc() {
509 return reinterpret_cast<T*>(SizeBasedAllocator<sizeof(T)>::alloc());
510 }
511
512 static void free(T* ptr) {
513 SizeBasedAllocator<sizeof(T)>::free(ptr);
514 }
515};
516
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700517class LoadTask {
518 public:
519 struct deleter_t {
520 void operator()(LoadTask* t) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700521 t->~LoadTask();
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700522 TypeBasedAllocator<LoadTask>::free(t);
523 }
524 };
525
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700526 static deleter_t deleter;
527
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700528 static LoadTask* create(const char* name, soinfo* needed_by,
529 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:
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700619 LoadTask(const char* name, soinfo* needed_by,
620 std::unordered_map<const soinfo*, ElfReader>* readers_map)
621 : name_(name), needed_by_(needed_by), si_(nullptr),
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700622 fd_(-1), close_fd_(false), file_offset_(0), elf_readers_map_(readers_map),
623 is_dt_needed_(false) {}
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700624
625 ~LoadTask() {
626 if (fd_ != -1 && close_fd_) {
627 close(fd_);
628 }
629 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700630
631 const char* name_;
632 soinfo* needed_by_;
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700633 soinfo* si_;
634 const android_dlextinfo* extinfo_;
635 int fd_;
636 bool close_fd_;
637 off64_t file_offset_;
638 std::unordered_map<const soinfo*, ElfReader>* elf_readers_map_;
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700639 // TODO(dimitry): needed by workaround for http://b/26394120 (the grey-list)
640 bool is_dt_needed_;
641 // END OF WORKAROUND
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700642
643 DISALLOW_IMPLICIT_CONSTRUCTORS(LoadTask);
644};
645
Ningsheng Jiane93be992014-09-16 15:22:10 +0800646LoadTask::deleter_t LoadTask::deleter;
647
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700648template <typename T>
649using linked_list_t = LinkedList<T, TypeBasedAllocator<LinkedListEntry<T>>>;
650
651typedef linked_list_t<soinfo> SoinfoLinkedList;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700652typedef linked_list_t<const char> StringLinkedList;
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700653typedef std::vector<LoadTask*> LoadTaskList;
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700654
Dmitriy Ivanovaa0f2bd2014-07-28 17:32:20 -0700655
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700656// This function walks down the tree of soinfo dependencies
657// in breadth-first order and
658// * calls action(soinfo* si) for each node, and
659// * terminates walk if action returns false.
660//
661// walk_dependencies_tree returns false if walk was terminated
662// by the action and true otherwise.
663template<typename F>
664static bool walk_dependencies_tree(soinfo* root_soinfos[], size_t root_soinfos_size, F action) {
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700665 SoinfoLinkedList visit_list;
666 SoinfoLinkedList visited;
667
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700668 for (size_t i = 0; i < root_soinfos_size; ++i) {
669 visit_list.push_back(root_soinfos[i]);
670 }
671
672 soinfo* si;
673 while ((si = visit_list.pop_front()) != nullptr) {
674 if (visited.contains(si)) {
Dmitriy Ivanov042426b2014-08-12 21:02:13 -0700675 continue;
676 }
677
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700678 if (!action(si)) {
679 return false;
Dmitriy Ivanovaa0f2bd2014-07-28 17:32:20 -0700680 }
681
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700682 visited.push_back(si);
683
684 si->get_children().for_each([&](soinfo* child) {
Dmitriy Ivanovaa0f2bd2014-07-28 17:32:20 -0700685 visit_list.push_back(child);
686 });
687 }
688
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700689 return true;
690}
691
692
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700693static const ElfW(Sym)* dlsym_handle_lookup(soinfo* root, soinfo* skip_until,
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800694 soinfo** found, SymbolName& symbol_name,
695 const version_info* vi) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700696 const ElfW(Sym)* result = nullptr;
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700697 bool skip_lookup = skip_until != nullptr;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700698
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700699 walk_dependencies_tree(&root, 1, [&](soinfo* current_soinfo) {
700 if (skip_lookup) {
701 skip_lookup = current_soinfo != skip_until;
702 return true;
703 }
704
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800705 if (!current_soinfo->find_symbol_by_name(symbol_name, vi, &result)) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700706 result = nullptr;
707 return false;
708 }
709
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700710 if (result != nullptr) {
711 *found = current_soinfo;
712 return false;
713 }
714
715 return true;
716 });
717
718 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800719}
720
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800721static const ElfW(Sym)* dlsym_linear_lookup(android_namespace_t* ns,
722 const char* name,
723 const version_info* vi,
724 soinfo** found,
725 soinfo* caller,
726 void* handle);
727
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700728// This is used by dlsym(3). It performs symbol lookup only within the
729// specified soinfo object and its dependencies in breadth first order.
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800730static const ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found,
731 const char* name, const version_info* vi) {
Dmitriy Ivanovf439b5a2015-05-30 13:04:39 -0700732 // According to man dlopen(3) and posix docs in the case when si is handle
733 // of the main executable we need to search not only in the executable and its
734 // dependencies but also in all libraries loaded with RTLD_GLOBAL.
735 //
736 // Since RTLD_GLOBAL is always set for the main executable and all dt_needed shared
737 // libraries and they are loaded in breath-first (correct) order we can just execute
738 // dlsym(RTLD_DEFAULT, ...); instead of doing two stage lookup.
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700739 if (si == solist_get_somain()) {
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800740 return dlsym_linear_lookup(&g_default_namespace, name, vi, found, nullptr, RTLD_DEFAULT);
Dmitriy Ivanovf439b5a2015-05-30 13:04:39 -0700741 }
742
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700743 SymbolName symbol_name(name);
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800744 return dlsym_handle_lookup(si, nullptr, found, symbol_name, vi);
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700745}
746
Brian Carlstromd4ee82d2013-02-28 15:58:45 -0800747/* This is used by dlsym(3) to performs a global symbol lookup. If the
748 start value is null (for RTLD_DEFAULT), the search starts at the
749 beginning of the global solist. Otherwise the search starts at the
750 specified soinfo (for RTLD_NEXT).
Iliyan Malchev6ed80c82009-09-28 19:38:04 -0700751 */
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800752static const ElfW(Sym)* dlsym_linear_lookup(android_namespace_t* ns,
753 const char* name,
754 const version_info* vi,
755 soinfo** found,
756 soinfo* caller,
757 void* handle) {
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800758 SymbolName symbol_name(name);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800759
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -0700760 auto& soinfo_list = ns->soinfo_list();
761 auto start = soinfo_list.begin();
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -0700762
763 if (handle == RTLD_NEXT) {
Dmitriy Ivanovb96ac412015-05-22 12:34:42 -0700764 if (caller == nullptr) {
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -0700765 return nullptr;
766 } else {
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -0700767 auto it = soinfo_list.find(caller);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700768 CHECK (it != soinfo_list.end());
769 start = ++it;
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -0700770 }
Elliott Hughescade4c32012-12-20 14:42:14 -0800771 }
772
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700773 const ElfW(Sym)* s = nullptr;
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -0700774 for (auto it = start, end = soinfo_list.end(); it != end; ++it) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700775 soinfo* si = *it;
Dmitriy Ivanov19133522015-06-02 17:36:54 -0700776 // Do not skip RTLD_LOCAL libraries in dlsym(RTLD_DEFAULT, ...)
Elliott Hughes5bc78c82016-11-16 11:35:43 -0800777 // if the library is opened by application with target api level < M.
Dmitriy Ivanov19133522015-06-02 17:36:54 -0700778 // See http://b/21565766
Elliott Hughes5bc78c82016-11-16 11:35:43 -0800779 if ((si->get_rtld_flags() & RTLD_GLOBAL) == 0 &&
780 si->get_target_sdk_version() >= __ANDROID_API_M__) {
Dmitriy Ivanove8ba50f2014-09-15 17:00:10 -0700781 continue;
782 }
783
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800784 if (!si->find_symbol_by_name(symbol_name, vi, &s)) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700785 return nullptr;
786 }
787
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700788 if (s != nullptr) {
Elliott Hughescade4c32012-12-20 14:42:14 -0800789 *found = si;
790 break;
Matt Fischer1698d9e2009-12-31 12:17:56 -0600791 }
Elliott Hughescade4c32012-12-20 14:42:14 -0800792 }
Matt Fischer1698d9e2009-12-31 12:17:56 -0600793
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700794 // If not found - use dlsym_handle_lookup for caller's
795 // local_group unless it is part of the global group in which
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -0700796 // case we already did it.
797 if (s == nullptr && caller != nullptr &&
798 (caller->get_rtld_flags() & RTLD_GLOBAL) == 0) {
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700799 return dlsym_handle_lookup(caller->get_local_group_root(),
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800800 (handle == RTLD_NEXT) ? caller : nullptr, found, symbol_name, vi);
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -0700801 }
802
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700803 if (s != nullptr) {
Elliott Hughesc00f2cb2013-10-04 17:01:33 -0700804 TRACE_TYPE(LOOKUP, "%s s->st_value = %p, found->base = %p",
805 name, reinterpret_cast<void*>(s->st_value), reinterpret_cast<void*>((*found)->base));
Elliott Hughescade4c32012-12-20 14:42:14 -0800806 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800807
Elliott Hughescade4c32012-12-20 14:42:14 -0800808 return s;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800809}
810
Kito Chengfa8c05d2013-03-12 14:58:06 +0800811soinfo* find_containing_library(const void* p) {
Elliott Hughes0266ae52014-02-10 17:46:57 -0800812 ElfW(Addr) address = reinterpret_cast<ElfW(Addr)>(p);
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700813 for (soinfo* si = solist_get_head(); si != nullptr; si = si->next) {
Kito Chengfa8c05d2013-03-12 14:58:06 +0800814 if (address >= si->base && address - si->base < si->size) {
815 return si;
Matt Fischere2a8b1f2009-12-31 12:17:40 -0600816 }
Kito Chengfa8c05d2013-03-12 14:58:06 +0800817 }
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700818 return nullptr;
Matt Fischere2a8b1f2009-12-31 12:17:40 -0600819}
820
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700821class ZipArchiveCache {
822 public:
823 ZipArchiveCache() {}
824 ~ZipArchiveCache();
825
826 bool get_or_open(const char* zip_path, ZipArchiveHandle* handle);
827 private:
828 DISALLOW_COPY_AND_ASSIGN(ZipArchiveCache);
829
830 std::unordered_map<std::string, ZipArchiveHandle> cache_;
831};
832
833bool ZipArchiveCache::get_or_open(const char* zip_path, ZipArchiveHandle* handle) {
834 std::string key(zip_path);
835
836 auto it = cache_.find(key);
837 if (it != cache_.end()) {
838 *handle = it->second;
839 return true;
840 }
841
842 int fd = TEMP_FAILURE_RETRY(open(zip_path, O_RDONLY | O_CLOEXEC));
843 if (fd == -1) {
844 return false;
845 }
846
847 if (OpenArchiveFd(fd, "", handle) != 0) {
848 // invalid zip-file (?)
Yabin Cui722072d2016-03-21 17:10:12 -0700849 CloseArchive(handle);
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700850 close(fd);
851 return false;
852 }
853
854 cache_[key] = *handle;
855 return true;
856}
857
858ZipArchiveCache::~ZipArchiveCache() {
Dmitriy Ivanov5dce8942015-10-13 12:14:16 -0700859 for (const auto& it : cache_) {
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700860 CloseArchive(it.second);
861 }
862}
863
864static int open_library_in_zipfile(ZipArchiveCache* zip_archive_cache,
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700865 const char* const input_path,
866 off64_t* file_offset, std::string* realpath) {
867 std::string normalized_path;
868 if (!normalize_path(input_path, &normalized_path)) {
869 return -1;
870 }
871
872 const char* const path = normalized_path.c_str();
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700873 TRACE("Trying zip file open from path \"%s\" -> normalized \"%s\"", input_path, path);
Simon Baldwinaef71952015-01-16 13:22:54 +0000874
Dmitriy Ivanov402a7502015-06-09 13:46:51 -0700875 // Treat an '!/' separator inside a path as the separator between the name
Simon Baldwinaef71952015-01-16 13:22:54 +0000876 // of the zip file on disk and the subdirectory to search within it.
Dmitriy Ivanov402a7502015-06-09 13:46:51 -0700877 // For example, if path is "foo.zip!/bar/bas/x.so", then we search for
Simon Baldwinaef71952015-01-16 13:22:54 +0000878 // "bar/bas/x.so" within "foo.zip".
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700879 const char* const separator = strstr(path, kZipFileSeparator);
Simon Baldwinaef71952015-01-16 13:22:54 +0000880 if (separator == nullptr) {
881 return -1;
Elliott Hughes124fae92012-10-31 14:20:03 -0700882 }
Simon Baldwinaef71952015-01-16 13:22:54 +0000883
884 char buf[512];
885 if (strlcpy(buf, path, sizeof(buf)) >= sizeof(buf)) {
886 PRINT("Warning: ignoring very long library path: %s", path);
887 return -1;
888 }
889
890 buf[separator - path] = '\0';
891
892 const char* zip_path = buf;
Dmitriy Ivanov402a7502015-06-09 13:46:51 -0700893 const char* file_path = &buf[separator - path + 2];
Simon Baldwinaef71952015-01-16 13:22:54 +0000894 int fd = TEMP_FAILURE_RETRY(open(zip_path, O_RDONLY | O_CLOEXEC));
895 if (fd == -1) {
896 return -1;
897 }
898
899 ZipArchiveHandle handle;
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700900 if (!zip_archive_cache->get_or_open(zip_path, &handle)) {
Simon Baldwinaef71952015-01-16 13:22:54 +0000901 // invalid zip-file (?)
902 close(fd);
903 return -1;
904 }
905
Simon Baldwinaef71952015-01-16 13:22:54 +0000906 ZipEntry entry;
907
Yusuke Sato56f40fb2015-06-25 14:56:07 -0700908 if (FindEntry(handle, ZipString(file_path), &entry) != 0) {
Simon Baldwinaef71952015-01-16 13:22:54 +0000909 // Entry was not found.
910 close(fd);
911 return -1;
912 }
913
914 // Check if it is properly stored
915 if (entry.method != kCompressStored || (entry.offset % PAGE_SIZE) != 0) {
916 close(fd);
917 return -1;
918 }
919
920 *file_offset = entry.offset;
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700921
922 if (realpath_fd(fd, realpath)) {
923 *realpath += separator;
924 } else {
925 PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.",
926 normalized_path.c_str());
927 *realpath = normalized_path;
928 }
929
Simon Baldwinaef71952015-01-16 13:22:54 +0000930 return fd;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800931}
932
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700933static bool format_path(char* buf, size_t buf_size, const char* path, const char* name) {
934 int n = __libc_format_buffer(buf, buf_size, "%s/%s", path, name);
935 if (n < 0 || n >= static_cast<int>(buf_size)) {
936 PRINT("Warning: ignoring very long library path: %s/%s", path, name);
937 return false;
938 }
Simon Baldwinaef71952015-01-16 13:22:54 +0000939
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700940 return true;
941}
942
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700943static int open_library_on_paths(ZipArchiveCache* zip_archive_cache,
944 const char* name, off64_t* file_offset,
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700945 const std::vector<std::string>& paths,
946 std::string* realpath) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700947 for (const auto& path : paths) {
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700948 char buf[512];
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700949 if (!format_path(buf, sizeof(buf), path.c_str(), name)) {
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700950 continue;
951 }
952
953 int fd = -1;
Dmitriy Ivanov730ed9d2015-07-16 04:52:06 -0700954 if (strstr(buf, kZipFileSeparator) != nullptr) {
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700955 fd = open_library_in_zipfile(zip_archive_cache, buf, file_offset, realpath);
Simon Baldwinaef71952015-01-16 13:22:54 +0000956 }
957
958 if (fd == -1) {
959 fd = TEMP_FAILURE_RETRY(open(buf, O_RDONLY | O_CLOEXEC));
960 if (fd != -1) {
961 *file_offset = 0;
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700962 if (!realpath_fd(fd, realpath)) {
963 PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.", buf);
964 *realpath = buf;
965 }
Simon Baldwinaef71952015-01-16 13:22:54 +0000966 }
967 }
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700968
969 if (fd != -1) {
970 return fd;
971 }
Simon Baldwinaef71952015-01-16 13:22:54 +0000972 }
973
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700974 return -1;
Simon Baldwinaef71952015-01-16 13:22:54 +0000975}
976
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700977static int open_library(android_namespace_t* ns,
978 ZipArchiveCache* zip_archive_cache,
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700979 const char* name, soinfo *needed_by,
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700980 off64_t* file_offset, std::string* realpath) {
Elliott Hughesca0c11b2013-03-12 10:40:45 -0700981 TRACE("[ opening %s ]", name);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800982
Elliott Hughes124fae92012-10-31 14:20:03 -0700983 // 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 -0700984 if (strchr(name, '/') != nullptr) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700985 int fd = -1;
986
Dmitriy Ivanov730ed9d2015-07-16 04:52:06 -0700987 if (strstr(name, kZipFileSeparator) != nullptr) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700988 fd = open_library_in_zipfile(zip_archive_cache, name, file_offset, realpath);
989 }
990
991 if (fd == -1) {
992 fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_CLOEXEC));
Simon Baldwinaef71952015-01-16 13:22:54 +0000993 if (fd != -1) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700994 *file_offset = 0;
995 if (!realpath_fd(fd, realpath)) {
996 PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.", name);
997 *realpath = name;
998 }
Simon Baldwinaef71952015-01-16 13:22:54 +0000999 }
1000 }
1001
Dmitriy Ivanove44fffd2015-03-17 17:12:18 -07001002 return fd;
Elliott Hughes124fae92012-10-31 14:20:03 -07001003 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001004
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001005 // Otherwise we try LD_LIBRARY_PATH first, and fall back to the default library path
1006 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 -07001007 if (fd == -1 && needed_by != nullptr) {
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001008 fd = open_library_on_paths(zip_archive_cache, name, file_offset, needed_by->get_dt_runpath(), realpath);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001009 // Check if the library is accessible
1010 if (fd != -1 && !ns->is_accessible(*realpath)) {
1011 fd = -1;
1012 }
Evgenii Stepanov68650822015-06-10 13:38:39 -07001013 }
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001014
Elliott Hughes124fae92012-10-31 14:20:03 -07001015 if (fd == -1) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001016 fd = open_library_on_paths(zip_archive_cache, name, file_offset, ns->get_default_library_paths(), realpath);
Elliott Hughes124fae92012-10-31 14:20:03 -07001017 }
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001018
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001019 // TODO(dimitry): workaround for http://b/26394120 (the grey-list)
1020 if (fd == -1 && ns != &g_default_namespace && is_greylisted(name, needed_by)) {
1021 // try searching for it on default_namespace default_library_path
1022 fd = open_library_on_paths(zip_archive_cache, name, file_offset,
1023 g_default_namespace.get_default_library_paths(), realpath);
1024 }
1025 // END OF WORKAROUND
1026
Elliott Hughes124fae92012-10-31 14:20:03 -07001027 return fd;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001028}
1029
Dimitry Ivanov3f660572016-09-09 10:00:39 -07001030const char* fix_dt_needed(const char* dt_needed, const char* sopath __unused) {
Dmitriy Ivanovd974e882015-05-27 18:29:41 -07001031#if !defined(__LP64__)
1032 // Work around incorrect DT_NEEDED entries for old apps: http://b/21364029
Elliott Hughes5bc78c82016-11-16 11:35:43 -08001033 if (get_application_target_sdk_version() < __ANDROID_API_M__) {
Dmitriy Ivanovd974e882015-05-27 18:29:41 -07001034 const char* bname = basename(dt_needed);
1035 if (bname != dt_needed) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001036 DL_WARN("library \"%s\" has invalid DT_NEEDED entry \"%s\"", sopath, dt_needed);
1037 add_dlwarning(sopath, "invalid DT_NEEDED entry", dt_needed);
Dmitriy Ivanovd974e882015-05-27 18:29:41 -07001038 }
1039
1040 return bname;
1041 }
1042#endif
1043 return dt_needed;
1044}
1045
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001046template<typename F>
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001047static void for_each_dt_needed(const ElfReader& elf_reader, F action) {
1048 for (const ElfW(Dyn)* d = elf_reader.dynamic(); d->d_tag != DT_NULL; ++d) {
1049 if (d->d_tag == DT_NEEDED) {
1050 action(fix_dt_needed(elf_reader.get_string(d->d_un.d_val), elf_reader.name()));
1051 }
1052 }
1053}
1054
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001055static bool load_library(android_namespace_t* ns,
1056 LoadTask* task,
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001057 LoadTaskList* load_tasks,
1058 int rtld_flags,
1059 const std::string& realpath) {
1060 off64_t file_offset = task->get_file_offset();
1061 const char* name = task->get_name();
1062 const android_dlextinfo* extinfo = task->get_extinfo();
1063
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001064 if ((file_offset % PAGE_SIZE) != 0) {
Dmitriy Ivanova6c12792014-10-21 12:09:18 -07001065 DL_ERR("file offset for the library \"%s\" is not page-aligned: %" PRId64, name, file_offset);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001066 return false;
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001067 }
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001068 if (file_offset < 0) {
1069 DL_ERR("file offset for the library \"%s\" is negative: %" PRId64, name, file_offset);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001070 return false;
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001071 }
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001072
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001073 struct stat file_stat;
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001074 if (TEMP_FAILURE_RETRY(fstat(task->get_fd(), &file_stat)) != 0) {
Dmitriy Ivanova6c12792014-10-21 12:09:18 -07001075 DL_ERR("unable to stat file for the library \"%s\": %s", name, strerror(errno));
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001076 return false;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001077 }
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001078 if (file_offset >= file_stat.st_size) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07001079 DL_ERR("file offset for the library \"%s\" >= file size: %" PRId64 " >= %" PRId64,
1080 name, file_offset, file_stat.st_size);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001081 return false;
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001082 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001083
1084 // Check for symlink and other situations where
Dmitriy Ivanov9b821362015-04-02 16:03:56 -07001085 // file can have different names, unless ANDROID_DLEXT_FORCE_LOAD is set
1086 if (extinfo == nullptr || (extinfo->flags & ANDROID_DLEXT_FORCE_LOAD) == 0) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001087 auto predicate = [&](soinfo* si) {
1088 return si->get_st_dev() != 0 &&
1089 si->get_st_ino() != 0 &&
1090 si->get_st_dev() == file_stat.st_dev &&
1091 si->get_st_ino() == file_stat.st_ino &&
1092 si->get_file_offset() == file_offset;
1093 };
1094
1095 soinfo* si = ns->soinfo_list().find_if(predicate);
1096
1097 // check public namespace
1098 if (si == nullptr) {
1099 si = g_public_namespace.find_if(predicate);
1100 if (si != nullptr) {
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001101 ns->add_soinfo(si);
Dmitriy Ivanov9b821362015-04-02 16:03:56 -07001102 }
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07001103 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001104
1105 if (si != nullptr) {
1106 TRACE("library \"%s\" is already loaded under different name/path \"%s\" - "
1107 "will return existing soinfo", name, si->get_realpath());
1108 task->set_soinfo(si);
1109 return true;
1110 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001111 }
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07001112
Dmitriy Ivanove8ba50f2014-09-15 17:00:10 -07001113 if ((rtld_flags & RTLD_NOLOAD) != 0) {
Dmitriy Ivanova6ac54a2014-09-09 10:21:42 -07001114 DL_ERR("library \"%s\" wasn't loaded and RTLD_NOLOAD prevented it", name);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001115 return false;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001116 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001117
Dimitry Ivanov22840aa2015-12-04 18:28:49 -08001118 if (!ns->is_accessible(realpath)) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001119 // TODO(dimitry): workaround for http://b/26394120 - the grey-list
1120 const soinfo* needed_by = task->is_dt_needed() ? task->get_needed_by() : nullptr;
1121 if (is_greylisted(name, needed_by)) {
1122 // print warning only if needed by non-system library
1123 if (needed_by == nullptr || !is_system_library(needed_by->get_realpath())) {
1124 const soinfo* needed_or_dlopened_by = task->get_needed_by();
1125 const char* sopath = needed_or_dlopened_by == nullptr ? "(unknown)" :
1126 needed_or_dlopened_by->get_realpath();
1127 DL_WARN("library \"%s\" (\"%s\") needed or dlopened by \"%s\" is not accessible for the namespace \"%s\""
1128 " - the access is temporarily granted as a workaround for http://b/26394120, note that the access"
1129 " will be removed in future releases of Android.",
1130 name, realpath.c_str(), sopath, ns->get_name());
1131 add_dlwarning(sopath, "unauthorized access to", name);
1132 }
1133 } else {
1134 // do not load libraries if they are not accessible for the specified namespace.
1135 const char* needed_or_dlopened_by = task->get_needed_by() == nullptr ?
1136 "(unknown)" :
1137 task->get_needed_by()->get_realpath();
Dimitry Ivanovd17a3772016-03-01 13:11:28 -08001138
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001139 DL_ERR("library \"%s\" needed or dlopened by \"%s\" is not accessible for the namespace \"%s\"",
1140 name, needed_or_dlopened_by, ns->get_name());
Dimitry Ivanovd17a3772016-03-01 13:11:28 -08001141
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001142 PRINT("library \"%s\" (\"%s\") needed or dlopened by \"%s\" is not accessible for the"
1143 " namespace: [name=\"%s\", ld_library_paths=\"%s\", default_library_paths=\"%s\","
1144 " permitted_paths=\"%s\"]",
1145 name, realpath.c_str(),
1146 needed_or_dlopened_by,
1147 ns->get_name(),
1148 android::base::Join(ns->get_ld_library_paths(), ':').c_str(),
1149 android::base::Join(ns->get_default_library_paths(), ':').c_str(),
1150 android::base::Join(ns->get_permitted_paths(), ':').c_str());
1151 return false;
1152 }
Dimitry Ivanov22840aa2015-12-04 18:28:49 -08001153 }
1154
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001155 soinfo* si = soinfo_alloc(ns, realpath.c_str(), &file_stat, file_offset, rtld_flags);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001156 if (si == nullptr) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001157 return false;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001158 }
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07001159
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001160 task->set_soinfo(si);
1161
1162 // Read the ELF header and some of the segments.
1163 if (!task->read(realpath.c_str(), file_stat.st_size)) {
Dmitriy Ivanovfd7a91e2015-11-06 10:44:37 -08001164 soinfo_free(si);
1165 task->set_soinfo(nullptr);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001166 return false;
1167 }
1168
1169 // find and set DT_RUNPATH and dt_soname
1170 // Note that these field values are temporary and are
1171 // going to be overwritten on soinfo::prelink_image
1172 // with values from PT_LOAD segments.
1173 const ElfReader& elf_reader = task->get_elf_reader();
1174 for (const ElfW(Dyn)* d = elf_reader.dynamic(); d->d_tag != DT_NULL; ++d) {
1175 if (d->d_tag == DT_RUNPATH) {
1176 si->set_dt_runpath(elf_reader.get_string(d->d_un.d_val));
1177 }
1178 if (d->d_tag == DT_SONAME) {
1179 si->set_soname(elf_reader.get_string(d->d_un.d_val));
1180 }
1181 }
1182
1183 for_each_dt_needed(task->get_elf_reader(), [&](const char* name) {
1184 load_tasks->push_back(LoadTask::create(name, si, task->get_readers_map()));
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001185 });
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07001186
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001187 return true;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001188}
1189
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001190static bool load_library(android_namespace_t* ns,
1191 LoadTask* task,
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001192 ZipArchiveCache* zip_archive_cache,
1193 LoadTaskList* load_tasks,
1194 int rtld_flags) {
1195 const char* name = task->get_name();
1196 soinfo* needed_by = task->get_needed_by();
1197 const android_dlextinfo* extinfo = task->get_extinfo();
1198
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001199 off64_t file_offset;
1200 std::string realpath;
Spencer Low0346ad72015-04-22 18:06:51 -07001201 if (extinfo != nullptr && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) {
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001202 file_offset = 0;
Spencer Low0346ad72015-04-22 18:06:51 -07001203 if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
1204 file_offset = extinfo->library_fd_offset;
1205 }
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001206
1207 if (!realpath_fd(extinfo->library_fd, &realpath)) {
1208 PRINT("warning: unable to get realpath for the library \"%s\" by extinfo->library_fd. "
1209 "Will use given name.", name);
1210 realpath = name;
1211 }
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001212
1213 task->set_fd(extinfo->library_fd, false);
1214 task->set_file_offset(file_offset);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001215 return load_library(ns, task, load_tasks, rtld_flags, realpath);
Spencer Low0346ad72015-04-22 18:06:51 -07001216 }
1217
1218 // Open the file.
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001219 int fd = open_library(ns, zip_archive_cache, name, needed_by, &file_offset, &realpath);
Spencer Low0346ad72015-04-22 18:06:51 -07001220 if (fd == -1) {
1221 DL_ERR("library \"%s\" not found", name);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001222 return false;
Spencer Low0346ad72015-04-22 18:06:51 -07001223 }
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001224
1225 task->set_fd(fd, true);
1226 task->set_file_offset(file_offset);
1227
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001228 return load_library(ns, task, load_tasks, rtld_flags, realpath);
Spencer Low0346ad72015-04-22 18:06:51 -07001229}
1230
Dimitry Ivanov3bd90612017-02-01 08:54:43 -08001231// Returns true if library was found and false otherwise
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001232static bool find_loaded_library_by_soname(android_namespace_t* ns,
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -07001233 const char* name, soinfo** candidate) {
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001234 *candidate = nullptr;
1235
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07001236 // Ignore filename with path.
1237 if (strchr(name, '/') != nullptr) {
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001238 return false;
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07001239 }
1240
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001241 return !ns->soinfo_list().visit([&](soinfo* si) {
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07001242 const char* soname = si->get_soname();
1243 if (soname != nullptr && (strcmp(name, soname) == 0)) {
Dimitry Ivanov3bd90612017-02-01 08:54:43 -08001244 *candidate = si;
1245 return false;
Ard Biesheuvel12c78bb2012-08-14 12:30:09 +02001246 }
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001247
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001248 return true;
1249 });
Ard Biesheuvel12c78bb2012-08-14 12:30:09 +02001250}
1251
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001252static bool find_library_internal(android_namespace_t* ns,
1253 LoadTask* task,
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001254 ZipArchiveCache* zip_archive_cache,
1255 LoadTaskList* load_tasks,
1256 int rtld_flags) {
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001257 soinfo* candidate;
1258
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001259 if (find_loaded_library_by_soname(ns, task->get_name(), &candidate)) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001260 task->set_soinfo(candidate);
1261 return true;
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001262 }
Dmitriy Ivanovb648a8a2014-05-19 15:06:58 -07001263
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001264 if (ns != &g_default_namespace) {
1265 // check public namespace
1266 candidate = g_public_namespace.find_if([&](soinfo* si) {
1267 return strcmp(task->get_name(), si->get_soname()) == 0;
1268 });
1269
1270 if (candidate != nullptr) {
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001271 ns->add_soinfo(candidate);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001272 task->set_soinfo(candidate);
1273 return true;
1274 }
1275 }
1276
Dmitriy Ivanovb648a8a2014-05-19 15:06:58 -07001277 // Library might still be loaded, the accurate detection
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001278 // of this fact is done by load_library.
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001279 TRACE("[ \"%s\" find_loaded_library_by_soname failed (*candidate=%s@%p). Trying harder...]",
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001280 task->get_name(), candidate == nullptr ? "n/a" : candidate->get_realpath(), candidate);
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001281
Dimitry Ivanov3bd90612017-02-01 08:54:43 -08001282 return load_library(ns, task, zip_archive_cache, load_tasks, rtld_flags);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001283}
1284
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001285static void soinfo_unload(soinfo* si);
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001286static void soinfo_unload(soinfo* soinfos[], size_t count);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001287
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001288// TODO: this is slightly unusual way to construct
1289// the global group for relocation. Not every RTLD_GLOBAL
1290// library is included in this group for backwards-compatibility
1291// reasons.
1292//
1293// This group consists of the main executable, LD_PRELOADs
1294// and libraries with the DF_1_GLOBAL flag set.
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001295static soinfo_list_t make_global_group(android_namespace_t* ns) {
1296 soinfo_list_t global_group;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001297 ns->soinfo_list().for_each([&](soinfo* si) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001298 if ((si->get_dt_flags_1() & DF_1_GLOBAL) != 0) {
1299 global_group.push_back(si);
1300 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001301 });
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001302
1303 return global_group;
1304}
1305
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07001306// This function provides a list of libraries to be shared
1307// by the namespace. For the default namespace this is the global
1308// group (see make_global_group). For all others this is a group
1309// of RTLD_GLOBAL libraries (which includes the global group from
1310// the default namespace).
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001311static soinfo_list_t get_shared_group(android_namespace_t* ns) {
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07001312 if (ns == &g_default_namespace) {
1313 return make_global_group(ns);
1314 }
1315
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001316 soinfo_list_t shared_group;
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07001317 ns->soinfo_list().for_each([&](soinfo* si) {
1318 if ((si->get_rtld_flags() & RTLD_GLOBAL) != 0) {
1319 shared_group.push_back(si);
1320 }
1321 });
1322
1323 return shared_group;
1324}
1325
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001326static void shuffle(std::vector<LoadTask*>* v) {
1327 for (size_t i = 0, size = v->size(); i < size; ++i) {
1328 size_t n = size - i;
1329 size_t r = arc4random_uniform(n);
1330 std::swap((*v)[n-1], (*v)[r]);
1331 }
1332}
1333
Evgenii Stepanov0cdef7e2015-07-06 17:56:31 -07001334// add_as_children - add first-level loaded libraries (i.e. library_names[], but
1335// not their transitive dependencies) as children of the start_with library.
1336// This is false when find_libraries is called for dlopen(), when newly loaded
1337// libraries must form a disjoint tree.
Dimitry Ivanov3f660572016-09-09 10:00:39 -07001338bool find_libraries(android_namespace_t* ns,
1339 soinfo* start_with,
1340 const char* const library_names[],
1341 size_t library_names_count,
1342 soinfo* soinfos[],
1343 std::vector<soinfo*>* ld_preloads,
1344 size_t ld_preloads_count,
1345 int rtld_flags,
1346 const android_dlextinfo* extinfo,
1347 bool add_as_children) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001348 // Step 0: prepare.
1349 LoadTaskList load_tasks;
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001350 std::unordered_map<const soinfo*, ElfReader> readers_map;
1351
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001352 for (size_t i = 0; i < library_names_count; ++i) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001353 const char* name = library_names[i];
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001354 load_tasks.push_back(LoadTask::create(name, start_with, &readers_map));
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001355 }
1356
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001357 // Construct global_group.
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001358 soinfo_list_t global_group = make_global_group(ns);
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001359
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001360 // If soinfos array is null allocate one on stack.
1361 // The array is needed in case of failure; for example
1362 // when library_names[] = {libone.so, libtwo.so} and libone.so
1363 // is loaded correctly but libtwo.so failed for some reason.
1364 // In this case libone.so should be unloaded on return.
1365 // See also implementation of failure_guard below.
1366
1367 if (soinfos == nullptr) {
1368 size_t soinfos_size = sizeof(soinfo*)*library_names_count;
1369 soinfos = reinterpret_cast<soinfo**>(alloca(soinfos_size));
1370 memset(soinfos, 0, soinfos_size);
1371 }
1372
1373 // list of libraries to link - see step 2.
1374 size_t soinfos_count = 0;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001375
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001376 auto scope_guard = make_scope_guard([&]() {
1377 for (LoadTask* t : load_tasks) {
1378 LoadTask::deleter(t);
1379 }
1380 });
1381
Dmitriy Ivanovd9ff7222014-09-08 16:22:22 -07001382 auto failure_guard = make_scope_guard([&]() {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001383 // Housekeeping
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001384 soinfo_unload(soinfos, soinfos_count);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001385 });
1386
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001387 ZipArchiveCache zip_archive_cache;
1388
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001389 // Step 1: expand the list of load_tasks to include
1390 // all DT_NEEDED libraries (do not load them just yet)
1391 for (size_t i = 0; i<load_tasks.size(); ++i) {
1392 LoadTask* task = load_tasks[i];
Evgenii Stepanov68650822015-06-10 13:38:39 -07001393 soinfo* needed_by = task->get_needed_by();
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001394
Dmitriy Ivanovedfc9f62015-09-02 16:32:02 -07001395 bool is_dt_needed = needed_by != nullptr && (needed_by != start_with || add_as_children);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001396 task->set_extinfo(is_dt_needed ? nullptr : extinfo);
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001397 task->set_dt_needed(is_dt_needed);
Dmitriy Ivanovedfc9f62015-09-02 16:32:02 -07001398
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001399 if(!find_library_internal(ns, task, &zip_archive_cache, &load_tasks, rtld_flags)) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001400 return false;
1401 }
1402
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001403 soinfo* si = task->get_soinfo();
1404
Dmitriy Ivanovedfc9f62015-09-02 16:32:02 -07001405 if (is_dt_needed) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001406 needed_by->add_child(si);
1407 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001408
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001409 if (si->is_linked()) {
1410 si->increment_ref_count();
1411 }
1412
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001413 // When ld_preloads is not null, the first
1414 // ld_preloads_count libs are in fact ld_preloads.
1415 if (ld_preloads != nullptr && soinfos_count < ld_preloads_count) {
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07001416 ld_preloads->push_back(si);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001417 }
1418
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001419 if (soinfos_count < library_names_count) {
1420 soinfos[soinfos_count++] = si;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001421 }
1422 }
1423
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001424 // Step 2: Load libraries in random order (see b/24047022)
1425 LoadTaskList load_list;
1426 for (auto&& task : load_tasks) {
1427 soinfo* si = task->get_soinfo();
1428 auto pred = [&](const LoadTask* t) {
1429 return t->get_soinfo() == si;
1430 };
1431
1432 if (!si->is_linked() &&
1433 std::find_if(load_list.begin(), load_list.end(), pred) == load_list.end() ) {
1434 load_list.push_back(task);
1435 }
1436 }
1437 shuffle(&load_list);
1438
1439 for (auto&& task : load_list) {
1440 if (!task->load()) {
1441 return false;
1442 }
1443 }
1444
1445 // Step 3: pre-link all DT_NEEDED libraries in breadth first order.
1446 for (auto&& task : load_tasks) {
1447 soinfo* si = task->get_soinfo();
1448 if (!si->is_linked() && !si->prelink_image()) {
1449 return false;
1450 }
1451 }
1452
1453 // Step 4: Add LD_PRELOADed libraries to the global group for
1454 // future runs. There is no need to explicitly add them to
1455 // the global group for this run because they are going to
1456 // appear in the local group in the correct order.
1457 if (ld_preloads != nullptr) {
1458 for (auto&& si : *ld_preloads) {
1459 si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL);
1460 }
1461 }
1462
1463
1464 // Step 5: link libraries.
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001465 soinfo_list_t local_group;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001466 walk_dependencies_tree(
Evgenii Stepanov0cdef7e2015-07-06 17:56:31 -07001467 (start_with != nullptr && add_as_children) ? &start_with : soinfos,
1468 (start_with != nullptr && add_as_children) ? 1 : soinfos_count,
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001469 [&] (soinfo* si) {
1470 local_group.push_back(si);
1471 return true;
1472 });
1473
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001474 // We need to increment ref_count in case
1475 // the root of the local group was not linked.
1476 bool was_local_group_root_linked = local_group.front()->is_linked();
1477
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001478 bool linked = local_group.visit([&](soinfo* si) {
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001479 if (!si->is_linked()) {
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -07001480 if (!si->link_image(global_group, local_group, extinfo) ||
1481 !get_cfi_shadow()->AfterLoad(si, solist_get_head())) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001482 return false;
1483 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001484 }
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001485
1486 return true;
1487 });
1488
1489 if (linked) {
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001490 local_group.for_each([](soinfo* si) {
1491 if (!si->is_linked()) {
1492 si->set_linked();
1493 }
1494 });
1495
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001496 failure_guard.disable();
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001497 }
1498
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001499 if (!was_local_group_root_linked) {
1500 local_group.front()->increment_ref_count();
1501 }
1502
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001503 return linked;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001504}
1505
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001506static soinfo* find_library(android_namespace_t* ns,
1507 const char* name, int rtld_flags,
Evgenii Stepanov0cdef7e2015-07-06 17:56:31 -07001508 const android_dlextinfo* extinfo,
1509 soinfo* needed_by) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001510 soinfo* si;
1511
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001512 if (name == nullptr) {
Dimitry Ivanov3f660572016-09-09 10:00:39 -07001513 si = solist_get_somain();
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001514 } else if (!find_libraries(ns, needed_by, &name, 1, &si, nullptr, 0, rtld_flags,
Evgenii Stepanov0cdef7e2015-07-06 17:56:31 -07001515 extinfo, /* add_as_children */ false)) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001516 return nullptr;
1517 }
1518
Elliott Hughesd23736e2012-11-01 15:16:56 -07001519 return si;
1520}
Elliott Hughesbedfe382012-08-14 14:07:59 -07001521
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001522static void soinfo_unload(soinfo* root) {
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001523 if (root->is_linked()) {
1524 root = root->get_local_group_root();
1525 }
1526
1527 if (!root->can_unload()) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001528 TRACE("not unloading \"%s\" - the binary is flagged with NODELETE", root->get_realpath());
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -07001529 return;
1530 }
1531
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001532 soinfo_unload(&root, 1);
1533}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001534
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001535static void soinfo_unload(soinfo* soinfos[], size_t count) {
1536 // Note that the library can be loaded but not linked;
1537 // in which case there is no root but we still need
1538 // to walk the tree and unload soinfos involved.
1539 //
1540 // This happens on unsuccessful dlopen, when one of
1541 // the DT_NEEDED libraries could not be linked/found.
1542 if (count == 0) {
1543 return;
1544 }
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001545
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001546 soinfo_list_t unload_list;
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001547 for (size_t i = 0; i < count; ++i) {
1548 soinfo* si = soinfos[i];
Dmitriy Ivanov5ae82cb2014-12-02 17:08:42 -08001549
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001550 if (si->can_unload()) {
1551 size_t ref_count = si->is_linked() ? si->decrement_ref_count() : 0;
1552 if (ref_count == 0) {
1553 unload_list.push_back(si);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001554 } else {
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001555 TRACE("not unloading '%s' group, decrementing ref_count to %zd",
1556 si->get_realpath(), ref_count);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001557 }
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001558 } else {
1559 TRACE("not unloading '%s' - the binary is flagged with NODELETE", si->get_realpath());
1560 return;
1561 }
1562 }
1563
1564 // This is used to identify soinfos outside of the load-group
1565 // note that we cannot have > 1 in the array and have any of them
1566 // linked. This is why we can safely use the first one.
1567 soinfo* root = soinfos[0];
1568
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001569 soinfo_list_t local_unload_list;
1570 soinfo_list_t external_unload_list;
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001571 soinfo* si = nullptr;
1572
1573 while ((si = unload_list.pop_front()) != nullptr) {
1574 if (local_unload_list.contains(si)) {
1575 continue;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001576 }
Elliott Hughesd23736e2012-11-01 15:16:56 -07001577
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001578 local_unload_list.push_back(si);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001579
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001580 if (si->has_min_version(0)) {
1581 soinfo* child = nullptr;
1582 while ((child = si->get_children().pop_front()) != nullptr) {
1583 TRACE("%s@%p needs to unload %s@%p", si->get_realpath(), si,
1584 child->get_realpath(), child);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001585
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001586 if (local_unload_list.contains(child)) {
1587 continue;
1588 } else if (child->is_linked() && child->get_local_group_root() != root) {
1589 external_unload_list.push_back(child);
1590 } else {
1591 unload_list.push_front(child);
1592 }
1593 }
1594 } else {
1595#if !defined(__work_around_b_24465209__)
1596 __libc_fatal("soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
1597#else
1598 PRINT("warning: soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
1599 for_each_dt_needed(si, [&] (const char* library_name) {
1600 TRACE("deprecated (old format of soinfo): %s needs to unload %s",
1601 si->get_realpath(), library_name);
1602
1603 soinfo* needed = find_library(si->get_primary_namespace(),
1604 library_name, RTLD_NOLOAD, nullptr, nullptr);
1605
1606 if (needed != nullptr) {
1607 // Not found: for example if symlink was deleted between dlopen and dlclose
1608 // Since we cannot really handle errors at this point - print and continue.
1609 PRINT("warning: couldn't find %s needed by %s on unload.",
1610 library_name, si->get_realpath());
1611 return;
1612 } else if (local_unload_list.contains(needed)) {
1613 // already visited
1614 return;
1615 } else if (needed->is_linked() && needed->get_local_group_root() != root) {
1616 // external group
1617 external_unload_list.push_back(needed);
1618 } else {
1619 // local group
1620 unload_list.push_front(needed);
1621 }
1622 });
1623#endif
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001624 }
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001625 }
1626
1627 local_unload_list.for_each([](soinfo* si) {
1628 si->call_destructors();
1629 });
1630
1631 while ((si = local_unload_list.pop_front()) != nullptr) {
1632 notify_gdb_of_unload(si);
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -07001633 get_cfi_shadow()->BeforeUnload(si);
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001634 soinfo_free(si);
1635 }
1636
1637 while ((si = external_unload_list.pop_front()) != nullptr) {
1638 soinfo_unload(si);
Dmitriy Ivanova2547052014-11-18 12:03:09 -08001639 }
1640}
1641
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001642static std::string symbol_display_name(const char* sym_name, const char* sym_ver) {
1643 if (sym_ver == nullptr) {
1644 return sym_name;
1645 }
1646
Dimitry Ivanov9cf99cb2015-12-11 14:22:24 -08001647 return std::string(sym_name) + ", version " + sym_ver;
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001648}
1649
Dimitry Ivanovaca299a2016-04-11 12:42:58 -07001650static android_namespace_t* get_caller_namespace(soinfo* caller) {
1651 return caller != nullptr ? caller->get_primary_namespace() : g_anonymous_namespace;
1652}
1653
Elliott Hughesa4aafd12014-01-13 16:37:47 -08001654void do_android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size) {
Christopher Ferris052fa3a2014-08-26 20:48:11 -07001655 // Use basic string manipulation calls to avoid snprintf.
1656 // snprintf indirectly calls pthread_getspecific to get the size of a buffer.
1657 // When debug malloc is enabled, this call returns 0. This in turn causes
1658 // snprintf to do nothing, which causes libraries to fail to load.
1659 // See b/17302493 for further details.
1660 // Once the above bug is fixed, this code can be modified to use
1661 // snprintf again.
Evgenii Stepanovd640b222015-07-10 17:54:01 -07001662 size_t required_len = 0;
1663 for (size_t i = 0; g_default_ld_paths[i] != nullptr; ++i) {
1664 required_len += strlen(g_default_ld_paths[i]) + 1;
1665 }
Christopher Ferris052fa3a2014-08-26 20:48:11 -07001666 if (buffer_size < required_len) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07001667 __libc_fatal("android_get_LD_LIBRARY_PATH failed, buffer too small: "
1668 "buffer len %zu, required len %zu", buffer_size, required_len);
Christopher Ferris052fa3a2014-08-26 20:48:11 -07001669 }
Evgenii Stepanovd640b222015-07-10 17:54:01 -07001670 char* end = buffer;
1671 for (size_t i = 0; g_default_ld_paths[i] != nullptr; ++i) {
1672 if (i > 0) *end++ = ':';
1673 end = stpcpy(end, g_default_ld_paths[i]);
1674 }
Elliott Hughesa4aafd12014-01-13 16:37:47 -08001675}
1676
Elliott Hughescade4c32012-12-20 14:42:14 -08001677void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path) {
Nick Kralevich6bb01b62015-03-07 13:37:05 -08001678 parse_LD_LIBRARY_PATH(ld_library_path);
Elliott Hughescade4c32012-12-20 14:42:14 -08001679}
1680
Dimitry Ivanovb996d602016-07-11 18:11:39 -07001681static std::string android_dlextinfo_to_string(const android_dlextinfo* info) {
1682 if (info == nullptr) {
1683 return "(null)";
1684 }
1685
1686 return android::base::StringPrintf("[flags=0x%" PRIx64 ","
1687 " reserved_addr=%p,"
1688 " reserved_size=0x%zx,"
1689 " relro_fd=%d,"
1690 " library_fd=%d,"
1691 " library_fd_offset=0x%" PRIx64 ","
1692 " library_namespace=%s@%p]",
1693 info->flags,
1694 info->reserved_addr,
1695 info->reserved_size,
1696 info->relro_fd,
1697 info->library_fd,
1698 info->library_fd_offset,
1699 (info->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0 ?
1700 (info->library_namespace != nullptr ?
1701 info->library_namespace->get_name() : "(null)") : "(n/a)",
1702 (info->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0 ?
1703 info->library_namespace : nullptr);
1704}
1705
Dimitry Ivanovd9e427c2016-11-22 16:55:25 -08001706void* do_dlopen(const char* name, int flags,
1707 const android_dlextinfo* extinfo,
1708 const void* caller_addr) {
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001709 soinfo* const caller = find_containing_library(caller_addr);
Dimitry Ivanovb996d602016-07-11 18:11:39 -07001710 android_namespace_t* ns = get_caller_namespace(caller);
1711
1712 LD_LOG(kLogDlopen,
1713 "dlopen(name=\"%s\", flags=0x%x, extinfo=%s, caller=\"%s\", caller_ns=%s@%p) ...",
1714 name,
1715 flags,
1716 android_dlextinfo_to_string(extinfo).c_str(),
1717 caller == nullptr ? "(null)" : caller->get_realpath(),
1718 ns == nullptr ? "(null)" : ns->get_name(),
1719 ns);
1720
1721 auto failure_guard = make_scope_guard([&]() {
1722 LD_LOG(kLogDlopen, "... dlopen failed: %s", linker_get_error_buffer());
1723 });
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001724
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -07001725 if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL|RTLD_NODELETE|RTLD_NOLOAD)) != 0) {
Elliott Hughese66190d2012-12-18 15:57:55 -08001726 DL_ERR("invalid flags to dlopen: %x", flags);
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07001727 return nullptr;
Elliott Hughese66190d2012-12-18 15:57:55 -08001728 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001729
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001730 if (extinfo != nullptr) {
1731 if ((extinfo->flags & ~(ANDROID_DLEXT_VALID_FLAG_BITS)) != 0) {
1732 DL_ERR("invalid extended flags to android_dlopen_ext: 0x%" PRIx64, extinfo->flags);
1733 return nullptr;
1734 }
Dmitriy Ivanov126af752015-10-07 16:34:20 -07001735
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001736 if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) == 0 &&
Dmitriy Ivanova6c12792014-10-21 12:09:18 -07001737 (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07001738 DL_ERR("invalid extended flag combination (ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET without "
1739 "ANDROID_DLEXT_USE_LIBRARY_FD): 0x%" PRIx64, extinfo->flags);
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001740 return nullptr;
1741 }
Dmitriy Ivanov126af752015-10-07 16:34:20 -07001742
1743 if ((extinfo->flags & ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS) != 0 &&
1744 (extinfo->flags & (ANDROID_DLEXT_RESERVED_ADDRESS | ANDROID_DLEXT_RESERVED_ADDRESS_HINT)) != 0) {
1745 DL_ERR("invalid extended flag combination: ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS is not "
1746 "compatible with ANDROID_DLEXT_RESERVED_ADDRESS/ANDROID_DLEXT_RESERVED_ADDRESS_HINT");
1747 return nullptr;
1748 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001749
1750 if ((extinfo->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0) {
1751 if (extinfo->library_namespace == nullptr) {
1752 DL_ERR("ANDROID_DLEXT_USE_NAMESPACE is set but extinfo->library_namespace is null");
1753 return nullptr;
1754 }
1755 ns = extinfo->library_namespace;
1756 }
Torne (Richard Coles)012cb452014-02-06 14:34:21 +00001757 }
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -08001758
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -07001759 std::string asan_name_holder;
1760
1761 const char* translated_name = name;
Dimitry Ivanov6c14f862016-12-05 13:35:47 -08001762 if (g_is_asan && translated_name != nullptr && translated_name[0] == '/') {
1763 char translated_path[PATH_MAX];
1764 if (realpath(translated_name, translated_path) != nullptr) {
1765 if (file_is_in_dir(translated_path, kSystemLibDir)) {
1766 asan_name_holder = std::string(kAsanSystemLibDir) + "/" + basename(translated_path);
1767 if (file_exists(asan_name_holder.c_str())) {
1768 translated_name = asan_name_holder.c_str();
1769 PRINT("linker_asan dlopen translating \"%s\" -> \"%s\"", name, translated_name);
1770 }
1771 } else if (file_is_in_dir(translated_path, kVendorLibDir)) {
1772 asan_name_holder = std::string(kAsanVendorLibDir) + "/" + basename(translated_path);
1773 if (file_exists(asan_name_holder.c_str())) {
1774 translated_name = asan_name_holder.c_str();
1775 PRINT("linker_asan dlopen translating \"%s\" -> \"%s\"", name, translated_name);
1776 }
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -07001777 }
1778 }
1779 }
1780
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -08001781 ProtectedDataGuard guard;
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -07001782 soinfo* si = find_library(ns, translated_name, flags, extinfo, caller);
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07001783 if (si != nullptr) {
Dimitry Ivanovb996d602016-07-11 18:11:39 -07001784 void* handle = si->to_handle();
1785 LD_LOG(kLogDlopen,
Dimitry Ivanovae4a0c12016-11-21 10:44:35 -08001786 "... dlopen calling constructors: realpath=\"%s\", soname=\"%s\", handle=%p",
1787 si->get_realpath(), si->get_soname(), handle);
1788 si->call_constructors();
1789 failure_guard.disable();
1790 LD_LOG(kLogDlopen,
Dimitry Ivanovb996d602016-07-11 18:11:39 -07001791 "... dlopen successful: realpath=\"%s\", soname=\"%s\", handle=%p",
1792 si->get_realpath(), si->get_soname(), handle);
1793 return handle;
Elliott Hughesd23736e2012-11-01 15:16:56 -07001794 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001795
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001796 return nullptr;
Elliott Hughesd23736e2012-11-01 15:16:56 -07001797}
1798
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001799int do_dladdr(const void* addr, Dl_info* info) {
1800 // Determine if this address can be found in any library currently mapped.
1801 soinfo* si = find_containing_library(addr);
1802 if (si == nullptr) {
1803 return 0;
1804 }
1805
1806 memset(info, 0, sizeof(Dl_info));
1807
1808 info->dli_fname = si->get_realpath();
1809 // Address at which the shared object is loaded.
1810 info->dli_fbase = reinterpret_cast<void*>(si->base);
1811
1812 // Determine if any symbol in the library contains the specified address.
1813 ElfW(Sym)* sym = si->find_symbol_by_address(addr);
1814 if (sym != nullptr) {
1815 info->dli_sname = si->get_string(sym->st_name);
1816 info->dli_saddr = reinterpret_cast<void*>(si->resolve_symbol_address(sym));
1817 }
1818
1819 return 1;
1820}
1821
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001822static soinfo* soinfo_from_handle(void* handle) {
1823 if ((reinterpret_cast<uintptr_t>(handle) & 1) != 0) {
1824 auto it = g_soinfo_handles_map.find(reinterpret_cast<uintptr_t>(handle));
1825 if (it == g_soinfo_handles_map.end()) {
1826 return nullptr;
1827 } else {
1828 return it->second;
1829 }
1830 }
1831
1832 return static_cast<soinfo*>(handle);
1833}
1834
Dimitry Ivanovd9e427c2016-11-22 16:55:25 -08001835bool do_dlsym(void* handle,
1836 const char* sym_name,
1837 const char* sym_ver,
1838 const void* caller_addr,
1839 void** symbol) {
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001840#if !defined(__LP64__)
1841 if (handle == nullptr) {
1842 DL_ERR("dlsym failed: library handle is null");
1843 return false;
1844 }
1845#endif
1846
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001847 soinfo* found = nullptr;
1848 const ElfW(Sym)* sym = nullptr;
1849 soinfo* caller = find_containing_library(caller_addr);
Dimitry Ivanovaca299a2016-04-11 12:42:58 -07001850 android_namespace_t* ns = get_caller_namespace(caller);
Dimitry Ivanov4742abd2016-12-12 16:30:15 -08001851 soinfo* si = nullptr;
1852 if (handle != RTLD_DEFAULT && handle != RTLD_NEXT) {
1853 si = soinfo_from_handle(handle);
1854 }
1855
1856 LD_LOG(kLogDlsym,
1857 "dlsym(handle=%p(\"%s\"), sym_name=\"%s\", sym_ver=\"%s\", caller=\"%s\", caller_ns=%s@%p) ...",
1858 handle,
1859 si != nullptr ? si->get_realpath() : "n/a",
1860 sym_name,
1861 sym_ver,
1862 caller == nullptr ? "(null)" : caller->get_realpath(),
1863 ns == nullptr ? "(null)" : ns->get_name(),
1864 ns);
1865
1866 auto failure_guard = make_scope_guard([&]() {
1867 LD_LOG(kLogDlsym, "... dlsym failed: %s", linker_get_error_buffer());
1868 });
1869
1870 if (sym_name == nullptr) {
1871 DL_ERR("dlsym failed: symbol name is null");
1872 return false;
1873 }
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001874
1875 version_info vi_instance;
1876 version_info* vi = nullptr;
1877
1878 if (sym_ver != nullptr) {
Dimitry Ivanov9cf99cb2015-12-11 14:22:24 -08001879 vi_instance.name = sym_ver;
1880 vi_instance.elf_hash = calculate_elf_hash(sym_ver);
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001881 vi = &vi_instance;
1882 }
1883
1884 if (handle == RTLD_DEFAULT || handle == RTLD_NEXT) {
1885 sym = dlsym_linear_lookup(ns, sym_name, vi, &found, caller, handle);
1886 } else {
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001887 if (si == nullptr) {
1888 DL_ERR("dlsym failed: invalid handle: %p", handle);
1889 return false;
1890 }
1891 sym = dlsym_handle_lookup(si, &found, sym_name, vi);
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001892 }
1893
1894 if (sym != nullptr) {
1895 uint32_t bind = ELF_ST_BIND(sym->st_info);
1896
1897 if ((bind == STB_GLOBAL || bind == STB_WEAK) && sym->st_shndx != 0) {
1898 *symbol = reinterpret_cast<void*>(found->resolve_symbol_address(sym));
Dimitry Ivanov4742abd2016-12-12 16:30:15 -08001899 failure_guard.disable();
1900 LD_LOG(kLogDlsym,
1901 "... dlsym successful: sym_name=\"%s\", sym_ver=\"%s\", found in=\"%s\", address=%p",
1902 sym_name, sym_ver, found->get_soname(), *symbol);
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001903 return true;
1904 }
1905
1906 DL_ERR("symbol \"%s\" found but not global", symbol_display_name(sym_name, sym_ver).c_str());
1907 return false;
1908 }
1909
1910 DL_ERR("undefined symbol: %s", symbol_display_name(sym_name, sym_ver).c_str());
1911 return false;
1912}
1913
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001914int do_dlclose(void* handle) {
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -08001915 ProtectedDataGuard guard;
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001916 soinfo* si = soinfo_from_handle(handle);
1917 if (si == nullptr) {
1918 DL_ERR("invalid handle: %p", handle);
1919 return -1;
1920 }
1921
Dmitriy Ivanovb648a8a2014-05-19 15:06:58 -07001922 soinfo_unload(si);
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001923 return 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001924}
1925
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08001926bool init_namespaces(const char* public_ns_sonames, const char* anon_ns_library_path) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001927 if (g_public_namespace_initialized) {
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08001928 DL_ERR("public namespace has already been initialized.");
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001929 return false;
1930 }
1931
Dimitry Ivanov54807612016-04-21 14:57:38 -07001932 if (public_ns_sonames == nullptr || public_ns_sonames[0] == '\0') {
1933 DL_ERR("error initializing public namespace: the list of public libraries is empty.");
1934 return false;
1935 }
1936
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08001937 std::vector<std::string> sonames = android::base::Split(public_ns_sonames, ":");
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001938
1939 ProtectedDataGuard guard;
1940
1941 auto failure_guard = make_scope_guard([&]() {
1942 g_public_namespace.clear();
1943 });
1944
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001945 for (const auto& soname : sonames) {
Dmitriy Ivanov3cc35e22015-11-17 18:36:50 -08001946 soinfo* candidate = nullptr;
1947
1948 find_loaded_library_by_soname(&g_default_namespace, soname.c_str(), &candidate);
1949
1950 if (candidate == nullptr) {
Christopher Ferris523e2a92016-06-17 13:46:36 -07001951 DL_ERR("error initializing public namespace: a library with soname \"%s\""
1952 " was not found in the default namespace", soname.c_str());
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001953 return false;
1954 }
1955
1956 candidate->set_nodelete();
1957 g_public_namespace.push_back(candidate);
1958 }
1959
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001960 g_public_namespace_initialized = true;
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08001961
1962 // create anonymous namespace
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08001963 // When the caller is nullptr - create_namespace will take global group
1964 // from the anonymous namespace, which is fine because anonymous namespace
1965 // is still pointing to the default one.
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08001966 android_namespace_t* anon_ns =
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08001967 create_namespace(nullptr, "(anonymous)", nullptr, anon_ns_library_path,
Dimitry Ivanov52408632016-05-23 10:31:11 -07001968 ANDROID_NAMESPACE_TYPE_REGULAR, nullptr, &g_default_namespace);
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08001969
1970 if (anon_ns == nullptr) {
1971 g_public_namespace_initialized = false;
1972 return false;
1973 }
1974 g_anonymous_namespace = anon_ns;
1975 failure_guard.disable();
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001976 return true;
1977}
1978
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001979static void add_soinfos_to_namespace(const soinfo_list_t& soinfos, android_namespace_t* ns) {
1980 ns->add_soinfos(soinfos);
1981 for (auto si : soinfos) {
1982 si->add_secondary_namespace(ns);
1983 }
1984}
1985
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08001986android_namespace_t* create_namespace(const void* caller_addr,
1987 const char* name,
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001988 const char* ld_library_path,
1989 const char* default_library_path,
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08001990 uint64_t type,
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07001991 const char* permitted_when_isolated_path,
1992 android_namespace_t* parent_namespace) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001993 if (!g_public_namespace_initialized) {
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08001994 DL_ERR("cannot create namespace: public namespace is not initialized.");
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001995 return nullptr;
1996 }
1997
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07001998 if (parent_namespace == nullptr) {
Dimitry Ivanov52408632016-05-23 10:31:11 -07001999 // if parent_namespace is nullptr -> set it to the caller namespace
2000 soinfo* caller_soinfo = find_containing_library(caller_addr);
2001
2002 parent_namespace = caller_soinfo != nullptr ?
2003 caller_soinfo->get_primary_namespace() :
2004 g_anonymous_namespace;
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002005 }
2006
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002007 ProtectedDataGuard guard;
2008 std::vector<std::string> ld_library_paths;
2009 std::vector<std::string> default_library_paths;
Dimitry Ivanov284ae352015-12-08 10:47:13 -08002010 std::vector<std::string> permitted_paths;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002011
2012 parse_path(ld_library_path, ":", &ld_library_paths);
2013 parse_path(default_library_path, ":", &default_library_paths);
Dimitry Ivanov284ae352015-12-08 10:47:13 -08002014 parse_path(permitted_when_isolated_path, ":", &permitted_paths);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002015
2016 android_namespace_t* ns = new (g_namespace_allocator.alloc()) android_namespace_t();
2017 ns->set_name(name);
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002018 ns->set_isolated((type & ANDROID_NAMESPACE_TYPE_ISOLATED) != 0);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002019 ns->set_ld_library_paths(std::move(ld_library_paths));
2020 ns->set_default_library_paths(std::move(default_library_paths));
Dimitry Ivanov284ae352015-12-08 10:47:13 -08002021 ns->set_permitted_paths(std::move(permitted_paths));
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002022
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002023 if ((type & ANDROID_NAMESPACE_TYPE_SHARED) != 0) {
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002024 // If shared - clone the parent namespace
Dimitry Ivanovb943f302016-08-03 16:00:10 -07002025 add_soinfos_to_namespace(parent_namespace->soinfo_list(), ns);
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002026 } else {
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002027 // If not shared - copy only the shared group
Dimitry Ivanovb943f302016-08-03 16:00:10 -07002028 add_soinfos_to_namespace(get_shared_group(parent_namespace), ns);
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002029 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002030
2031 return ns;
2032}
2033
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002034ElfW(Addr) call_ifunc_resolver(ElfW(Addr) resolver_addr) {
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07002035 typedef ElfW(Addr) (*ifunc_resolver_t)(void);
2036 ifunc_resolver_t ifunc_resolver = reinterpret_cast<ifunc_resolver_t>(resolver_addr);
2037 ElfW(Addr) ifunc_addr = ifunc_resolver();
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002038 TRACE_TYPE(RELO, "Called ifunc_resolver@%p. The result is %p",
2039 ifunc_resolver, reinterpret_cast<void*>(ifunc_addr));
Brigid Smithc5a13ef2014-07-23 11:22:25 -07002040
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07002041 return ifunc_addr;
Brigid Smithc5a13ef2014-07-23 11:22:25 -07002042}
Brigid Smithc5a13ef2014-07-23 11:22:25 -07002043
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002044const version_info* VersionTracker::get_version_info(ElfW(Versym) source_symver) const {
2045 if (source_symver < 2 ||
2046 source_symver >= version_infos.size() ||
2047 version_infos[source_symver].name == nullptr) {
2048 return nullptr;
2049 }
2050
2051 return &version_infos[source_symver];
2052}
2053
2054void VersionTracker::add_version_info(size_t source_index,
2055 ElfW(Word) elf_hash,
2056 const char* ver_name,
2057 const soinfo* target_si) {
2058 if (source_index >= version_infos.size()) {
2059 version_infos.resize(source_index+1);
2060 }
2061
2062 version_infos[source_index].elf_hash = elf_hash;
2063 version_infos[source_index].name = ver_name;
2064 version_infos[source_index].target_si = target_si;
2065}
2066
2067bool VersionTracker::init_verneed(const soinfo* si_from) {
2068 uintptr_t verneed_ptr = si_from->get_verneed_ptr();
2069
2070 if (verneed_ptr == 0) {
2071 return true;
2072 }
2073
2074 size_t verneed_cnt = si_from->get_verneed_cnt();
2075
2076 for (size_t i = 0, offset = 0; i<verneed_cnt; ++i) {
2077 const ElfW(Verneed)* verneed = reinterpret_cast<ElfW(Verneed)*>(verneed_ptr + offset);
2078 size_t vernaux_offset = offset + verneed->vn_aux;
2079 offset += verneed->vn_next;
2080
2081 if (verneed->vn_version != 1) {
2082 DL_ERR("unsupported verneed[%zd] vn_version: %d (expected 1)", i, verneed->vn_version);
2083 return false;
2084 }
2085
2086 const char* target_soname = si_from->get_string(verneed->vn_file);
2087 // find it in dependencies
2088 soinfo* target_si = si_from->get_children().find_if([&](const soinfo* si) {
Dmitriy Ivanov406d9962015-05-06 11:05:27 -07002089 return si->get_soname() != nullptr && strcmp(si->get_soname(), target_soname) == 0;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002090 });
2091
2092 if (target_si == nullptr) {
2093 DL_ERR("cannot find \"%s\" from verneed[%zd] in DT_NEEDED list for \"%s\"",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002094 target_soname, i, si_from->get_realpath());
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002095 return false;
2096 }
2097
2098 for (size_t j = 0; j<verneed->vn_cnt; ++j) {
2099 const ElfW(Vernaux)* vernaux = reinterpret_cast<ElfW(Vernaux)*>(verneed_ptr + vernaux_offset);
2100 vernaux_offset += vernaux->vna_next;
2101
2102 const ElfW(Word) elf_hash = vernaux->vna_hash;
2103 const char* ver_name = si_from->get_string(vernaux->vna_name);
2104 ElfW(Half) source_index = vernaux->vna_other;
2105
2106 add_version_info(source_index, elf_hash, ver_name, target_si);
2107 }
2108 }
2109
2110 return true;
2111}
2112
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002113template <typename F>
2114static bool for_each_verdef(const soinfo* si, F functor) {
2115 if (!si->has_min_version(2)) {
2116 return true;
2117 }
2118
2119 uintptr_t verdef_ptr = si->get_verdef_ptr();
2120 if (verdef_ptr == 0) {
2121 return true;
2122 }
2123
2124 size_t offset = 0;
2125
2126 size_t verdef_cnt = si->get_verdef_cnt();
2127 for (size_t i = 0; i<verdef_cnt; ++i) {
2128 const ElfW(Verdef)* verdef = reinterpret_cast<ElfW(Verdef)*>(verdef_ptr + offset);
2129 size_t verdaux_offset = offset + verdef->vd_aux;
2130 offset += verdef->vd_next;
2131
2132 if (verdef->vd_version != 1) {
2133 DL_ERR("unsupported verdef[%zd] vd_version: %d (expected 1) library: %s",
2134 i, verdef->vd_version, si->get_realpath());
2135 return false;
2136 }
2137
2138 if ((verdef->vd_flags & VER_FLG_BASE) != 0) {
2139 // "this is the version of the file itself. It must not be used for
2140 // matching a symbol. It can be used to match references."
2141 //
2142 // http://www.akkadia.org/drepper/symbol-versioning
2143 continue;
2144 }
2145
2146 if (verdef->vd_cnt == 0) {
2147 DL_ERR("invalid verdef[%zd] vd_cnt == 0 (version without a name)", i);
2148 return false;
2149 }
2150
2151 const ElfW(Verdaux)* verdaux = reinterpret_cast<ElfW(Verdaux)*>(verdef_ptr + verdaux_offset);
2152
2153 if (functor(i, verdef, verdaux) == true) {
2154 break;
2155 }
2156 }
2157
2158 return true;
2159}
2160
2161bool find_verdef_version_index(const soinfo* si, const version_info* vi, ElfW(Versym)* versym) {
2162 if (vi == nullptr) {
2163 *versym = kVersymNotNeeded;
2164 return true;
2165 }
2166
2167 *versym = kVersymGlobal;
2168
2169 return for_each_verdef(si,
2170 [&](size_t, const ElfW(Verdef)* verdef, const ElfW(Verdaux)* verdaux) {
2171 if (verdef->vd_hash == vi->elf_hash &&
2172 strcmp(vi->name, si->get_string(verdaux->vda_name)) == 0) {
2173 *versym = verdef->vd_ndx;
2174 return true;
2175 }
2176
2177 return false;
2178 }
2179 );
2180}
2181
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002182bool VersionTracker::init_verdef(const soinfo* si_from) {
2183 return for_each_verdef(si_from,
2184 [&](size_t, const ElfW(Verdef)* verdef, const ElfW(Verdaux)* verdaux) {
2185 add_version_info(verdef->vd_ndx, verdef->vd_hash,
2186 si_from->get_string(verdaux->vda_name), si_from);
2187 return false;
2188 }
2189 );
2190}
2191
2192bool VersionTracker::init(const soinfo* si_from) {
2193 if (!si_from->has_min_version(2)) {
2194 return true;
2195 }
2196
2197 return init_verneed(si_from) && init_verdef(si_from);
2198}
2199
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002200// TODO (dimitry): Methods below need to be moved out of soinfo
2201// and in more isolated file in order minimize dependencies on
2202// unnecessary object in the linker binary. Consider making them
2203// independent from soinfo (?).
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002204bool soinfo::lookup_version_info(const VersionTracker& version_tracker, ElfW(Word) sym,
2205 const char* sym_name, const version_info** vi) {
2206 const ElfW(Versym)* sym_ver_ptr = get_versym(sym);
2207 ElfW(Versym) sym_ver = sym_ver_ptr == nullptr ? 0 : *sym_ver_ptr;
2208
2209 if (sym_ver != VER_NDX_LOCAL && sym_ver != VER_NDX_GLOBAL) {
2210 *vi = version_tracker.get_version_info(sym_ver);
2211
2212 if (*vi == nullptr) {
2213 DL_ERR("cannot find verneed/verdef for version index=%d "
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002214 "referenced by symbol \"%s\" at \"%s\"", sym_ver, sym_name, get_realpath());
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002215 return false;
2216 }
2217 } else {
2218 // there is no version info
2219 *vi = nullptr;
2220 }
2221
2222 return true;
2223}
2224
Dimitry Ivanov576a3752016-08-09 06:58:55 -07002225#if !defined(__mips__)
2226#if defined(USE_RELA)
2227static ElfW(Addr) get_addend(ElfW(Rela)* rela, ElfW(Addr) reloc_addr __unused) {
2228 return rela->r_addend;
2229}
2230#else
2231static ElfW(Addr) get_addend(ElfW(Rel)* rel, ElfW(Addr) reloc_addr) {
2232 if (ELFW(R_TYPE)(rel->r_info) == R_GENERIC_RELATIVE ||
2233 ELFW(R_TYPE)(rel->r_info) == R_GENERIC_IRELATIVE) {
2234 return *reinterpret_cast<ElfW(Addr)*>(reloc_addr);
2235 }
2236 return 0;
2237}
2238#endif
2239
Dmitriy Ivanovfa26eee2015-02-03 16:06:47 -08002240template<typename ElfRelIteratorT>
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07002241bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& rel_iterator,
2242 const soinfo_list_t& global_group, const soinfo_list_t& local_group) {
Dmitriy Ivanovfa26eee2015-02-03 16:06:47 -08002243 for (size_t idx = 0; rel_iterator.has_next(); ++idx) {
2244 const auto rel = rel_iterator.next();
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002245 if (rel == nullptr) {
2246 return false;
2247 }
2248
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002249 ElfW(Word) type = ELFW(R_TYPE)(rel->r_info);
2250 ElfW(Word) sym = ELFW(R_SYM)(rel->r_info);
2251
2252 ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rel->r_offset + load_bias);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002253 ElfW(Addr) sym_addr = 0;
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07002254 const char* sym_name = nullptr;
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002255 ElfW(Addr) addend = get_addend(rel, reloc);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002256
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07002257 DEBUG("Processing \"%s\" relocation at index %zd", get_realpath(), idx);
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002258 if (type == R_GENERIC_NONE) {
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002259 continue;
2260 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002261
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002262 const ElfW(Sym)* s = nullptr;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002263 soinfo* lsi = nullptr;
2264
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002265 if (sym != 0) {
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002266 sym_name = get_string(symtab_[sym].st_name);
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002267 const version_info* vi = nullptr;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002268
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002269 if (!lookup_version_info(version_tracker, sym, sym_name, &vi)) {
2270 return false;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002271 }
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002272
2273 if (!soinfo_do_lookup(this, sym_name, vi, &lsi, global_group, local_group, &s)) {
2274 return false;
2275 }
2276
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07002277 if (s == nullptr) {
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002278 // We only allow an undefined symbol if this is a weak reference...
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002279 s = &symtab_[sym];
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002280 if (ELF_ST_BIND(s->st_info) != STB_WEAK) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002281 DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, get_realpath());
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002282 return false;
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002283 }
2284
2285 /* IHI0044C AAELF 4.5.1.1:
2286
2287 Libraries are not searched to resolve weak references.
2288 It is not an error for a weak reference to remain unsatisfied.
2289
2290 During linking, the value of an undefined weak reference is:
2291 - Zero if the relocation type is absolute
2292 - The address of the place if the relocation is pc-relative
2293 - The address of nominal base address if the relocation
2294 type is base-relative.
2295 */
2296
2297 switch (type) {
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002298 case R_GENERIC_JUMP_SLOT:
2299 case R_GENERIC_GLOB_DAT:
2300 case R_GENERIC_RELATIVE:
2301 case R_GENERIC_IRELATIVE:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002302#if defined(__aarch64__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002303 case R_AARCH64_ABS64:
2304 case R_AARCH64_ABS32:
2305 case R_AARCH64_ABS16:
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002306#elif defined(__x86_64__)
2307 case R_X86_64_32:
2308 case R_X86_64_64:
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002309#elif defined(__arm__)
2310 case R_ARM_ABS32:
2311#elif defined(__i386__)
2312 case R_386_32:
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002313#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002314 /*
2315 * The sym_addr was initialized to be zero above, or the relocation
2316 * code below does not care about value of sym_addr.
2317 * No need to do anything.
2318 */
2319 break;
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002320#if defined(__x86_64__)
Dimitry Ivanovd338aac2015-01-13 22:31:54 +00002321 case R_X86_64_PC32:
2322 sym_addr = reloc;
2323 break;
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002324#elif defined(__i386__)
2325 case R_386_PC32:
2326 sym_addr = reloc;
2327 break;
2328#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002329 default:
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002330 DL_ERR("unknown weak reloc type %d @ %p (%zu)", type, rel, idx);
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002331 return false;
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002332 }
Dmitriy Ivanovec83a612015-07-26 07:37:09 -07002333 } else { // We got a definition.
2334#if !defined(__LP64__)
2335 // When relocating dso with text_relocation .text segment is
2336 // not executable. We need to restore elf flags before resolving
2337 // STT_GNU_IFUNC symbol.
2338 bool protect_segments = has_text_relocations &&
2339 lsi == this &&
2340 ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC;
2341 if (protect_segments) {
2342 if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
2343 DL_ERR("can't protect segments for \"%s\": %s",
2344 get_realpath(), strerror(errno));
2345 return false;
2346 }
2347 }
2348#endif
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07002349 sym_addr = lsi->resolve_symbol_address(s);
Dmitriy Ivanovec83a612015-07-26 07:37:09 -07002350#if !defined(__LP64__)
2351 if (protect_segments) {
2352 if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
2353 DL_ERR("can't unprotect loadable segments for \"%s\": %s",
2354 get_realpath(), strerror(errno));
2355 return false;
2356 }
2357 }
2358#endif
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002359 }
2360 count_relocation(kRelocSymbol);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002361 }
2362
2363 switch (type) {
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002364 case R_GENERIC_JUMP_SLOT:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002365 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002366 MARK(rel->r_offset);
2367 TRACE_TYPE(RELO, "RELO JMP_SLOT %16p <- %16p %s\n",
2368 reinterpret_cast<void*>(reloc),
2369 reinterpret_cast<void*>(sym_addr + addend), sym_name);
2370
2371 *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002372 break;
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002373 case R_GENERIC_GLOB_DAT:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002374 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002375 MARK(rel->r_offset);
2376 TRACE_TYPE(RELO, "RELO GLOB_DAT %16p <- %16p %s\n",
2377 reinterpret_cast<void*>(reloc),
2378 reinterpret_cast<void*>(sym_addr + addend), sym_name);
2379 *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002380 break;
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002381 case R_GENERIC_RELATIVE:
2382 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002383 MARK(rel->r_offset);
2384 TRACE_TYPE(RELO, "RELO RELATIVE %16p <- %16p\n",
2385 reinterpret_cast<void*>(reloc),
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002386 reinterpret_cast<void*>(load_bias + addend));
2387 *reinterpret_cast<ElfW(Addr)*>(reloc) = (load_bias + addend);
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002388 break;
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002389 case R_GENERIC_IRELATIVE:
2390 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002391 MARK(rel->r_offset);
2392 TRACE_TYPE(RELO, "RELO IRELATIVE %16p <- %16p\n",
2393 reinterpret_cast<void*>(reloc),
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002394 reinterpret_cast<void*>(load_bias + addend));
Dmitriy Ivanovec83a612015-07-26 07:37:09 -07002395 {
2396#if !defined(__LP64__)
2397 // When relocating dso with text_relocation .text segment is
2398 // not executable. We need to restore elf flags for this
2399 // particular call.
2400 if (has_text_relocations) {
2401 if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
2402 DL_ERR("can't protect segments for \"%s\": %s",
2403 get_realpath(), strerror(errno));
2404 return false;
2405 }
2406 }
2407#endif
2408 ElfW(Addr) ifunc_addr = call_ifunc_resolver(load_bias + addend);
2409#if !defined(__LP64__)
2410 // Unprotect it afterwards...
2411 if (has_text_relocations) {
2412 if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
2413 DL_ERR("can't unprotect loadable segments for \"%s\": %s",
2414 get_realpath(), strerror(errno));
2415 return false;
2416 }
2417 }
2418#endif
2419 *reinterpret_cast<ElfW(Addr)*>(reloc) = ifunc_addr;
2420 }
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002421 break;
2422
2423#if defined(__aarch64__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002424 case R_AARCH64_ABS64:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002425 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002426 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002427 TRACE_TYPE(RELO, "RELO ABS64 %16llx <- %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002428 reloc, sym_addr + addend, sym_name);
2429 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend;
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002430 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002431 case R_AARCH64_ABS32:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002432 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002433 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002434 TRACE_TYPE(RELO, "RELO ABS32 %16llx <- %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002435 reloc, sym_addr + addend, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002436 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002437 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT32_MIN);
2438 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT32_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002439 if ((min_value <= (sym_addr + addend)) &&
2440 ((sym_addr + addend) <= max_value)) {
2441 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend;
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002442 } else {
2443 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002444 sym_addr + addend, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002445 return false;
2446 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002447 }
2448 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002449 case R_AARCH64_ABS16:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002450 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002451 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002452 TRACE_TYPE(RELO, "RELO ABS16 %16llx <- %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002453 reloc, sym_addr + addend, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002454 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002455 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN);
2456 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT16_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002457 if ((min_value <= (sym_addr + addend)) &&
2458 ((sym_addr + addend) <= max_value)) {
2459 *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002460 } else {
2461 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002462 sym_addr + addend, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002463 return false;
2464 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002465 }
2466 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002467 case R_AARCH64_PREL64:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002468 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002469 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002470 TRACE_TYPE(RELO, "RELO REL64 %16llx <- %16llx - %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002471 reloc, sym_addr + addend, rel->r_offset, sym_name);
2472 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset;
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002473 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002474 case R_AARCH64_PREL32:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002475 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002476 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002477 TRACE_TYPE(RELO, "RELO REL32 %16llx <- %16llx - %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002478 reloc, sym_addr + addend, rel->r_offset, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002479 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002480 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT32_MIN);
2481 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT32_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002482 if ((min_value <= (sym_addr + addend - rel->r_offset)) &&
2483 ((sym_addr + addend - rel->r_offset) <= max_value)) {
2484 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset;
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002485 } else {
2486 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002487 sym_addr + addend - rel->r_offset, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002488 return false;
2489 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002490 }
2491 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002492 case R_AARCH64_PREL16:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002493 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002494 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002495 TRACE_TYPE(RELO, "RELO REL16 %16llx <- %16llx - %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002496 reloc, sym_addr + addend, rel->r_offset, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002497 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002498 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN);
2499 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT16_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002500 if ((min_value <= (sym_addr + addend - rel->r_offset)) &&
2501 ((sym_addr + addend - rel->r_offset) <= max_value)) {
2502 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset;
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002503 } else {
2504 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002505 sym_addr + addend - rel->r_offset, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002506 return false;
2507 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002508 }
2509 break;
2510
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002511 case R_AARCH64_COPY:
Nick Kralevich76e289c2014-07-03 12:04:31 -07002512 /*
2513 * ET_EXEC is not supported so this should not happen.
2514 *
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002515 * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0056b/IHI0056B_aaelf64.pdf
Nick Kralevich76e289c2014-07-03 12:04:31 -07002516 *
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002517 * Section 4.6.11 "Dynamic relocations"
Nick Kralevich76e289c2014-07-03 12:04:31 -07002518 * R_AARCH64_COPY may only appear in executable objects where e_type is
2519 * set to ET_EXEC.
2520 */
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002521 DL_ERR("%s R_AARCH64_COPY relocations are not supported", get_realpath());
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002522 return false;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002523 case R_AARCH64_TLS_TPREL64:
Elliott Hughes0266ae52014-02-10 17:46:57 -08002524 TRACE_TYPE(RELO, "RELO TLS_TPREL64 *** %16llx <- %16llx - %16llx\n",
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002525 reloc, (sym_addr + addend), rel->r_offset);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002526 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002527 case R_AARCH64_TLS_DTPREL32:
Elliott Hughes0266ae52014-02-10 17:46:57 -08002528 TRACE_TYPE(RELO, "RELO TLS_DTPREL32 *** %16llx <- %16llx - %16llx\n",
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002529 reloc, (sym_addr + addend), rel->r_offset);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002530 break;
2531#elif defined(__x86_64__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002532 case R_X86_64_32:
2533 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002534 MARK(rel->r_offset);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002535 TRACE_TYPE(RELO, "RELO R_X86_64_32 %08zx <- +%08zx %s", static_cast<size_t>(reloc),
2536 static_cast<size_t>(sym_addr), sym_name);
Junichi Uekawaff35b1e2015-11-18 10:18:59 +09002537 *reinterpret_cast<Elf32_Addr*>(reloc) = sym_addr + addend;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002538 break;
2539 case R_X86_64_64:
2540 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002541 MARK(rel->r_offset);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002542 TRACE_TYPE(RELO, "RELO R_X86_64_64 %08zx <- +%08zx %s", static_cast<size_t>(reloc),
2543 static_cast<size_t>(sym_addr), sym_name);
Junichi Uekawaff35b1e2015-11-18 10:18:59 +09002544 *reinterpret_cast<Elf64_Addr*>(reloc) = sym_addr + addend;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002545 break;
2546 case R_X86_64_PC32:
2547 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002548 MARK(rel->r_offset);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002549 TRACE_TYPE(RELO, "RELO R_X86_64_PC32 %08zx <- +%08zx (%08zx - %08zx) %s",
2550 static_cast<size_t>(reloc), static_cast<size_t>(sym_addr - reloc),
2551 static_cast<size_t>(sym_addr), static_cast<size_t>(reloc), sym_name);
Junichi Uekawaff35b1e2015-11-18 10:18:59 +09002552 *reinterpret_cast<Elf32_Addr*>(reloc) = sym_addr + addend - reloc;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002553 break;
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002554#elif defined(__arm__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002555 case R_ARM_ABS32:
2556 count_relocation(kRelocAbsolute);
2557 MARK(rel->r_offset);
2558 TRACE_TYPE(RELO, "RELO ABS %08x <- %08x %s", reloc, sym_addr, sym_name);
2559 *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
2560 break;
2561 case R_ARM_REL32:
2562 count_relocation(kRelocRelative);
2563 MARK(rel->r_offset);
2564 TRACE_TYPE(RELO, "RELO REL32 %08x <- %08x - %08x %s",
2565 reloc, sym_addr, rel->r_offset, sym_name);
2566 *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr - rel->r_offset;
2567 break;
2568 case R_ARM_COPY:
2569 /*
2570 * ET_EXEC is not supported so this should not happen.
2571 *
2572 * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044d/IHI0044D_aaelf.pdf
2573 *
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002574 * Section 4.6.1.10 "Dynamic relocations"
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002575 * R_ARM_COPY may only appear in executable objects where e_type is
2576 * set to ET_EXEC.
2577 */
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002578 DL_ERR("%s R_ARM_COPY relocations are not supported", get_realpath());
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002579 return false;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002580#elif defined(__i386__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002581 case R_386_32:
2582 count_relocation(kRelocRelative);
2583 MARK(rel->r_offset);
2584 TRACE_TYPE(RELO, "RELO R_386_32 %08x <- +%08x %s", reloc, sym_addr, sym_name);
2585 *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
2586 break;
2587 case R_386_PC32:
2588 count_relocation(kRelocRelative);
2589 MARK(rel->r_offset);
2590 TRACE_TYPE(RELO, "RELO R_386_PC32 %08x <- +%08x (%08x - %08x) %s",
2591 reloc, (sym_addr - reloc), sym_addr, reloc, sym_name);
2592 *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr - reloc);
2593 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002594#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002595 default:
2596 DL_ERR("unknown reloc type %d @ %p (%zu)", type, rel, idx);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002597 return false;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002598 }
2599 }
2600 return true;
Raghu Gandhamd7daacb2012-07-31 12:07:22 -07002601}
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002602#endif // !defined(__mips__)
Raghu Gandhamd7daacb2012-07-31 12:07:22 -07002603
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002604// An empty list of soinfos
Dimitry Ivanovb943f302016-08-03 16:00:10 -07002605static soinfo_list_t g_empty_list;
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07002606
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002607bool soinfo::prelink_image() {
Ningsheng Jiane93be992014-09-16 15:22:10 +08002608 /* Extract dynamic section */
2609 ElfW(Word) dynamic_flags = 0;
2610 phdr_table_get_dynamic_section(phdr, phnum, load_bias, &dynamic, &dynamic_flags);
Dmitriy Ivanov498eb182014-09-05 14:57:59 -07002611
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002612 /* We can't log anything until the linker is relocated */
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002613 bool relocating_linker = (flags_ & FLAG_LINKER) != 0;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002614 if (!relocating_linker) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07002615 INFO("[ Linking \"%s\" ]", get_realpath());
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002616 DEBUG("si->base = %p si->flags = 0x%08x", reinterpret_cast<void*>(base), flags_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002617 }
2618
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002619 if (dynamic == nullptr) {
David 'Digit' Turnerb52e4382012-06-19 01:24:17 +02002620 if (!relocating_linker) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002621 DL_ERR("missing PT_DYNAMIC in \"%s\"", get_realpath());
David 'Digit' Turnerb52e4382012-06-19 01:24:17 +02002622 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002623 return false;
2624 } else {
2625 if (!relocating_linker) {
2626 DEBUG("dynamic = %p", dynamic);
David 'Digit' Turner63f99f42012-06-19 00:08:39 +02002627 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002628 }
David 'Digit' Turner63f99f42012-06-19 00:08:39 +02002629
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07002630#if defined(__arm__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002631 (void) phdr_table_get_arm_exidx(phdr, phnum, load_bias,
2632 &ARM_exidx, &ARM_exidx_count);
David 'Digit' Turner63f99f42012-06-19 00:08:39 +02002633#endif
2634
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002635 // Extract useful information from dynamic section.
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07002636 // Note that: "Except for the DT_NULL element at the end of the array,
2637 // and the relative order of DT_NEEDED elements, entries may appear in any order."
2638 //
2639 // source: http://www.sco.com/developers/gabi/1998-04-29/ch5.dynamic.html
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002640 uint32_t needed_count = 0;
2641 for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
2642 DEBUG("d = %p, d[0](tag) = %p d[1](val) = %p",
2643 d, reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
2644 switch (d->d_tag) {
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002645 case DT_SONAME:
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07002646 // this is parsed after we have strtab initialized (see below).
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002647 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002648
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002649 case DT_HASH:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002650 nbucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0];
2651 nchain_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
2652 bucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8);
2653 chain_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8 + nbucket_ * 4);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002654 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002655
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002656 case DT_GNU_HASH:
Dmitriy Ivanov3597b802015-03-09 12:02:02 -07002657 gnu_nbucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0];
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002658 // skip symndx
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002659 gnu_maskwords_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[2];
2660 gnu_shift2_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[3];
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002661
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002662 gnu_bloom_filter_ = reinterpret_cast<ElfW(Addr)*>(load_bias + d->d_un.d_ptr + 16);
Dmitriy Ivanov3597b802015-03-09 12:02:02 -07002663 gnu_bucket_ = reinterpret_cast<uint32_t*>(gnu_bloom_filter_ + gnu_maskwords_);
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002664 // amend chain for symndx = header[1]
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002665 gnu_chain_ = gnu_bucket_ + gnu_nbucket_ -
2666 reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002667
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002668 if (!powerof2(gnu_maskwords_)) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002669 DL_ERR("invalid maskwords for gnu_hash = 0x%x, in \"%s\" expecting power to two",
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002670 gnu_maskwords_, get_realpath());
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002671 return false;
2672 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002673 --gnu_maskwords_;
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002674
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002675 flags_ |= FLAG_GNU_HASH;
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002676 break;
2677
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002678 case DT_STRTAB:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002679 strtab_ = reinterpret_cast<const char*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002680 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002681
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07002682 case DT_STRSZ:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002683 strtab_size_ = d->d_un.d_val;
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07002684 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002685
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002686 case DT_SYMTAB:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002687 symtab_ = reinterpret_cast<ElfW(Sym)*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002688 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002689
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002690 case DT_SYMENT:
2691 if (d->d_un.d_val != sizeof(ElfW(Sym))) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002692 DL_ERR("invalid DT_SYMENT: %zd in \"%s\"",
2693 static_cast<size_t>(d->d_un.d_val), get_realpath());
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002694 return false;
2695 }
2696 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002697
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002698 case DT_PLTREL:
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002699#if defined(USE_RELA)
2700 if (d->d_un.d_val != DT_RELA) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002701 DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_RELA", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002702 return false;
2703 }
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002704#else
2705 if (d->d_un.d_val != DT_REL) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002706 DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_REL", get_realpath());
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002707 return false;
2708 }
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002709#endif
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002710 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002711
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002712 case DT_JMPREL:
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07002713#if defined(USE_RELA)
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002714 plt_rela_ = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002715#else
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002716 plt_rel_ = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002717#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002718 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002719
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002720 case DT_PLTRELSZ:
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07002721#if defined(USE_RELA)
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002722 plt_rela_count_ = d->d_un.d_val / sizeof(ElfW(Rela));
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002723#else
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002724 plt_rel_count_ = d->d_un.d_val / sizeof(ElfW(Rel));
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002725#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002726 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002727
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002728 case DT_PLTGOT:
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002729#if defined(__mips__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002730 // Used by mips and mips64.
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002731 plt_got_ = reinterpret_cast<ElfW(Addr)**>(load_bias + d->d_un.d_ptr);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002732#endif
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002733 // Ignore for other platforms... (because RTLD_LAZY is not supported)
2734 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002735
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002736 case DT_DEBUG:
2737 // Set the DT_DEBUG entry to the address of _r_debug for GDB
2738 // if the dynamic table is writable
Chris Dearman99186652014-02-06 20:36:51 -08002739// FIXME: not working currently for N64
2740// The flags for the LOAD and DYNAMIC program headers do not agree.
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002741// The LOAD section containing the dynamic table has been mapped as
Chris Dearman99186652014-02-06 20:36:51 -08002742// read-only, but the DYNAMIC header claims it is writable.
2743#if !(defined(__mips__) && defined(__LP64__))
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002744 if ((dynamic_flags & PF_W) != 0) {
2745 d->d_un.d_val = reinterpret_cast<uintptr_t>(&_r_debug);
2746 }
Chris Dearman99186652014-02-06 20:36:51 -08002747#endif
Dmitriy Ivanovc6292ea2015-02-13 16:29:50 -08002748 break;
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07002749#if defined(USE_RELA)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002750 case DT_RELA:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002751 rela_ = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002752 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002753
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002754 case DT_RELASZ:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002755 rela_count_ = d->d_un.d_val / sizeof(ElfW(Rela));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002756 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002757
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002758 case DT_ANDROID_RELA:
2759 android_relocs_ = reinterpret_cast<uint8_t*>(load_bias + d->d_un.d_ptr);
2760 break;
2761
2762 case DT_ANDROID_RELASZ:
2763 android_relocs_size_ = d->d_un.d_val;
2764 break;
2765
2766 case DT_ANDROID_REL:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002767 DL_ERR("unsupported DT_ANDROID_REL in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002768 return false;
2769
2770 case DT_ANDROID_RELSZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002771 DL_ERR("unsupported DT_ANDROID_RELSZ in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002772 return false;
2773
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002774 case DT_RELAENT:
2775 if (d->d_un.d_val != sizeof(ElfW(Rela))) {
Dmitriy Ivanovf240aa82014-09-16 23:34:20 -07002776 DL_ERR("invalid DT_RELAENT: %zd", static_cast<size_t>(d->d_un.d_val));
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002777 return false;
2778 }
2779 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002780
2781 // ignored (see DT_RELCOUNT comments for details)
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002782 case DT_RELACOUNT:
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002783 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002784
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002785 case DT_REL:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002786 DL_ERR("unsupported DT_REL in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002787 return false;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002788
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002789 case DT_RELSZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002790 DL_ERR("unsupported DT_RELSZ in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002791 return false;
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002792
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002793#else
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002794 case DT_REL:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002795 rel_ = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002796 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002797
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002798 case DT_RELSZ:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002799 rel_count_ = d->d_un.d_val / sizeof(ElfW(Rel));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002800 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002801
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002802 case DT_RELENT:
2803 if (d->d_un.d_val != sizeof(ElfW(Rel))) {
Dmitriy Ivanovf240aa82014-09-16 23:34:20 -07002804 DL_ERR("invalid DT_RELENT: %zd", static_cast<size_t>(d->d_un.d_val));
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002805 return false;
2806 }
2807 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002808
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002809 case DT_ANDROID_REL:
2810 android_relocs_ = reinterpret_cast<uint8_t*>(load_bias + d->d_un.d_ptr);
2811 break;
2812
2813 case DT_ANDROID_RELSZ:
2814 android_relocs_size_ = d->d_un.d_val;
2815 break;
2816
2817 case DT_ANDROID_RELA:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002818 DL_ERR("unsupported DT_ANDROID_RELA in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002819 return false;
2820
2821 case DT_ANDROID_RELASZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002822 DL_ERR("unsupported DT_ANDROID_RELASZ in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002823 return false;
2824
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002825 // "Indicates that all RELATIVE relocations have been concatenated together,
2826 // and specifies the RELATIVE relocation count."
2827 //
2828 // TODO: Spec also mentions that this can be used to optimize relocation process;
2829 // Not currently used by bionic linker - ignored.
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002830 case DT_RELCOUNT:
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002831 break;
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002832
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002833 case DT_RELA:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002834 DL_ERR("unsupported DT_RELA in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002835 return false;
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002836
2837 case DT_RELASZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002838 DL_ERR("unsupported DT_RELASZ in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002839 return false;
2840
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002841#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002842 case DT_INIT:
Dimitry Ivanov55437462016-07-20 15:33:07 -07002843 init_func_ = reinterpret_cast<linker_ctor_function_t>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002844 DEBUG("%s constructors (DT_INIT) found at %p", get_realpath(), init_func_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002845 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002846
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002847 case DT_FINI:
Dimitry Ivanov55437462016-07-20 15:33:07 -07002848 fini_func_ = reinterpret_cast<linker_dtor_function_t>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002849 DEBUG("%s destructors (DT_FINI) found at %p", get_realpath(), fini_func_);
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_INIT_ARRAY:
Dimitry Ivanov55437462016-07-20 15:33:07 -07002853 init_array_ = reinterpret_cast<linker_ctor_function_t*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002854 DEBUG("%s constructors (DT_INIT_ARRAY) found at %p", get_realpath(), init_array_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002855 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002856
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002857 case DT_INIT_ARRAYSZ:
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -08002858 init_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002859 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002860
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002861 case DT_FINI_ARRAY:
Dimitry Ivanov55437462016-07-20 15:33:07 -07002862 fini_array_ = reinterpret_cast<linker_dtor_function_t*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002863 DEBUG("%s destructors (DT_FINI_ARRAY) found at %p", get_realpath(), fini_array_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002864 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002865
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002866 case DT_FINI_ARRAYSZ:
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -08002867 fini_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002868 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002869
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002870 case DT_PREINIT_ARRAY:
Dimitry Ivanov55437462016-07-20 15:33:07 -07002871 preinit_array_ = reinterpret_cast<linker_ctor_function_t*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002872 DEBUG("%s constructors (DT_PREINIT_ARRAY) found at %p", get_realpath(), preinit_array_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002873 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002874
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002875 case DT_PREINIT_ARRAYSZ:
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -08002876 preinit_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002877 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002878
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002879 case DT_TEXTREL:
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00002880#if defined(__LP64__)
Dimitry Ivanov816676e2016-10-19 11:00:28 -07002881 DL_ERR("\"%s\" has text relocations", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002882 return false;
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00002883#else
2884 has_text_relocations = true;
2885 break;
2886#endif
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002887
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002888 case DT_SYMBOLIC:
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -07002889 has_DT_SYMBOLIC = true;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002890 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002891
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002892 case DT_NEEDED:
2893 ++needed_count;
2894 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002895
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002896 case DT_FLAGS:
2897 if (d->d_un.d_val & DF_TEXTREL) {
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00002898#if defined(__LP64__)
Dimitry Ivanov816676e2016-10-19 11:00:28 -07002899 DL_ERR("\"%s\" has text relocations", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002900 return false;
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00002901#else
2902 has_text_relocations = true;
2903#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002904 }
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -07002905 if (d->d_un.d_val & DF_SYMBOLIC) {
2906 has_DT_SYMBOLIC = true;
2907 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002908 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002909
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07002910 case DT_FLAGS_1:
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07002911 set_dt_flags_1(d->d_un.d_val);
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -07002912
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07002913 if ((d->d_un.d_val & ~SUPPORTED_DT_FLAGS_1) != 0) {
Dimitry Ivanov816676e2016-10-19 11:00:28 -07002914 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 -07002915 }
2916 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002917#if defined(__mips__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002918 case DT_MIPS_RLD_MAP:
2919 // Set the DT_MIPS_RLD_MAP entry to the address of _r_debug for GDB.
2920 {
2921 r_debug** dp = reinterpret_cast<r_debug**>(load_bias + d->d_un.d_ptr);
2922 *dp = &_r_debug;
2923 }
2924 break;
Lazar Trsic83b44a92016-04-06 13:39:17 +02002925 case DT_MIPS_RLD_MAP_REL:
2926 // Set the DT_MIPS_RLD_MAP_REL entry to the address of _r_debug for GDB.
Raghu Gandham68815722014-12-18 19:12:19 -08002927 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002928 r_debug** dp = reinterpret_cast<r_debug**>(
2929 reinterpret_cast<ElfW(Addr)>(d) + d->d_un.d_val);
Raghu Gandham68815722014-12-18 19:12:19 -08002930 *dp = &_r_debug;
2931 }
2932 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002933
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002934 case DT_MIPS_RLD_VERSION:
2935 case DT_MIPS_FLAGS:
2936 case DT_MIPS_BASE_ADDRESS:
2937 case DT_MIPS_UNREFEXTNO:
2938 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002939
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002940 case DT_MIPS_SYMTABNO:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002941 mips_symtabno_ = d->d_un.d_val;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002942 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002943
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002944 case DT_MIPS_LOCAL_GOTNO:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002945 mips_local_gotno_ = d->d_un.d_val;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002946 break;
2947
2948 case DT_MIPS_GOTSYM:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002949 mips_gotsym_ = d->d_un.d_val;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002950 break;
2951#endif
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002952 // Ignored: "Its use has been superseded by the DF_BIND_NOW flag"
2953 case DT_BIND_NOW:
2954 break;
2955
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002956 case DT_VERSYM:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002957 versym_ = reinterpret_cast<ElfW(Versym)*>(load_bias + d->d_un.d_ptr);
2958 break;
2959
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002960 case DT_VERDEF:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002961 verdef_ptr_ = load_bias + d->d_un.d_ptr;
2962 break;
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002963 case DT_VERDEFNUM:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002964 verdef_cnt_ = d->d_un.d_val;
2965 break;
2966
Alexander Ivchenkoe8314332014-12-02 15:32:25 +03002967 case DT_VERNEED:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002968 verneed_ptr_ = load_bias + d->d_un.d_ptr;
2969 break;
2970
Alexander Ivchenkoe8314332014-12-02 15:32:25 +03002971 case DT_VERNEEDNUM:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002972 verneed_cnt_ = d->d_un.d_val;
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002973 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002974
Evgenii Stepanov68650822015-06-10 13:38:39 -07002975 case DT_RUNPATH:
2976 // this is parsed after we have strtab initialized (see below).
2977 break;
2978
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002979 default:
Dmitriy Ivanov8f61d992014-09-16 14:31:06 -07002980 if (!relocating_linker) {
Dimitry Ivanov816676e2016-10-19 11:00:28 -07002981 DL_WARN("\"%s\" unused DT entry: type %p arg %p", get_realpath(),
Dmitriy Ivanov8f61d992014-09-16 14:31:06 -07002982 reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
2983 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002984 break;
Brian Carlstromd4ee82d2013-02-28 15:58:45 -08002985 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002986 }
2987
Duane Sandbc425c72015-06-01 16:29:14 -07002988#if defined(__mips__) && !defined(__LP64__)
2989 if (!mips_check_and_adjust_fp_modes()) {
2990 return false;
2991 }
2992#endif
2993
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002994 DEBUG("si->base = %p, si->strtab = %p, si->symtab = %p",
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002995 reinterpret_cast<void*>(base), strtab_, symtab_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002996
2997 // Sanity checks.
2998 if (relocating_linker && needed_count != 0) {
2999 DL_ERR("linker cannot have DT_NEEDED dependencies on other libraries");
3000 return false;
3001 }
Dmitriy Ivanov3597b802015-03-09 12:02:02 -07003002 if (nbucket_ == 0 && gnu_nbucket_ == 0) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003003 DL_ERR("empty/missing DT_HASH/DT_GNU_HASH in \"%s\" "
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003004 "(new hash type from the future?)", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003005 return false;
3006 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003007 if (strtab_ == 0) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003008 DL_ERR("empty/missing DT_STRTAB in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003009 return false;
3010 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003011 if (symtab_ == 0) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003012 DL_ERR("empty/missing DT_SYMTAB in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003013 return false;
3014 }
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003015
Dmitriy Ivanov624b8f12015-06-08 10:41:33 -07003016 // second pass - parse entries relying on strtab
3017 for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
Evgenii Stepanov68650822015-06-10 13:38:39 -07003018 switch (d->d_tag) {
3019 case DT_SONAME:
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07003020 set_soname(get_string(d->d_un.d_val));
Evgenii Stepanov68650822015-06-10 13:38:39 -07003021 break;
3022 case DT_RUNPATH:
Evgenii Stepanov68650822015-06-10 13:38:39 -07003023 set_dt_runpath(get_string(d->d_un.d_val));
3024 break;
Dmitriy Ivanov624b8f12015-06-08 10:41:33 -07003025 }
3026 }
3027
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003028 // Before M release linker was using basename in place of soname.
Dmitriy Ivanov19133522015-06-02 17:36:54 -07003029 // In the case when dt_soname is absent some apps stop working
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003030 // because they can't find dt_needed library by soname.
3031 // This workaround should keep them working. (applies only
Elliott Hughes5bc78c82016-11-16 11:35:43 -08003032 // for apps targeting sdk version < M). Make an exception for
Dmitriy Ivanov19133522015-06-02 17:36:54 -07003033 // the main executable and linker; they do not need to have dt_soname
Dimitry Ivanov3f660572016-09-09 10:00:39 -07003034 if (soname_ == nullptr &&
3035 this != solist_get_somain() &&
3036 (flags_ & FLAG_LINKER) == 0 &&
Elliott Hughes5bc78c82016-11-16 11:35:43 -08003037 get_application_target_sdk_version() < __ANDROID_API_M__) {
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003038 soname_ = basename(realpath_.c_str());
3039 DL_WARN("%s: is missing DT_SONAME will use basename as a replacement: \"%s\"",
3040 get_realpath(), soname_);
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07003041 // 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 -07003042 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003043 return true;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07003044}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003045
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003046bool soinfo::link_image(const soinfo_list_t& global_group, const soinfo_list_t& local_group,
3047 const android_dlextinfo* extinfo) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003048
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08003049 local_group_root_ = local_group.front();
3050 if (local_group_root_ == nullptr) {
3051 local_group_root_ = this;
3052 }
3053
Dmitriy Ivanov19133522015-06-02 17:36:54 -07003054 if ((flags_ & FLAG_LINKER) == 0 && local_group_root_ == this) {
3055 target_sdk_version_ = get_application_target_sdk_version();
3056 }
3057
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003058 VersionTracker version_tracker;
3059
3060 if (!version_tracker.init(this)) {
3061 return false;
3062 }
3063
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003064#if !defined(__LP64__)
3065 if (has_text_relocations) {
Elliott Hughes5bc78c82016-11-16 11:35:43 -08003066 // Fail if app is targeting M or above.
3067 if (get_application_target_sdk_version() >= __ANDROID_API_M__) {
Dimitry Ivanov816676e2016-10-19 11:00:28 -07003068 DL_ERR_AND_LOG("\"%s\" has text relocations", get_realpath());
Dmitriy Ivanove4ad91f2015-06-12 15:00:31 -07003069 return false;
3070 }
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003071 // Make segments writable to allow text relocations to work properly. We will later call
Dmitriy Ivanov7e039932015-10-01 14:02:19 -07003072 // phdr_table_protect_segments() after all of them are applied.
Dimitry Ivanov816676e2016-10-19 11:00:28 -07003073 DL_WARN("\"%s\" has text relocations. This is wasting memory and prevents "
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003074 "security hardening. Please fix.", get_realpath());
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07003075 add_dlwarning(get_realpath(), "text relocations");
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003076 if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
3077 DL_ERR("can't unprotect loadable segments for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003078 get_realpath(), strerror(errno));
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003079 return false;
3080 }
3081 }
3082#endif
3083
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003084 if (android_relocs_ != nullptr) {
3085 // check signature
3086 if (android_relocs_size_ > 3 &&
3087 android_relocs_[0] == 'A' &&
3088 android_relocs_[1] == 'P' &&
Dmitriy Ivanov18870d32015-04-22 13:10:04 -07003089 android_relocs_[2] == 'S' &&
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003090 android_relocs_[3] == '2') {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003091 DEBUG("[ android relocating %s ]", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003092
3093 bool relocated = false;
3094 const uint8_t* packed_relocs = android_relocs_ + 4;
3095 const size_t packed_relocs_size = android_relocs_size_ - 4;
3096
Dmitriy Ivanov18870d32015-04-22 13:10:04 -07003097 relocated = relocate(
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003098 version_tracker,
Dmitriy Ivanov18870d32015-04-22 13:10:04 -07003099 packed_reloc_iterator<sleb128_decoder>(
3100 sleb128_decoder(packed_relocs, packed_relocs_size)),
3101 global_group, local_group);
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003102
3103 if (!relocated) {
3104 return false;
3105 }
3106 } else {
3107 DL_ERR("bad android relocation header.");
3108 return false;
3109 }
3110 }
3111
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07003112#if defined(USE_RELA)
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003113 if (rela_ != nullptr) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003114 DEBUG("[ relocating %s ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003115 if (!relocate(version_tracker,
3116 plain_reloc_iterator(rela_, rela_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003117 return false;
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07003118 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003119 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003120 if (plt_rela_ != nullptr) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003121 DEBUG("[ relocating %s plt ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003122 if (!relocate(version_tracker,
3123 plain_reloc_iterator(plt_rela_, plt_rela_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003124 return false;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003125 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003126 }
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07003127#else
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003128 if (rel_ != nullptr) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003129 DEBUG("[ relocating %s ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003130 if (!relocate(version_tracker,
3131 plain_reloc_iterator(rel_, rel_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003132 return false;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003133 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003134 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003135 if (plt_rel_ != nullptr) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003136 DEBUG("[ relocating %s plt ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003137 if (!relocate(version_tracker,
3138 plain_reloc_iterator(plt_rel_, plt_rel_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003139 return false;
Brigid Smithc5a13ef2014-07-23 11:22:25 -07003140 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003141 }
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07003142#endif
Brigid Smithc5a13ef2014-07-23 11:22:25 -07003143
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07003144#if defined(__mips__)
Dmitriy Ivanovf39cb632015-04-30 20:17:03 -07003145 if (!mips_relocate_got(version_tracker, global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003146 return false;
3147 }
Raghu Gandhamd7daacb2012-07-31 12:07:22 -07003148#endif
3149
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003150 DEBUG("[ finished linking %s ]", get_realpath());
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003151
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003152#if !defined(__LP64__)
3153 if (has_text_relocations) {
3154 // All relocations are done, we can protect our segments back to read-only.
3155 if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
3156 DL_ERR("can't protect segments for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003157 get_realpath(), strerror(errno));
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003158 return false;
3159 }
3160 }
3161#endif
3162
Mingwei Shibe910522015-11-12 07:02:14 +00003163 // We can also turn on GNU RELRO protection if we're not linking the dynamic linker
3164 // itself --- it can't make system calls yet, and will have to call protect_relro later.
3165 if (!is_linker() && !protect_relro()) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003166 return false;
3167 }
Nick Kralevich9ec0f032012-02-28 10:40:00 -08003168
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003169 /* Handle serializing/sharing the RELRO segment */
3170 if (extinfo && (extinfo->flags & ANDROID_DLEXT_WRITE_RELRO)) {
3171 if (phdr_table_serialize_gnu_relro(phdr, phnum, load_bias,
3172 extinfo->relro_fd) < 0) {
3173 DL_ERR("failed serializing GNU RELRO section for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003174 get_realpath(), strerror(errno));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003175 return false;
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +00003176 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003177 } else if (extinfo && (extinfo->flags & ANDROID_DLEXT_USE_RELRO)) {
3178 if (phdr_table_map_gnu_relro(phdr, phnum, load_bias,
3179 extinfo->relro_fd) < 0) {
3180 DL_ERR("failed mapping GNU RELRO section for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003181 get_realpath(), strerror(errno));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003182 return false;
3183 }
3184 }
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +00003185
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003186 notify_gdb_of_load(this);
3187 return true;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003188}
3189
Mingwei Shibe910522015-11-12 07:02:14 +00003190bool soinfo::protect_relro() {
3191 if (phdr_table_protect_gnu_relro(phdr, phnum, load_bias) < 0) {
3192 DL_ERR("can't enable GNU RELRO protection for \"%s\": %s",
3193 get_realpath(), strerror(errno));
3194 return false;
3195 }
3196 return true;
3197}
3198
Dimitry Ivanov3f660572016-09-09 10:00:39 -07003199void init_default_namespace() {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003200 g_default_namespace.set_name("(default)");
3201 g_default_namespace.set_isolated(false);
3202
Dimitry Ivanov3f660572016-09-09 10:00:39 -07003203 soinfo* somain = solist_get_somain();
3204
Evgenii Stepanovd640b222015-07-10 17:54:01 -07003205 const char *interp = phdr_table_get_interpreter_name(somain->phdr, somain->phnum,
3206 somain->load_bias);
3207 const char* bname = basename(interp);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003208 if (bname && (strcmp(bname, "linker_asan") == 0 || strcmp(bname, "linker_asan64") == 0)) {
Evgenii Stepanovd640b222015-07-10 17:54:01 -07003209 g_default_ld_paths = kAsanDefaultLdPaths;
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -07003210 g_is_asan = true;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003211 } else {
Evgenii Stepanovd640b222015-07-10 17:54:01 -07003212 g_default_ld_paths = kDefaultLdPaths;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003213 }
3214
neo.chae2589f9d2016-10-04 11:00:27 +09003215 char real_path[PATH_MAX];
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003216 std::vector<std::string> ld_default_paths;
3217 for (size_t i = 0; g_default_ld_paths[i] != nullptr; ++i) {
neo.chae2589f9d2016-10-04 11:00:27 +09003218 if (realpath(g_default_ld_paths[i], real_path) != nullptr) {
3219 ld_default_paths.push_back(real_path);
3220 } else {
3221 ld_default_paths.push_back(g_default_ld_paths[i]);
3222 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003223 }
3224
3225 g_default_namespace.set_default_library_paths(std::move(ld_default_paths));
Evgenii Stepanovd640b222015-07-10 17:54:01 -07003226};