blob: 60dff988e82079efa0c41cabed0a3ec73381d89e [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 Ivanov4cabfaa2017-03-07 11:19:05 -080052#include "linker_config.h"
Dimitry Ivanov6b788ee2016-02-17 16:08:03 -080053#include "linker_gdb_support.h"
Dimitry Ivanov48ec2882016-08-04 11:50:36 -070054#include "linker_globals.h"
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080055#include "linker_debug.h"
Dimitry Ivanov769b33f2016-07-21 11:33:40 -070056#include "linker_dlwarning.h"
Dimitry Ivanov3f660572016-09-09 10:00:39 -070057#include "linker_main.h"
Dimitry Ivanovb943f302016-08-03 16:00:10 -070058#include "linker_namespaces.h"
Dmitriy Ivanov18870d32015-04-22 13:10:04 -070059#include "linker_sleb128.h"
David 'Digit' Turner23363ed2012-06-18 18:13:49 +020060#include "linker_phdr.h"
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -080061#include "linker_relocs.h"
Dmitriy Ivanovfa26eee2015-02-03 16:06:47 -080062#include "linker_reloc_iterators.h"
Dmitriy Ivanova1feb112015-10-01 18:41:57 -070063#include "linker_utils.h"
tony.ys_liub4474402015-07-29 18:00:22 +080064
Elliott Hughes939a7e02015-12-04 15:27:46 -080065#include "android-base/strings.h"
Dimitry Ivanovb996d602016-07-11 18:11:39 -070066#include "android-base/stringprintf.h"
Simon Baldwinaef71952015-01-16 13:22:54 +000067#include "ziparchive/zip_archive.h"
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080068
Elliott Hughes1801db32015-06-08 18:04:00 -070069// Override macros to use C++ style casts.
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -080070#undef ELF_ST_TYPE
71#define ELF_ST_TYPE(x) (static_cast<uint32_t>(x) & 0xf)
72
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -070073static android_namespace_t* g_anonymous_namespace = &g_default_namespace;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -070074
Dmitriy Ivanov600bc3c2015-03-10 15:43:50 -070075static LinkerTypeAllocator<soinfo> g_soinfo_allocator;
76static LinkerTypeAllocator<LinkedListEntry<soinfo>> g_soinfo_links_allocator;
Magnus Malmbornba98d922012-09-12 13:00:55 +020077
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -070078static LinkerTypeAllocator<android_namespace_t> g_namespace_allocator;
Dimitry Ivanovaca299a2016-04-11 12:42:58 -070079static LinkerTypeAllocator<LinkedListEntry<android_namespace_t>> g_namespace_list_allocator;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -070080
Dimitry Ivanov4cabfaa2017-03-07 11:19:05 -080081static const char* const kLdConfigFilePath = "/system/etc/ld.config.txt";
82
Elliott Hughes4eeb1f12013-10-25 17:38:02 -070083#if defined(__LP64__)
Dimitry Ivanova1446972017-03-17 00:08:23 +000084static const char* const kSystemLibDir = "/system/lib64";
85static const char* const kVendorLibDir = "/vendor/lib64";
86static const char* const kAsanSystemLibDir = "/data/lib64";
87static const char* const kAsanVendorLibDir = "/data/vendor/lib64";
Elliott Hughes011bc0b2013-10-08 14:27:10 -070088#else
Dimitry Ivanova1446972017-03-17 00:08:23 +000089static const char* const kSystemLibDir = "/system/lib";
90static const char* const kVendorLibDir = "/vendor/lib";
91static const char* const kAsanSystemLibDir = "/data/lib";
92static const char* const kAsanVendorLibDir = "/data/vendor/lib";
Elliott Hughes011bc0b2013-10-08 14:27:10 -070093#endif
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -070094
95static const char* const kDefaultLdPaths[] = {
96 kSystemLibDir,
97 kVendorLibDir,
Dmitriy Ivanov851135b2014-08-29 12:02:36 -070098 nullptr
Elliott Hughes124fae92012-10-31 14:20:03 -070099};
David Bartleybc3a5c22009-06-02 18:27:28 -0700100
Evgenii Stepanovd640b222015-07-10 17:54:01 -0700101static const char* const kAsanDefaultLdPaths[] = {
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700102 kAsanSystemLibDir,
103 kSystemLibDir,
104 kAsanVendorLibDir,
105 kVendorLibDir,
Evgenii Stepanovd640b222015-07-10 17:54:01 -0700106 nullptr
107};
108
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700109// Is ASAN enabled?
110static bool g_is_asan = false;
111
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -0700112static CFIShadowWriter g_cfi_shadow;
113
114CFIShadowWriter* get_cfi_shadow() {
115 return &g_cfi_shadow;
116}
117
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700118static bool is_system_library(const std::string& realpath) {
119 for (const auto& dir : g_default_namespace.get_default_library_paths()) {
120 if (file_is_in_dir(realpath, dir)) {
121 return true;
122 }
123 }
124 return false;
125}
126
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700127// Checks if the file exists and not a directory.
128static bool file_exists(const char* path) {
Dimitry Ivanov4cf70242016-08-11 11:11:52 -0700129 struct stat s;
130
131 if (stat(path, &s) != 0) {
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700132 return false;
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700133 }
Dimitry Ivanov4cf70242016-08-11 11:11:52 -0700134
135 return S_ISREG(s.st_mode);
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700136}
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700137
Dimitry Ivanov35c8e3b2017-02-27 12:17:47 -0800138static std::string resolve_soname(const std::string& name) {
139 // We assume that soname equals to basename here
140
141 // TODO(dimitry): consider having honest absolute-path -> soname resolution
142 // note that since we might end up refusing to load this library because
143 // it is not in shared libs list we need to get the soname without actually loading
144 // the library.
145 //
146 // On the other hand there are several places where we already assume that
147 // soname == basename in particular for any not-loaded library mentioned
148 // in DT_NEEDED list.
149 return basename(name.c_str());
150}
151
152static bool maybe_accessible_via_namespace_links(android_namespace_t* ns, const char* name) {
153 std::string soname = resolve_soname(name);
154 for (auto& ns_link : ns->linked_namespaces()) {
155 if (ns_link.is_accessible(soname.c_str())) {
156 return true;
157 }
158 }
159
160 return false;
161}
162
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700163// TODO(dimitry): The grey-list is a workaround for http://b/26394120 ---
164// gradually remove libraries from this list until it is gone.
Dimitry Ivanov35c8e3b2017-02-27 12:17:47 -0800165static bool is_greylisted(android_namespace_t* ns, const char* name, const soinfo* needed_by) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700166 static const char* const kLibraryGreyList[] = {
167 "libandroid_runtime.so",
168 "libbinder.so",
169 "libcrypto.so",
170 "libcutils.so",
171 "libexpat.so",
172 "libgui.so",
173 "libmedia.so",
174 "libnativehelper.so",
175 "libskia.so",
176 "libssl.so",
177 "libstagefright.so",
178 "libsqlite.so",
179 "libui.so",
180 "libutils.so",
181 "libvorbisidec.so",
182 nullptr
183 };
184
Elliott Hughes5bc78c82016-11-16 11:35:43 -0800185 // If you're targeting N, you don't get the greylist.
186 if (get_application_target_sdk_version() >= __ANDROID_API_N__) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700187 return false;
188 }
189
190 // if the library needed by a system library - implicitly assume it
Dimitry Ivanov35c8e3b2017-02-27 12:17:47 -0800191 // is greylisted unless it is in the list of shared libraries for one or
192 // more linked namespaces
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700193 if (needed_by != nullptr && is_system_library(needed_by->get_realpath())) {
Dimitry Ivanov35c8e3b2017-02-27 12:17:47 -0800194 return !maybe_accessible_via_namespace_links(ns, name);
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700195 }
196
197 // if this is an absolute path - make sure it points to /system/lib(64)
198 if (name[0] == '/' && dirname(name) == kSystemLibDir) {
199 // and reduce the path to basename
200 name = basename(name);
201 }
202
203 for (size_t i = 0; kLibraryGreyList[i] != nullptr; ++i) {
204 if (strcmp(name, kLibraryGreyList[i]) == 0) {
205 return true;
206 }
207 }
208
209 return false;
210}
211// END OF WORKAROUND
212
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700213static std::vector<std::string> g_ld_preload_names;
Elliott Hughesa4aafd12014-01-13 16:37:47 -0800214
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800215static bool g_anonymous_namespace_initialized;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700216
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800217#if STATS
Elliott Hughesbedfe382012-08-14 14:07:59 -0700218struct linker_stats_t {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700219 int count[kRelocMax];
Elliott Hughesbedfe382012-08-14 14:07:59 -0700220};
221
222static linker_stats_t linker_stats;
223
Dmitriy Ivanov114ff692015-01-14 11:36:38 -0800224void count_relocation(RelocationKind kind) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700225 ++linker_stats.count[kind];
Elliott Hughesbedfe382012-08-14 14:07:59 -0700226}
227#else
Dmitriy Ivanov114ff692015-01-14 11:36:38 -0800228void count_relocation(RelocationKind) {
Elliott Hughesbedfe382012-08-14 14:07:59 -0700229}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800230#endif
231
232#if COUNT_PAGES
Dmitriy Ivanov114ff692015-01-14 11:36:38 -0800233uint32_t bitmask[4096];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800234#endif
235
Elliott Hughesbedfe382012-08-14 14:07:59 -0700236static void notify_gdb_of_load(soinfo* info) {
Dimitry Ivanove97d8ed2016-03-01 15:55:56 -0800237 if (info->is_linker() || info->is_main_executable()) {
238 // gdb already knows about the linker and the main executable.
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700239 return;
240 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800241
Dimitry Ivanov6b788ee2016-02-17 16:08:03 -0800242 link_map* map = &(info->link_map_head);
Nicolas Geoffray0fa54102016-02-18 09:31:24 +0000243
Dimitry Ivanov6b788ee2016-02-17 16:08:03 -0800244 map->l_addr = info->load_bias;
245 // link_map l_name field is not const.
246 map->l_name = const_cast<char*>(info->get_realpath());
247 map->l_ld = info->dynamic;
Nicolas Geoffray0fa54102016-02-18 09:31:24 +0000248
Dimitry Ivanove97d8ed2016-03-01 15:55:56 -0800249 CHECK(map->l_name != nullptr);
250 CHECK(map->l_name[0] != '\0');
251
Dimitry Ivanov6b788ee2016-02-17 16:08:03 -0800252 notify_gdb_of_load(map);
Iliyan Malchev5e12d7e2009-03-24 19:02:00 -0700253}
254
Elliott Hughesbedfe382012-08-14 14:07:59 -0700255static void notify_gdb_of_unload(soinfo* info) {
Dimitry Ivanov6b788ee2016-02-17 16:08:03 -0800256 notify_gdb_of_unload(&(info->link_map_head));
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800257}
258
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -0700259LinkedListEntry<soinfo>* SoinfoListAllocator::alloc() {
260 return g_soinfo_links_allocator.alloc();
261}
262
263void SoinfoListAllocator::free(LinkedListEntry<soinfo>* entry) {
264 g_soinfo_links_allocator.free(entry);
265}
266
Dimitry Ivanovaca299a2016-04-11 12:42:58 -0700267LinkedListEntry<android_namespace_t>* NamespaceListAllocator::alloc() {
268 return g_namespace_list_allocator.alloc();
269}
270
271void NamespaceListAllocator::free(LinkedListEntry<android_namespace_t>* entry) {
272 g_namespace_list_allocator.free(entry);
273}
274
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700275soinfo* soinfo_alloc(android_namespace_t* ns, const char* name,
276 struct stat* file_stat, off64_t file_offset,
277 uint32_t rtld_flags) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700278 if (strlen(name) >= PATH_MAX) {
Magnus Malmbornba98d922012-09-12 13:00:55 +0200279 DL_ERR("library name \"%s\" too long", name);
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700280 return nullptr;
Magnus Malmbornba98d922012-09-12 13:00:55 +0200281 }
282
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700283 TRACE("name %s: allocating soinfo for ns=%p", name, ns);
284
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700285 soinfo* si = new (g_soinfo_allocator.alloc()) soinfo(ns, name, file_stat,
286 file_offset, rtld_flags);
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -0700287
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700288 solist_add_soinfo(si);
Magnus Malmbornba98d922012-09-12 13:00:55 +0200289
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -0700290 si->generate_handle();
291 ns->add_soinfo(si);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700292
Elliott Hughesca0c11b2013-03-12 10:40:45 -0700293 TRACE("name %s: allocated soinfo @ %p", name, si);
Magnus Malmbornba98d922012-09-12 13:00:55 +0200294 return si;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800295}
296
Elliott Hughesfaf05ba2014-02-11 16:59:37 -0800297static void soinfo_free(soinfo* si) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700298 if (si == nullptr) {
299 return;
300 }
301
302 if (si->base != 0 && si->size != 0) {
Dimitry Ivanovf45b0e92016-01-15 11:13:35 -0800303 if (!si->is_mapped_by_caller()) {
304 munmap(reinterpret_cast<void*>(si->base), si->size);
305 } else {
306 // remap the region as PROT_NONE, MAP_ANONYMOUS | MAP_NORESERVE
307 mmap(reinterpret_cast<void*>(si->base), si->size, PROT_NONE,
308 MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
309 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700310 }
311
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700312 TRACE("name %s: freeing soinfo @ %p", si->get_realpath(), si);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700313
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700314 if (!solist_remove_soinfo(si)) {
315 // TODO (dimitry): revisit this - for now preserving the logic
316 // but it does not look right, abort if soinfo is not in the list instead?
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700317 return;
318 }
Elliott Hughes46882792012-08-03 16:49:39 -0700319
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700320 // clear links to/from si
321 si->remove_all_links();
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -0700322
Dmitriy Ivanov609f11b2015-07-08 15:26:46 -0700323 si->~soinfo();
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700324 g_soinfo_allocator.free(si);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800325}
326
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700327static void parse_path(const char* path, const char* delimiters,
328 std::vector<std::string>* resolved_paths) {
329 std::vector<std::string> paths;
330 split_path(path, delimiters, &paths);
331 resolve_paths(paths, resolved_paths);
332}
333
Elliott Hughescade4c32012-12-20 14:42:14 -0800334static void parse_LD_LIBRARY_PATH(const char* path) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700335 std::vector<std::string> ld_libary_paths;
336 parse_path(path, ":", &ld_libary_paths);
337 g_default_namespace.set_ld_library_paths(std::move(ld_libary_paths));
Elliott Hughescade4c32012-12-20 14:42:14 -0800338}
339
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700340static bool realpath_fd(int fd, std::string* realpath) {
341 std::vector<char> buf(PATH_MAX), proc_self_fd(PATH_MAX);
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700342 __libc_format_buffer(&proc_self_fd[0], proc_self_fd.size(), "/proc/self/fd/%d", fd);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700343 if (readlink(&proc_self_fd[0], &buf[0], buf.size()) == -1) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700344 PRINT("readlink(\"%s\") failed: %s [fd=%d]", &proc_self_fd[0], strerror(errno), fd);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700345 return false;
346 }
347
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700348 *realpath = &buf[0];
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700349 return true;
350}
351
Elliott Hughes4eeb1f12013-10-25 17:38:02 -0700352#if defined(__arm__)
Elliott Hughes46882792012-08-03 16:49:39 -0700353
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700354// For a given PC, find the .so that it belongs to.
355// Returns the base address of the .ARM.exidx section
356// for that .so, and the number of 8-byte entries
357// in that section (via *pcount).
358//
359// Intended to be called by libc's __gnu_Unwind_Find_exidx().
Dimitry Ivanovd9e427c2016-11-22 16:55:25 -0800360_Unwind_Ptr do_dl_unwind_find_exidx(_Unwind_Ptr pc, int* pcount) {
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -0800361 uintptr_t addr = reinterpret_cast<uintptr_t>(pc);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800362
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700363 for (soinfo* si = solist_get_head(); si != 0; si = si->next) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700364 if ((addr >= si->base) && (addr < (si->base + si->size))) {
365 *pcount = si->ARM_exidx_count;
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -0800366 return reinterpret_cast<_Unwind_Ptr>(si->ARM_exidx);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800367 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700368 }
369 *pcount = 0;
370 return nullptr;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800371}
Elliott Hughes46882792012-08-03 16:49:39 -0700372
Christopher Ferris24053a42013-08-19 17:45:09 -0700373#endif
Elliott Hughes46882792012-08-03 16:49:39 -0700374
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700375// Here, we only have to provide a callback to iterate across all the
376// loaded libraries. gcc_eh does the rest.
Dmitriy Ivanov7271caf2015-06-29 14:48:25 -0700377int do_dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void* data) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700378 int rv = 0;
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700379 for (soinfo* si = solist_get_head(); si != nullptr; si = si->next) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700380 dl_phdr_info dl_info;
381 dl_info.dlpi_addr = si->link_map_head.l_addr;
382 dl_info.dlpi_name = si->link_map_head.l_name;
383 dl_info.dlpi_phdr = si->phdr;
384 dl_info.dlpi_phnum = si->phnum;
385 rv = cb(&dl_info, sizeof(dl_phdr_info), data);
386 if (rv != 0) {
387 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800388 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700389 }
390 return rv;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800391}
Elliott Hughes46882792012-08-03 16:49:39 -0700392
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800393
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700394bool soinfo_do_lookup(soinfo* si_from, const char* name, const version_info* vi,
Dimitry Ivanovb943f302016-08-03 16:00:10 -0700395 soinfo** si_found_in, const soinfo_list_t& global_group,
396 const soinfo_list_t& local_group, const ElfW(Sym)** symbol) {
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800397 SymbolName symbol_name(name);
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700398 const ElfW(Sym)* s = nullptr;
Iliyan Malchev6ed80c82009-09-28 19:38:04 -0700399
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -0700400 /* "This element's presence in a shared object library alters the dynamic linker's
401 * symbol resolution algorithm for references within the library. Instead of starting
402 * a symbol search with the executable file, the dynamic linker starts from the shared
403 * object itself. If the shared object fails to supply the referenced symbol, the
404 * dynamic linker then searches the executable file and other shared objects as usual."
405 *
406 * http://www.sco.com/developers/gabi/2012-12-31/ch5.dynamic.html
407 *
408 * Note that this is unlikely since static linker avoids generating
409 * relocations for -Bsymbolic linked dynamic executables.
410 */
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700411 if (si_from->has_DT_SYMBOLIC) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700412 DEBUG("%s: looking up %s in local scope (DT_SYMBOLIC)", si_from->get_realpath(), name);
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700413 if (!si_from->find_symbol_by_name(symbol_name, vi, &s)) {
414 return false;
415 }
416
Dmitriy Ivanov8f61d992014-09-16 14:31:06 -0700417 if (s != nullptr) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700418 *si_found_in = si_from;
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -0700419 }
420 }
421
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700422 // 1. Look for it in global_group
423 if (s == nullptr) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700424 bool error = false;
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700425 global_group.visit([&](soinfo* global_si) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700426 DEBUG("%s: looking up %s in %s (from global group)",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700427 si_from->get_realpath(), name, global_si->get_realpath());
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700428 if (!global_si->find_symbol_by_name(symbol_name, vi, &s)) {
429 error = true;
430 return false;
431 }
432
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -0700433 if (s != nullptr) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700434 *si_found_in = global_si;
435 return false;
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -0700436 }
Dmitriy Ivanovc2048942014-08-29 10:15:25 -0700437
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700438 return true;
439 });
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700440
441 if (error) {
442 return false;
443 }
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -0700444 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700445
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700446 // 2. Look for it in the local group
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700447 if (s == nullptr) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700448 bool error = false;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700449 local_group.visit([&](soinfo* local_si) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700450 if (local_si == si_from && si_from->has_DT_SYMBOLIC) {
Dmitriy Ivanove47b3f82014-10-23 14:19:07 -0700451 // we already did this - skip
452 return true;
453 }
454
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700455 DEBUG("%s: looking up %s in %s (from local group)",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700456 si_from->get_realpath(), name, local_si->get_realpath());
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700457 if (!local_si->find_symbol_by_name(symbol_name, vi, &s)) {
458 error = true;
459 return false;
460 }
461
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700462 if (s != nullptr) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700463 *si_found_in = local_si;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700464 return false;
465 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700466
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700467 return true;
468 });
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700469
470 if (error) {
471 return false;
472 }
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700473 }
474
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700475 if (s != nullptr) {
476 TRACE_TYPE(LOOKUP, "si %s sym %s s->st_value = %p, "
477 "found in %s, base = %p, load bias = %p",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700478 si_from->get_realpath(), name, reinterpret_cast<void*>(s->st_value),
479 (*si_found_in)->get_realpath(), reinterpret_cast<void*>((*si_found_in)->base),
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700480 reinterpret_cast<void*>((*si_found_in)->load_bias));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700481 }
Iliyan Malchev6ed80c82009-09-28 19:38:04 -0700482
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700483 *symbol = s;
484 return true;
Iliyan Malchev6ed80c82009-09-28 19:38:04 -0700485}
486
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700487ProtectedDataGuard::ProtectedDataGuard() {
488 if (ref_count_++ == 0) {
489 protect_data(PROT_READ | PROT_WRITE);
490 }
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700491
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700492 if (ref_count_ == 0) { // overflow
493 __libc_fatal("Too many nested calls to dlopen()");
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -0800494 }
Dimitry Ivanov68e6c032017-02-01 12:55:11 -0800495}
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -0800496
Dimitry Ivanov68e6c032017-02-01 12:55:11 -0800497ProtectedDataGuard::~ProtectedDataGuard() {
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700498 if (--ref_count_ == 0) {
499 protect_data(PROT_READ);
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -0800500 }
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700501}
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -0800502
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700503void ProtectedDataGuard::protect_data(int protection) {
504 g_soinfo_allocator.protect_all(protection);
505 g_soinfo_links_allocator.protect_all(protection);
506 g_namespace_allocator.protect_all(protection);
507 g_namespace_list_allocator.protect_all(protection);
508}
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -0800509
510size_t ProtectedDataGuard::ref_count_ = 0;
511
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700512// Each size has it's own allocator.
513template<size_t size>
514class SizeBasedAllocator {
515 public:
516 static void* alloc() {
517 return allocator_.alloc();
518 }
Dmitriy Ivanov4bea4982014-08-29 14:01:48 -0700519
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700520 static void free(void* ptr) {
521 allocator_.free(ptr);
522 }
Dmitriy Ivanov4bea4982014-08-29 14:01:48 -0700523
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700524 private:
525 static LinkerBlockAllocator allocator_;
526};
527
528template<size_t size>
529LinkerBlockAllocator SizeBasedAllocator<size>::allocator_(size);
530
531template<typename T>
532class TypeBasedAllocator {
533 public:
534 static T* alloc() {
535 return reinterpret_cast<T*>(SizeBasedAllocator<sizeof(T)>::alloc());
536 }
537
538 static void free(T* ptr) {
539 SizeBasedAllocator<sizeof(T)>::free(ptr);
540 }
541};
542
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700543class LoadTask {
544 public:
545 struct deleter_t {
546 void operator()(LoadTask* t) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700547 t->~LoadTask();
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700548 TypeBasedAllocator<LoadTask>::free(t);
549 }
550 };
551
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700552 static deleter_t deleter;
553
Dimitry Ivanov7d429d32017-02-01 15:28:52 -0800554 static LoadTask* create(const char* name,
555 soinfo* needed_by,
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700556 std::unordered_map<const soinfo*, ElfReader>* readers_map) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700557 LoadTask* ptr = TypeBasedAllocator<LoadTask>::alloc();
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700558 return new (ptr) LoadTask(name, needed_by, readers_map);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700559 }
560
561 const char* get_name() const {
562 return name_;
563 }
564
565 soinfo* get_needed_by() const {
566 return needed_by_;
567 }
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700568
569 soinfo* get_soinfo() const {
570 return si_;
571 }
572
573 void set_soinfo(soinfo* si) {
574 si_ = si;
575 }
576
577 off64_t get_file_offset() const {
578 return file_offset_;
579 }
580
581 void set_file_offset(off64_t offset) {
582 file_offset_ = offset;
583 }
584
585 int get_fd() const {
586 return fd_;
587 }
588
589 void set_fd(int fd, bool assume_ownership) {
590 fd_ = fd;
591 close_fd_ = assume_ownership;
592 }
593
594 const android_dlextinfo* get_extinfo() const {
595 return extinfo_;
596 }
597
598 void set_extinfo(const android_dlextinfo* extinfo) {
599 extinfo_ = extinfo;
600 }
601
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700602 bool is_dt_needed() const {
603 return is_dt_needed_;
604 }
605
606 void set_dt_needed(bool is_dt_needed) {
607 is_dt_needed_ = is_dt_needed;
608 }
609
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700610 const ElfReader& get_elf_reader() const {
611 CHECK(si_ != nullptr);
612 return (*elf_readers_map_)[si_];
613 }
614
615 ElfReader& get_elf_reader() {
616 CHECK(si_ != nullptr);
617 return (*elf_readers_map_)[si_];
618 }
619
620 std::unordered_map<const soinfo*, ElfReader>* get_readers_map() {
621 return elf_readers_map_;
622 }
623
624 bool read(const char* realpath, off64_t file_size) {
625 ElfReader& elf_reader = get_elf_reader();
626 return elf_reader.Read(realpath, fd_, file_offset_, file_size);
627 }
628
629 bool load() {
630 ElfReader& elf_reader = get_elf_reader();
631 if (!elf_reader.Load(extinfo_)) {
632 return false;
633 }
634
635 si_->base = elf_reader.load_start();
636 si_->size = elf_reader.load_size();
Dimitry Ivanovf45b0e92016-01-15 11:13:35 -0800637 si_->set_mapped_by_caller(elf_reader.is_mapped_by_caller());
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700638 si_->load_bias = elf_reader.load_bias();
639 si_->phnum = elf_reader.phdr_count();
640 si_->phdr = elf_reader.loaded_phdr();
641
642 return true;
643 }
644
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700645 private:
Dimitry Ivanov7d429d32017-02-01 15:28:52 -0800646 LoadTask(const char* name,
647 soinfo* needed_by,
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700648 std::unordered_map<const soinfo*, ElfReader>* readers_map)
649 : name_(name), needed_by_(needed_by), si_(nullptr),
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700650 fd_(-1), close_fd_(false), file_offset_(0), elf_readers_map_(readers_map),
651 is_dt_needed_(false) {}
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700652
653 ~LoadTask() {
654 if (fd_ != -1 && close_fd_) {
655 close(fd_);
656 }
657 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700658
659 const char* name_;
660 soinfo* needed_by_;
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700661 soinfo* si_;
662 const android_dlextinfo* extinfo_;
663 int fd_;
664 bool close_fd_;
665 off64_t file_offset_;
666 std::unordered_map<const soinfo*, ElfReader>* elf_readers_map_;
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700667 // TODO(dimitry): needed by workaround for http://b/26394120 (the grey-list)
668 bool is_dt_needed_;
669 // END OF WORKAROUND
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700670
671 DISALLOW_IMPLICIT_CONSTRUCTORS(LoadTask);
672};
673
Ningsheng Jiane93be992014-09-16 15:22:10 +0800674LoadTask::deleter_t LoadTask::deleter;
675
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700676template <typename T>
677using linked_list_t = LinkedList<T, TypeBasedAllocator<LinkedListEntry<T>>>;
678
679typedef linked_list_t<soinfo> SoinfoLinkedList;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700680typedef linked_list_t<const char> StringLinkedList;
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700681typedef std::vector<LoadTask*> LoadTaskList;
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700682
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800683enum walk_action_result_t : uint32_t {
684 kWalkStop = 0,
685 kWalkContinue = 1,
686 kWalkSkip = 2
687};
Dmitriy Ivanovaa0f2bd2014-07-28 17:32:20 -0700688
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700689// This function walks down the tree of soinfo dependencies
690// in breadth-first order and
691// * calls action(soinfo* si) for each node, and
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800692// * terminates walk if action returns kWalkStop
693// * skips children of the node if action
694// return kWalkSkip
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700695//
696// walk_dependencies_tree returns false if walk was terminated
697// by the action and true otherwise.
698template<typename F>
699static bool walk_dependencies_tree(soinfo* root_soinfos[], size_t root_soinfos_size, F action) {
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700700 SoinfoLinkedList visit_list;
701 SoinfoLinkedList visited;
702
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700703 for (size_t i = 0; i < root_soinfos_size; ++i) {
704 visit_list.push_back(root_soinfos[i]);
705 }
706
707 soinfo* si;
708 while ((si = visit_list.pop_front()) != nullptr) {
709 if (visited.contains(si)) {
Dmitriy Ivanov042426b2014-08-12 21:02:13 -0700710 continue;
711 }
712
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800713 walk_action_result_t result = action(si);
714
715 if (result == kWalkStop) {
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700716 return false;
Dmitriy Ivanovaa0f2bd2014-07-28 17:32:20 -0700717 }
718
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700719 visited.push_back(si);
720
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800721 if (result != kWalkSkip) {
722 si->get_children().for_each([&](soinfo* child) {
723 visit_list.push_back(child);
724 });
725 }
Dmitriy Ivanovaa0f2bd2014-07-28 17:32:20 -0700726 }
727
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700728 return true;
729}
730
731
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800732static const ElfW(Sym)* dlsym_handle_lookup(android_namespace_t* ns,
733 soinfo* root,
734 soinfo* skip_until,
735 soinfo** found,
736 SymbolName& symbol_name,
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800737 const version_info* vi) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700738 const ElfW(Sym)* result = nullptr;
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700739 bool skip_lookup = skip_until != nullptr;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700740
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700741 walk_dependencies_tree(&root, 1, [&](soinfo* current_soinfo) {
742 if (skip_lookup) {
743 skip_lookup = current_soinfo != skip_until;
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800744 return kWalkContinue;
745 }
746
747 if (!ns->is_accessible(current_soinfo)) {
748 return kWalkSkip;
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700749 }
750
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800751 if (!current_soinfo->find_symbol_by_name(symbol_name, vi, &result)) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700752 result = nullptr;
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800753 return kWalkStop;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700754 }
755
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700756 if (result != nullptr) {
757 *found = current_soinfo;
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800758 return kWalkStop;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700759 }
760
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800761 return kWalkContinue;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700762 });
763
764 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800765}
766
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800767static const ElfW(Sym)* dlsym_linear_lookup(android_namespace_t* ns,
768 const char* name,
769 const version_info* vi,
770 soinfo** found,
771 soinfo* caller,
772 void* handle);
773
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700774// This is used by dlsym(3). It performs symbol lookup only within the
775// specified soinfo object and its dependencies in breadth first order.
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800776static const ElfW(Sym)* dlsym_handle_lookup(soinfo* si,
777 soinfo** found,
778 const char* name,
779 const version_info* vi) {
Dmitriy Ivanovf439b5a2015-05-30 13:04:39 -0700780 // According to man dlopen(3) and posix docs in the case when si is handle
781 // of the main executable we need to search not only in the executable and its
782 // dependencies but also in all libraries loaded with RTLD_GLOBAL.
783 //
784 // Since RTLD_GLOBAL is always set for the main executable and all dt_needed shared
785 // libraries and they are loaded in breath-first (correct) order we can just execute
786 // dlsym(RTLD_DEFAULT, ...); instead of doing two stage lookup.
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700787 if (si == solist_get_somain()) {
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800788 return dlsym_linear_lookup(&g_default_namespace, name, vi, found, nullptr, RTLD_DEFAULT);
Dmitriy Ivanovf439b5a2015-05-30 13:04:39 -0700789 }
790
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700791 SymbolName symbol_name(name);
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800792 // note that the namespace is not the namespace associated with caller_addr
793 // we use ns associated with root si intentionally here. Using caller_ns
794 // causes problems when user uses dlopen_ext to open a library in the separate
795 // namespace and then calls dlsym() on the handle.
796 return dlsym_handle_lookup(si->get_primary_namespace(), si, nullptr, found, symbol_name, vi);
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700797}
798
Brian Carlstromd4ee82d2013-02-28 15:58:45 -0800799/* This is used by dlsym(3) to performs a global symbol lookup. If the
800 start value is null (for RTLD_DEFAULT), the search starts at the
801 beginning of the global solist. Otherwise the search starts at the
802 specified soinfo (for RTLD_NEXT).
Iliyan Malchev6ed80c82009-09-28 19:38:04 -0700803 */
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800804static const ElfW(Sym)* dlsym_linear_lookup(android_namespace_t* ns,
805 const char* name,
806 const version_info* vi,
807 soinfo** found,
808 soinfo* caller,
809 void* handle) {
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800810 SymbolName symbol_name(name);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800811
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -0700812 auto& soinfo_list = ns->soinfo_list();
813 auto start = soinfo_list.begin();
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -0700814
815 if (handle == RTLD_NEXT) {
Dmitriy Ivanovb96ac412015-05-22 12:34:42 -0700816 if (caller == nullptr) {
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -0700817 return nullptr;
818 } else {
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -0700819 auto it = soinfo_list.find(caller);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700820 CHECK (it != soinfo_list.end());
821 start = ++it;
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -0700822 }
Elliott Hughescade4c32012-12-20 14:42:14 -0800823 }
824
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700825 const ElfW(Sym)* s = nullptr;
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -0700826 for (auto it = start, end = soinfo_list.end(); it != end; ++it) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700827 soinfo* si = *it;
Dmitriy Ivanov19133522015-06-02 17:36:54 -0700828 // Do not skip RTLD_LOCAL libraries in dlsym(RTLD_DEFAULT, ...)
Elliott Hughes5bc78c82016-11-16 11:35:43 -0800829 // if the library is opened by application with target api level < M.
Dmitriy Ivanov19133522015-06-02 17:36:54 -0700830 // See http://b/21565766
Elliott Hughes5bc78c82016-11-16 11:35:43 -0800831 if ((si->get_rtld_flags() & RTLD_GLOBAL) == 0 &&
832 si->get_target_sdk_version() >= __ANDROID_API_M__) {
Dmitriy Ivanove8ba50f2014-09-15 17:00:10 -0700833 continue;
834 }
835
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800836 if (!si->find_symbol_by_name(symbol_name, vi, &s)) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700837 return nullptr;
838 }
839
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700840 if (s != nullptr) {
Elliott Hughescade4c32012-12-20 14:42:14 -0800841 *found = si;
842 break;
Matt Fischer1698d9e2009-12-31 12:17:56 -0600843 }
Elliott Hughescade4c32012-12-20 14:42:14 -0800844 }
Matt Fischer1698d9e2009-12-31 12:17:56 -0600845
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700846 // If not found - use dlsym_handle_lookup for caller's
847 // local_group unless it is part of the global group in which
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -0700848 // case we already did it.
849 if (s == nullptr && caller != nullptr &&
850 (caller->get_rtld_flags() & RTLD_GLOBAL) == 0) {
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800851 soinfo* local_group_root = caller->get_local_group_root();
852
853 return dlsym_handle_lookup(local_group_root->get_primary_namespace(),
854 local_group_root,
855 (handle == RTLD_NEXT) ? caller : nullptr,
856 found,
857 symbol_name,
858 vi);
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -0700859 }
860
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700861 if (s != nullptr) {
Elliott Hughesc00f2cb2013-10-04 17:01:33 -0700862 TRACE_TYPE(LOOKUP, "%s s->st_value = %p, found->base = %p",
863 name, reinterpret_cast<void*>(s->st_value), reinterpret_cast<void*>((*found)->base));
Elliott Hughescade4c32012-12-20 14:42:14 -0800864 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800865
Elliott Hughescade4c32012-12-20 14:42:14 -0800866 return s;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800867}
868
Kito Chengfa8c05d2013-03-12 14:58:06 +0800869soinfo* find_containing_library(const void* p) {
Elliott Hughes0266ae52014-02-10 17:46:57 -0800870 ElfW(Addr) address = reinterpret_cast<ElfW(Addr)>(p);
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700871 for (soinfo* si = solist_get_head(); si != nullptr; si = si->next) {
Kito Chengfa8c05d2013-03-12 14:58:06 +0800872 if (address >= si->base && address - si->base < si->size) {
873 return si;
Matt Fischere2a8b1f2009-12-31 12:17:40 -0600874 }
Kito Chengfa8c05d2013-03-12 14:58:06 +0800875 }
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700876 return nullptr;
Matt Fischere2a8b1f2009-12-31 12:17:40 -0600877}
878
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700879class ZipArchiveCache {
880 public:
881 ZipArchiveCache() {}
882 ~ZipArchiveCache();
883
884 bool get_or_open(const char* zip_path, ZipArchiveHandle* handle);
885 private:
886 DISALLOW_COPY_AND_ASSIGN(ZipArchiveCache);
887
888 std::unordered_map<std::string, ZipArchiveHandle> cache_;
889};
890
891bool ZipArchiveCache::get_or_open(const char* zip_path, ZipArchiveHandle* handle) {
892 std::string key(zip_path);
893
894 auto it = cache_.find(key);
895 if (it != cache_.end()) {
896 *handle = it->second;
897 return true;
898 }
899
900 int fd = TEMP_FAILURE_RETRY(open(zip_path, O_RDONLY | O_CLOEXEC));
901 if (fd == -1) {
902 return false;
903 }
904
905 if (OpenArchiveFd(fd, "", handle) != 0) {
906 // invalid zip-file (?)
Yabin Cui722072d2016-03-21 17:10:12 -0700907 CloseArchive(handle);
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700908 close(fd);
909 return false;
910 }
911
912 cache_[key] = *handle;
913 return true;
914}
915
916ZipArchiveCache::~ZipArchiveCache() {
Dmitriy Ivanov5dce8942015-10-13 12:14:16 -0700917 for (const auto& it : cache_) {
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700918 CloseArchive(it.second);
919 }
920}
921
922static int open_library_in_zipfile(ZipArchiveCache* zip_archive_cache,
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700923 const char* const input_path,
924 off64_t* file_offset, std::string* realpath) {
925 std::string normalized_path;
926 if (!normalize_path(input_path, &normalized_path)) {
927 return -1;
928 }
929
930 const char* const path = normalized_path.c_str();
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700931 TRACE("Trying zip file open from path \"%s\" -> normalized \"%s\"", input_path, path);
Simon Baldwinaef71952015-01-16 13:22:54 +0000932
Dmitriy Ivanov402a7502015-06-09 13:46:51 -0700933 // Treat an '!/' separator inside a path as the separator between the name
Simon Baldwinaef71952015-01-16 13:22:54 +0000934 // of the zip file on disk and the subdirectory to search within it.
Dmitriy Ivanov402a7502015-06-09 13:46:51 -0700935 // For example, if path is "foo.zip!/bar/bas/x.so", then we search for
Simon Baldwinaef71952015-01-16 13:22:54 +0000936 // "bar/bas/x.so" within "foo.zip".
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700937 const char* const separator = strstr(path, kZipFileSeparator);
Simon Baldwinaef71952015-01-16 13:22:54 +0000938 if (separator == nullptr) {
939 return -1;
Elliott Hughes124fae92012-10-31 14:20:03 -0700940 }
Simon Baldwinaef71952015-01-16 13:22:54 +0000941
942 char buf[512];
943 if (strlcpy(buf, path, sizeof(buf)) >= sizeof(buf)) {
944 PRINT("Warning: ignoring very long library path: %s", path);
945 return -1;
946 }
947
948 buf[separator - path] = '\0';
949
950 const char* zip_path = buf;
Dmitriy Ivanov402a7502015-06-09 13:46:51 -0700951 const char* file_path = &buf[separator - path + 2];
Simon Baldwinaef71952015-01-16 13:22:54 +0000952 int fd = TEMP_FAILURE_RETRY(open(zip_path, O_RDONLY | O_CLOEXEC));
953 if (fd == -1) {
954 return -1;
955 }
956
957 ZipArchiveHandle handle;
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700958 if (!zip_archive_cache->get_or_open(zip_path, &handle)) {
Simon Baldwinaef71952015-01-16 13:22:54 +0000959 // invalid zip-file (?)
960 close(fd);
961 return -1;
962 }
963
Simon Baldwinaef71952015-01-16 13:22:54 +0000964 ZipEntry entry;
965
Yusuke Sato56f40fb2015-06-25 14:56:07 -0700966 if (FindEntry(handle, ZipString(file_path), &entry) != 0) {
Simon Baldwinaef71952015-01-16 13:22:54 +0000967 // Entry was not found.
968 close(fd);
969 return -1;
970 }
971
972 // Check if it is properly stored
973 if (entry.method != kCompressStored || (entry.offset % PAGE_SIZE) != 0) {
974 close(fd);
975 return -1;
976 }
977
978 *file_offset = entry.offset;
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700979
980 if (realpath_fd(fd, realpath)) {
981 *realpath += separator;
982 } else {
983 PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.",
984 normalized_path.c_str());
985 *realpath = normalized_path;
986 }
987
Simon Baldwinaef71952015-01-16 13:22:54 +0000988 return fd;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800989}
990
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700991static bool format_path(char* buf, size_t buf_size, const char* path, const char* name) {
992 int n = __libc_format_buffer(buf, buf_size, "%s/%s", path, name);
993 if (n < 0 || n >= static_cast<int>(buf_size)) {
994 PRINT("Warning: ignoring very long library path: %s/%s", path, name);
995 return false;
996 }
Simon Baldwinaef71952015-01-16 13:22:54 +0000997
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700998 return true;
999}
1000
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001001static int open_library_on_paths(ZipArchiveCache* zip_archive_cache,
1002 const char* name, off64_t* file_offset,
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001003 const std::vector<std::string>& paths,
1004 std::string* realpath) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001005 for (const auto& path : paths) {
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07001006 char buf[512];
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001007 if (!format_path(buf, sizeof(buf), path.c_str(), name)) {
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07001008 continue;
1009 }
1010
1011 int fd = -1;
Dmitriy Ivanov730ed9d2015-07-16 04:52:06 -07001012 if (strstr(buf, kZipFileSeparator) != nullptr) {
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001013 fd = open_library_in_zipfile(zip_archive_cache, buf, file_offset, realpath);
Simon Baldwinaef71952015-01-16 13:22:54 +00001014 }
1015
1016 if (fd == -1) {
1017 fd = TEMP_FAILURE_RETRY(open(buf, O_RDONLY | O_CLOEXEC));
1018 if (fd != -1) {
1019 *file_offset = 0;
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001020 if (!realpath_fd(fd, realpath)) {
1021 PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.", buf);
1022 *realpath = buf;
1023 }
Simon Baldwinaef71952015-01-16 13:22:54 +00001024 }
1025 }
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07001026
1027 if (fd != -1) {
1028 return fd;
1029 }
Simon Baldwinaef71952015-01-16 13:22:54 +00001030 }
1031
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07001032 return -1;
Simon Baldwinaef71952015-01-16 13:22:54 +00001033}
1034
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001035static int open_library(android_namespace_t* ns,
1036 ZipArchiveCache* zip_archive_cache,
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001037 const char* name, soinfo *needed_by,
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001038 off64_t* file_offset, std::string* realpath) {
Elliott Hughesca0c11b2013-03-12 10:40:45 -07001039 TRACE("[ opening %s ]", name);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001040
Elliott Hughes124fae92012-10-31 14:20:03 -07001041 // 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 -07001042 if (strchr(name, '/') != nullptr) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001043 int fd = -1;
1044
Dmitriy Ivanov730ed9d2015-07-16 04:52:06 -07001045 if (strstr(name, kZipFileSeparator) != nullptr) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001046 fd = open_library_in_zipfile(zip_archive_cache, name, file_offset, realpath);
1047 }
1048
1049 if (fd == -1) {
1050 fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_CLOEXEC));
Simon Baldwinaef71952015-01-16 13:22:54 +00001051 if (fd != -1) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001052 *file_offset = 0;
1053 if (!realpath_fd(fd, realpath)) {
1054 PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.", name);
1055 *realpath = name;
1056 }
Simon Baldwinaef71952015-01-16 13:22:54 +00001057 }
1058 }
1059
Dmitriy Ivanove44fffd2015-03-17 17:12:18 -07001060 return fd;
Elliott Hughes124fae92012-10-31 14:20:03 -07001061 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001062
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001063 // Otherwise we try LD_LIBRARY_PATH first, and fall back to the default library path
1064 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 -07001065 if (fd == -1 && needed_by != nullptr) {
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001066 fd = open_library_on_paths(zip_archive_cache, name, file_offset, needed_by->get_dt_runpath(), realpath);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001067 // Check if the library is accessible
1068 if (fd != -1 && !ns->is_accessible(*realpath)) {
1069 fd = -1;
1070 }
Evgenii Stepanov68650822015-06-10 13:38:39 -07001071 }
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001072
Elliott Hughes124fae92012-10-31 14:20:03 -07001073 if (fd == -1) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001074 fd = open_library_on_paths(zip_archive_cache, name, file_offset, ns->get_default_library_paths(), realpath);
Elliott Hughes124fae92012-10-31 14:20:03 -07001075 }
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001076
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001077 // TODO(dimitry): workaround for http://b/26394120 (the grey-list)
Dimitry Ivanov35c8e3b2017-02-27 12:17:47 -08001078 if (fd == -1 && ns != &g_default_namespace && is_greylisted(ns, name, needed_by)) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001079 // try searching for it on default_namespace default_library_path
1080 fd = open_library_on_paths(zip_archive_cache, name, file_offset,
1081 g_default_namespace.get_default_library_paths(), realpath);
1082 }
1083 // END OF WORKAROUND
1084
Elliott Hughes124fae92012-10-31 14:20:03 -07001085 return fd;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001086}
1087
Dimitry Ivanov3f660572016-09-09 10:00:39 -07001088const char* fix_dt_needed(const char* dt_needed, const char* sopath __unused) {
Dmitriy Ivanovd974e882015-05-27 18:29:41 -07001089#if !defined(__LP64__)
1090 // Work around incorrect DT_NEEDED entries for old apps: http://b/21364029
Elliott Hughes5bc78c82016-11-16 11:35:43 -08001091 if (get_application_target_sdk_version() < __ANDROID_API_M__) {
Dmitriy Ivanovd974e882015-05-27 18:29:41 -07001092 const char* bname = basename(dt_needed);
1093 if (bname != dt_needed) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001094 DL_WARN("library \"%s\" has invalid DT_NEEDED entry \"%s\"", sopath, dt_needed);
1095 add_dlwarning(sopath, "invalid DT_NEEDED entry", dt_needed);
Dmitriy Ivanovd974e882015-05-27 18:29:41 -07001096 }
1097
1098 return bname;
1099 }
1100#endif
1101 return dt_needed;
1102}
1103
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001104template<typename F>
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001105static void for_each_dt_needed(const ElfReader& elf_reader, F action) {
1106 for (const ElfW(Dyn)* d = elf_reader.dynamic(); d->d_tag != DT_NULL; ++d) {
1107 if (d->d_tag == DT_NEEDED) {
1108 action(fix_dt_needed(elf_reader.get_string(d->d_un.d_val), elf_reader.name()));
1109 }
1110 }
1111}
1112
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001113static bool load_library(android_namespace_t* ns,
1114 LoadTask* task,
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001115 LoadTaskList* load_tasks,
1116 int rtld_flags,
1117 const std::string& realpath) {
1118 off64_t file_offset = task->get_file_offset();
1119 const char* name = task->get_name();
1120 const android_dlextinfo* extinfo = task->get_extinfo();
1121
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001122 if ((file_offset % PAGE_SIZE) != 0) {
Dmitriy Ivanova6c12792014-10-21 12:09:18 -07001123 DL_ERR("file offset for the library \"%s\" is not page-aligned: %" PRId64, name, file_offset);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001124 return false;
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001125 }
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001126 if (file_offset < 0) {
1127 DL_ERR("file offset for the library \"%s\" is negative: %" PRId64, name, file_offset);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001128 return false;
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001129 }
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001130
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001131 struct stat file_stat;
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001132 if (TEMP_FAILURE_RETRY(fstat(task->get_fd(), &file_stat)) != 0) {
Dmitriy Ivanova6c12792014-10-21 12:09:18 -07001133 DL_ERR("unable to stat file for the library \"%s\": %s", name, strerror(errno));
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001134 return false;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001135 }
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001136 if (file_offset >= file_stat.st_size) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07001137 DL_ERR("file offset for the library \"%s\" >= file size: %" PRId64 " >= %" PRId64,
1138 name, file_offset, file_stat.st_size);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001139 return false;
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001140 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001141
1142 // Check for symlink and other situations where
Dmitriy Ivanov9b821362015-04-02 16:03:56 -07001143 // file can have different names, unless ANDROID_DLEXT_FORCE_LOAD is set
1144 if (extinfo == nullptr || (extinfo->flags & ANDROID_DLEXT_FORCE_LOAD) == 0) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001145 auto predicate = [&](soinfo* si) {
1146 return si->get_st_dev() != 0 &&
1147 si->get_st_ino() != 0 &&
1148 si->get_st_dev() == file_stat.st_dev &&
1149 si->get_st_ino() == file_stat.st_ino &&
1150 si->get_file_offset() == file_offset;
1151 };
1152
1153 soinfo* si = ns->soinfo_list().find_if(predicate);
1154
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001155 if (si != nullptr) {
1156 TRACE("library \"%s\" is already loaded under different name/path \"%s\" - "
1157 "will return existing soinfo", name, si->get_realpath());
1158 task->set_soinfo(si);
1159 return true;
1160 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001161 }
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07001162
Dmitriy Ivanove8ba50f2014-09-15 17:00:10 -07001163 if ((rtld_flags & RTLD_NOLOAD) != 0) {
Dmitriy Ivanova6ac54a2014-09-09 10:21:42 -07001164 DL_ERR("library \"%s\" wasn't loaded and RTLD_NOLOAD prevented it", name);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001165 return false;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001166 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001167
Dimitry Ivanov22840aa2015-12-04 18:28:49 -08001168 if (!ns->is_accessible(realpath)) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001169 // TODO(dimitry): workaround for http://b/26394120 - the grey-list
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001170
1171 // TODO(dimitry) before O release: add a namespace attribute to have this enabled
1172 // only for classloader-namespaces
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001173 const soinfo* needed_by = task->is_dt_needed() ? task->get_needed_by() : nullptr;
Dimitry Ivanov35c8e3b2017-02-27 12:17:47 -08001174 if (is_greylisted(ns, name, needed_by)) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001175 // print warning only if needed by non-system library
1176 if (needed_by == nullptr || !is_system_library(needed_by->get_realpath())) {
1177 const soinfo* needed_or_dlopened_by = task->get_needed_by();
1178 const char* sopath = needed_or_dlopened_by == nullptr ? "(unknown)" :
1179 needed_or_dlopened_by->get_realpath();
1180 DL_WARN("library \"%s\" (\"%s\") needed or dlopened by \"%s\" is not accessible for the namespace \"%s\""
1181 " - the access is temporarily granted as a workaround for http://b/26394120, note that the access"
1182 " will be removed in future releases of Android.",
1183 name, realpath.c_str(), sopath, ns->get_name());
1184 add_dlwarning(sopath, "unauthorized access to", name);
1185 }
1186 } else {
1187 // do not load libraries if they are not accessible for the specified namespace.
1188 const char* needed_or_dlopened_by = task->get_needed_by() == nullptr ?
1189 "(unknown)" :
1190 task->get_needed_by()->get_realpath();
Dimitry Ivanovd17a3772016-03-01 13:11:28 -08001191
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001192 DL_ERR("library \"%s\" needed or dlopened by \"%s\" is not accessible for the namespace \"%s\"",
1193 name, needed_or_dlopened_by, ns->get_name());
Dimitry Ivanovd17a3772016-03-01 13:11:28 -08001194
Dimitry Ivanov35c8e3b2017-02-27 12:17:47 -08001195 // do not print this if a library is in the list of shared libraries for linked namespaces
1196 if (!maybe_accessible_via_namespace_links(ns, name)) {
1197 PRINT("library \"%s\" (\"%s\") needed or dlopened by \"%s\" is not accessible for the"
1198 " namespace: [name=\"%s\", ld_library_paths=\"%s\", default_library_paths=\"%s\","
1199 " permitted_paths=\"%s\"]",
1200 name, realpath.c_str(),
1201 needed_or_dlopened_by,
1202 ns->get_name(),
1203 android::base::Join(ns->get_ld_library_paths(), ':').c_str(),
1204 android::base::Join(ns->get_default_library_paths(), ':').c_str(),
1205 android::base::Join(ns->get_permitted_paths(), ':').c_str());
1206 }
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001207 return false;
1208 }
Dimitry Ivanov22840aa2015-12-04 18:28:49 -08001209 }
1210
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001211 soinfo* si = soinfo_alloc(ns, realpath.c_str(), &file_stat, file_offset, rtld_flags);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001212 if (si == nullptr) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001213 return false;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001214 }
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07001215
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001216 task->set_soinfo(si);
1217
1218 // Read the ELF header and some of the segments.
1219 if (!task->read(realpath.c_str(), file_stat.st_size)) {
Dmitriy Ivanovfd7a91e2015-11-06 10:44:37 -08001220 soinfo_free(si);
1221 task->set_soinfo(nullptr);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001222 return false;
1223 }
1224
1225 // find and set DT_RUNPATH and dt_soname
1226 // Note that these field values are temporary and are
1227 // going to be overwritten on soinfo::prelink_image
1228 // with values from PT_LOAD segments.
1229 const ElfReader& elf_reader = task->get_elf_reader();
1230 for (const ElfW(Dyn)* d = elf_reader.dynamic(); d->d_tag != DT_NULL; ++d) {
1231 if (d->d_tag == DT_RUNPATH) {
1232 si->set_dt_runpath(elf_reader.get_string(d->d_un.d_val));
1233 }
1234 if (d->d_tag == DT_SONAME) {
1235 si->set_soname(elf_reader.get_string(d->d_un.d_val));
1236 }
1237 }
1238
1239 for_each_dt_needed(task->get_elf_reader(), [&](const char* name) {
1240 load_tasks->push_back(LoadTask::create(name, si, task->get_readers_map()));
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001241 });
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07001242
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001243 return true;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001244}
1245
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001246static bool load_library(android_namespace_t* ns,
1247 LoadTask* task,
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001248 ZipArchiveCache* zip_archive_cache,
1249 LoadTaskList* load_tasks,
1250 int rtld_flags) {
1251 const char* name = task->get_name();
1252 soinfo* needed_by = task->get_needed_by();
1253 const android_dlextinfo* extinfo = task->get_extinfo();
1254
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001255 off64_t file_offset;
1256 std::string realpath;
Spencer Low0346ad72015-04-22 18:06:51 -07001257 if (extinfo != nullptr && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) {
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001258 file_offset = 0;
Spencer Low0346ad72015-04-22 18:06:51 -07001259 if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
1260 file_offset = extinfo->library_fd_offset;
1261 }
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001262
1263 if (!realpath_fd(extinfo->library_fd, &realpath)) {
1264 PRINT("warning: unable to get realpath for the library \"%s\" by extinfo->library_fd. "
1265 "Will use given name.", name);
1266 realpath = name;
1267 }
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001268
1269 task->set_fd(extinfo->library_fd, false);
1270 task->set_file_offset(file_offset);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001271 return load_library(ns, task, load_tasks, rtld_flags, realpath);
Spencer Low0346ad72015-04-22 18:06:51 -07001272 }
1273
1274 // Open the file.
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001275 int fd = open_library(ns, zip_archive_cache, name, needed_by, &file_offset, &realpath);
Spencer Low0346ad72015-04-22 18:06:51 -07001276 if (fd == -1) {
1277 DL_ERR("library \"%s\" not found", name);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001278 return false;
Spencer Low0346ad72015-04-22 18:06:51 -07001279 }
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001280
1281 task->set_fd(fd, true);
1282 task->set_file_offset(file_offset);
1283
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001284 return load_library(ns, task, load_tasks, rtld_flags, realpath);
Spencer Low0346ad72015-04-22 18:06:51 -07001285}
1286
Dimitry Ivanov3bd90612017-02-01 08:54:43 -08001287// Returns true if library was found and false otherwise
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001288static bool find_loaded_library_by_soname(android_namespace_t* ns,
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -07001289 const char* name, soinfo** candidate) {
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001290 *candidate = nullptr;
1291
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07001292 // Ignore filename with path.
1293 if (strchr(name, '/') != nullptr) {
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001294 return false;
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07001295 }
1296
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001297 return !ns->soinfo_list().visit([&](soinfo* si) {
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07001298 const char* soname = si->get_soname();
1299 if (soname != nullptr && (strcmp(name, soname) == 0)) {
Dimitry Ivanov3bd90612017-02-01 08:54:43 -08001300 *candidate = si;
1301 return false;
Ard Biesheuvel12c78bb2012-08-14 12:30:09 +02001302 }
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001303
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001304 return true;
1305 });
Ard Biesheuvel12c78bb2012-08-14 12:30:09 +02001306}
1307
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001308static bool find_library_in_linked_namespace(const android_namespace_link_t& namespace_link,
1309 LoadTask* task,
1310 int rtld_flags) {
1311 android_namespace_t* ns = namespace_link.linked_namespace();
1312
1313 soinfo* candidate;
1314 bool loaded = false;
1315
1316 std::string soname;
1317 if (find_loaded_library_by_soname(ns, task->get_name(), &candidate)) {
1318 loaded = true;
1319 soname = candidate->get_soname();
1320 } else {
1321 soname = resolve_soname(task->get_name());
1322 }
1323
1324 if (!namespace_link.is_accessible(soname.c_str())) {
1325 // the library is not accessible via namespace_link
1326 return false;
1327 }
1328
1329 // if library is already loaded - return it
1330 if (loaded) {
1331 task->set_soinfo(candidate);
1332 return true;
1333 }
1334
1335 // try to load the library - once namespace boundary is crossed
1336 // we need to load a library within separate load_group
1337 // to avoid using symbols from foreign namespace while.
1338 //
1339 // All symbols during relocation should be resolved within a
1340 // namespace to preserve library locality to a namespace.
1341 const char* name = task->get_name();
1342 if (find_libraries(ns,
1343 task->get_needed_by(),
1344 &name,
1345 1,
1346 &candidate,
1347 nullptr /* ld_preloads */,
1348 0 /* ld_preload_count*/,
1349 rtld_flags,
1350 nullptr /* extinfo*/,
1351 false /* add_as_children */,
1352 false /* search_linked_namespaces */)) {
1353 task->set_soinfo(candidate);
1354 return true;
1355 }
1356
1357 return false;
1358}
1359
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001360static bool find_library_internal(android_namespace_t* ns,
1361 LoadTask* task,
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001362 ZipArchiveCache* zip_archive_cache,
1363 LoadTaskList* load_tasks,
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001364 int rtld_flags,
1365 bool search_linked_namespaces) {
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001366 soinfo* candidate;
1367
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001368 if (find_loaded_library_by_soname(ns, task->get_name(), &candidate)) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001369 task->set_soinfo(candidate);
1370 return true;
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001371 }
Dmitriy Ivanovb648a8a2014-05-19 15:06:58 -07001372
1373 // Library might still be loaded, the accurate detection
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001374 // of this fact is done by load_library.
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001375 TRACE("[ \"%s\" find_loaded_library_by_soname failed (*candidate=%s@%p). Trying harder...]",
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001376 task->get_name(), candidate == nullptr ? "n/a" : candidate->get_realpath(), candidate);
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001377
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001378 if (load_library(ns, task, zip_archive_cache, load_tasks, rtld_flags)) {
1379 return true;
1380 }
1381
1382 if (search_linked_namespaces) {
1383 // if a library was not found - look into linked namespaces
1384 for (auto& linked_namespace : ns->linked_namespaces()) {
1385 if (find_library_in_linked_namespace(linked_namespace,
1386 task,
1387 rtld_flags)) {
1388 return true;
1389 }
1390 }
1391 }
1392
1393 return false;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001394}
1395
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001396static void soinfo_unload(soinfo* si);
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001397static void soinfo_unload(soinfo* soinfos[], size_t count);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001398
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001399// TODO: this is slightly unusual way to construct
1400// the global group for relocation. Not every RTLD_GLOBAL
1401// library is included in this group for backwards-compatibility
1402// reasons.
1403//
1404// This group consists of the main executable, LD_PRELOADs
1405// and libraries with the DF_1_GLOBAL flag set.
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001406static soinfo_list_t make_global_group(android_namespace_t* ns) {
1407 soinfo_list_t global_group;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001408 ns->soinfo_list().for_each([&](soinfo* si) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001409 if ((si->get_dt_flags_1() & DF_1_GLOBAL) != 0) {
1410 global_group.push_back(si);
1411 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001412 });
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001413
1414 return global_group;
1415}
1416
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07001417// This function provides a list of libraries to be shared
1418// by the namespace. For the default namespace this is the global
1419// group (see make_global_group). For all others this is a group
1420// of RTLD_GLOBAL libraries (which includes the global group from
1421// the default namespace).
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001422static soinfo_list_t get_shared_group(android_namespace_t* ns) {
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07001423 if (ns == &g_default_namespace) {
1424 return make_global_group(ns);
1425 }
1426
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001427 soinfo_list_t shared_group;
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07001428 ns->soinfo_list().for_each([&](soinfo* si) {
1429 if ((si->get_rtld_flags() & RTLD_GLOBAL) != 0) {
1430 shared_group.push_back(si);
1431 }
1432 });
1433
1434 return shared_group;
1435}
1436
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001437static void shuffle(std::vector<LoadTask*>* v) {
1438 for (size_t i = 0, size = v->size(); i < size; ++i) {
1439 size_t n = size - i;
1440 size_t r = arc4random_uniform(n);
1441 std::swap((*v)[n-1], (*v)[r]);
1442 }
1443}
1444
Evgenii Stepanov0cdef7e2015-07-06 17:56:31 -07001445// add_as_children - add first-level loaded libraries (i.e. library_names[], but
1446// not their transitive dependencies) as children of the start_with library.
1447// This is false when find_libraries is called for dlopen(), when newly loaded
1448// libraries must form a disjoint tree.
Dimitry Ivanov3f660572016-09-09 10:00:39 -07001449bool find_libraries(android_namespace_t* ns,
1450 soinfo* start_with,
1451 const char* const library_names[],
1452 size_t library_names_count,
1453 soinfo* soinfos[],
1454 std::vector<soinfo*>* ld_preloads,
1455 size_t ld_preloads_count,
1456 int rtld_flags,
1457 const android_dlextinfo* extinfo,
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001458 bool add_as_children,
1459 bool search_linked_namespaces) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001460 // Step 0: prepare.
1461 LoadTaskList load_tasks;
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001462 std::unordered_map<const soinfo*, ElfReader> readers_map;
1463
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001464 for (size_t i = 0; i < library_names_count; ++i) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001465 const char* name = library_names[i];
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001466 load_tasks.push_back(LoadTask::create(name, start_with, &readers_map));
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001467 }
1468
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001469 // Construct global_group.
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001470 soinfo_list_t global_group = make_global_group(ns);
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001471
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001472 // If soinfos array is null allocate one on stack.
1473 // The array is needed in case of failure; for example
1474 // when library_names[] = {libone.so, libtwo.so} and libone.so
1475 // is loaded correctly but libtwo.so failed for some reason.
1476 // In this case libone.so should be unloaded on return.
1477 // See also implementation of failure_guard below.
1478
1479 if (soinfos == nullptr) {
1480 size_t soinfos_size = sizeof(soinfo*)*library_names_count;
1481 soinfos = reinterpret_cast<soinfo**>(alloca(soinfos_size));
1482 memset(soinfos, 0, soinfos_size);
1483 }
1484
1485 // list of libraries to link - see step 2.
1486 size_t soinfos_count = 0;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001487
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001488 auto scope_guard = make_scope_guard([&]() {
1489 for (LoadTask* t : load_tasks) {
1490 LoadTask::deleter(t);
1491 }
1492 });
1493
Dmitriy Ivanovd9ff7222014-09-08 16:22:22 -07001494 auto failure_guard = make_scope_guard([&]() {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001495 // Housekeeping
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001496 soinfo_unload(soinfos, soinfos_count);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001497 });
1498
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001499 ZipArchiveCache zip_archive_cache;
1500
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001501 // Step 1: expand the list of load_tasks to include
1502 // all DT_NEEDED libraries (do not load them just yet)
1503 for (size_t i = 0; i<load_tasks.size(); ++i) {
1504 LoadTask* task = load_tasks[i];
Evgenii Stepanov68650822015-06-10 13:38:39 -07001505 soinfo* needed_by = task->get_needed_by();
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001506
Dmitriy Ivanovedfc9f62015-09-02 16:32:02 -07001507 bool is_dt_needed = needed_by != nullptr && (needed_by != start_with || add_as_children);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001508 task->set_extinfo(is_dt_needed ? nullptr : extinfo);
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001509 task->set_dt_needed(is_dt_needed);
Dmitriy Ivanovedfc9f62015-09-02 16:32:02 -07001510
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001511 if (!find_library_internal(ns,
1512 task,
1513 &zip_archive_cache,
1514 &load_tasks,
1515 rtld_flags,
1516 search_linked_namespaces || is_dt_needed)) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001517 return false;
1518 }
1519
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001520 soinfo* si = task->get_soinfo();
1521
Dmitriy Ivanovedfc9f62015-09-02 16:32:02 -07001522 if (is_dt_needed) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001523 needed_by->add_child(si);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001524
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001525 if (si->is_linked()) {
1526 si->increment_ref_count();
1527 }
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001528 }
1529
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001530 // When ld_preloads is not null, the first
1531 // ld_preloads_count libs are in fact ld_preloads.
1532 if (ld_preloads != nullptr && soinfos_count < ld_preloads_count) {
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07001533 ld_preloads->push_back(si);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001534 }
1535
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001536 if (soinfos_count < library_names_count) {
1537 soinfos[soinfos_count++] = si;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001538 }
1539 }
1540
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001541 // Step 2: Load libraries in random order (see b/24047022)
1542 LoadTaskList load_list;
1543 for (auto&& task : load_tasks) {
1544 soinfo* si = task->get_soinfo();
1545 auto pred = [&](const LoadTask* t) {
1546 return t->get_soinfo() == si;
1547 };
1548
1549 if (!si->is_linked() &&
1550 std::find_if(load_list.begin(), load_list.end(), pred) == load_list.end() ) {
1551 load_list.push_back(task);
1552 }
1553 }
1554 shuffle(&load_list);
1555
1556 for (auto&& task : load_list) {
1557 if (!task->load()) {
1558 return false;
1559 }
1560 }
1561
1562 // Step 3: pre-link all DT_NEEDED libraries in breadth first order.
1563 for (auto&& task : load_tasks) {
1564 soinfo* si = task->get_soinfo();
1565 if (!si->is_linked() && !si->prelink_image()) {
1566 return false;
1567 }
1568 }
1569
1570 // Step 4: Add LD_PRELOADed libraries to the global group for
1571 // future runs. There is no need to explicitly add them to
1572 // the global group for this run because they are going to
1573 // appear in the local group in the correct order.
1574 if (ld_preloads != nullptr) {
1575 for (auto&& si : *ld_preloads) {
1576 si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL);
1577 }
1578 }
1579
1580
1581 // Step 5: link libraries.
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001582 soinfo_list_t local_group;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001583 walk_dependencies_tree(
Evgenii Stepanov0cdef7e2015-07-06 17:56:31 -07001584 (start_with != nullptr && add_as_children) ? &start_with : soinfos,
1585 (start_with != nullptr && add_as_children) ? 1 : soinfos_count,
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001586 [&] (soinfo* si) {
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -08001587 if (ns->is_accessible(si)) {
1588 local_group.push_back(si);
1589 return kWalkContinue;
1590 } else {
1591 return kWalkSkip;
1592 }
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001593 });
1594
1595 bool linked = local_group.visit([&](soinfo* si) {
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001596 if (!si->is_linked()) {
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -07001597 if (!si->link_image(global_group, local_group, extinfo) ||
1598 !get_cfi_shadow()->AfterLoad(si, solist_get_head())) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001599 return false;
1600 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001601 }
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001602
1603 return true;
1604 });
1605
1606 if (linked) {
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001607 local_group.for_each([](soinfo* si) {
1608 if (!si->is_linked()) {
1609 si->set_linked();
1610 }
1611 });
1612
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001613 failure_guard.disable();
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001614 }
1615
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001616 return linked;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001617}
1618
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001619static soinfo* find_library(android_namespace_t* ns,
1620 const char* name, int rtld_flags,
Evgenii Stepanov0cdef7e2015-07-06 17:56:31 -07001621 const android_dlextinfo* extinfo,
1622 soinfo* needed_by) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001623 soinfo* si;
1624
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001625 if (name == nullptr) {
Dimitry Ivanov3f660572016-09-09 10:00:39 -07001626 si = solist_get_somain();
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001627 } else if (!find_libraries(ns,
1628 needed_by,
1629 &name,
1630 1,
1631 &si,
1632 nullptr,
1633 0,
1634 rtld_flags,
1635 extinfo,
1636 false /* add_as_children */,
1637 true /* search_linked_namespaces */)) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001638 return nullptr;
1639 }
1640
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001641 si->increment_ref_count();
1642
Elliott Hughesd23736e2012-11-01 15:16:56 -07001643 return si;
1644}
Elliott Hughesbedfe382012-08-14 14:07:59 -07001645
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001646static void soinfo_unload(soinfo* root) {
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001647 if (root->is_linked()) {
1648 root = root->get_local_group_root();
1649 }
1650
Dimitry Ivanov6705e8c2017-03-21 10:29:06 -07001651 ScopedTrace trace((std::string("unload ") + root->get_realpath()).c_str());
1652
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001653 if (!root->can_unload()) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001654 TRACE("not unloading \"%s\" - the binary is flagged with NODELETE", root->get_realpath());
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -07001655 return;
1656 }
1657
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001658 soinfo_unload(&root, 1);
1659}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001660
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001661static void soinfo_unload(soinfo* soinfos[], size_t count) {
1662 // Note that the library can be loaded but not linked;
1663 // in which case there is no root but we still need
1664 // to walk the tree and unload soinfos involved.
1665 //
1666 // This happens on unsuccessful dlopen, when one of
1667 // the DT_NEEDED libraries could not be linked/found.
1668 if (count == 0) {
1669 return;
1670 }
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001671
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001672 soinfo_list_t unload_list;
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001673 for (size_t i = 0; i < count; ++i) {
1674 soinfo* si = soinfos[i];
Dmitriy Ivanov5ae82cb2014-12-02 17:08:42 -08001675
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001676 if (si->can_unload()) {
1677 size_t ref_count = si->is_linked() ? si->decrement_ref_count() : 0;
1678 if (ref_count == 0) {
1679 unload_list.push_back(si);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001680 } else {
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001681 TRACE("not unloading '%s' group, decrementing ref_count to %zd",
1682 si->get_realpath(), ref_count);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001683 }
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001684 } else {
1685 TRACE("not unloading '%s' - the binary is flagged with NODELETE", si->get_realpath());
1686 return;
1687 }
1688 }
1689
1690 // This is used to identify soinfos outside of the load-group
1691 // note that we cannot have > 1 in the array and have any of them
1692 // linked. This is why we can safely use the first one.
1693 soinfo* root = soinfos[0];
1694
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001695 soinfo_list_t local_unload_list;
1696 soinfo_list_t external_unload_list;
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001697 soinfo* si = nullptr;
1698
1699 while ((si = unload_list.pop_front()) != nullptr) {
1700 if (local_unload_list.contains(si)) {
1701 continue;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001702 }
Elliott Hughesd23736e2012-11-01 15:16:56 -07001703
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001704 local_unload_list.push_back(si);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001705
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001706 if (si->has_min_version(0)) {
1707 soinfo* child = nullptr;
1708 while ((child = si->get_children().pop_front()) != nullptr) {
1709 TRACE("%s@%p needs to unload %s@%p", si->get_realpath(), si,
1710 child->get_realpath(), child);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001711
Dimitry Ivanovec90e242017-02-10 11:04:20 -08001712 child->get_parents().remove(si);
1713
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001714 if (local_unload_list.contains(child)) {
1715 continue;
1716 } else if (child->is_linked() && child->get_local_group_root() != root) {
1717 external_unload_list.push_back(child);
Dimitry Ivanovec90e242017-02-10 11:04:20 -08001718 } else if (child->get_parents().empty()) {
1719 unload_list.push_back(child);
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001720 }
1721 }
1722 } else {
1723#if !defined(__work_around_b_24465209__)
1724 __libc_fatal("soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
1725#else
1726 PRINT("warning: soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
1727 for_each_dt_needed(si, [&] (const char* library_name) {
1728 TRACE("deprecated (old format of soinfo): %s needs to unload %s",
1729 si->get_realpath(), library_name);
1730
1731 soinfo* needed = find_library(si->get_primary_namespace(),
1732 library_name, RTLD_NOLOAD, nullptr, nullptr);
1733
1734 if (needed != nullptr) {
1735 // Not found: for example if symlink was deleted between dlopen and dlclose
1736 // Since we cannot really handle errors at this point - print and continue.
1737 PRINT("warning: couldn't find %s needed by %s on unload.",
1738 library_name, si->get_realpath());
1739 return;
1740 } else if (local_unload_list.contains(needed)) {
1741 // already visited
1742 return;
1743 } else if (needed->is_linked() && needed->get_local_group_root() != root) {
1744 // external group
1745 external_unload_list.push_back(needed);
1746 } else {
1747 // local group
1748 unload_list.push_front(needed);
1749 }
1750 });
1751#endif
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001752 }
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001753 }
1754
1755 local_unload_list.for_each([](soinfo* si) {
1756 si->call_destructors();
1757 });
1758
1759 while ((si = local_unload_list.pop_front()) != nullptr) {
1760 notify_gdb_of_unload(si);
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -07001761 get_cfi_shadow()->BeforeUnload(si);
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001762 soinfo_free(si);
1763 }
1764
1765 while ((si = external_unload_list.pop_front()) != nullptr) {
1766 soinfo_unload(si);
Dmitriy Ivanova2547052014-11-18 12:03:09 -08001767 }
1768}
1769
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001770static std::string symbol_display_name(const char* sym_name, const char* sym_ver) {
1771 if (sym_ver == nullptr) {
1772 return sym_name;
1773 }
1774
Dimitry Ivanov9cf99cb2015-12-11 14:22:24 -08001775 return std::string(sym_name) + ", version " + sym_ver;
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001776}
1777
Dimitry Ivanovaca299a2016-04-11 12:42:58 -07001778static android_namespace_t* get_caller_namespace(soinfo* caller) {
1779 return caller != nullptr ? caller->get_primary_namespace() : g_anonymous_namespace;
1780}
1781
Elliott Hughesa4aafd12014-01-13 16:37:47 -08001782void do_android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size) {
Christopher Ferris052fa3a2014-08-26 20:48:11 -07001783 // Use basic string manipulation calls to avoid snprintf.
1784 // snprintf indirectly calls pthread_getspecific to get the size of a buffer.
1785 // When debug malloc is enabled, this call returns 0. This in turn causes
1786 // snprintf to do nothing, which causes libraries to fail to load.
1787 // See b/17302493 for further details.
1788 // Once the above bug is fixed, this code can be modified to use
1789 // snprintf again.
Dimitry Ivanov77ad6422017-03-06 13:02:29 -08001790 const auto& default_ld_paths = g_default_namespace.get_default_library_paths();
1791
1792 size_t required_size = 0;
1793 for (const auto& path : default_ld_paths) {
1794 required_size += path.size() + 1;
Evgenii Stepanovd640b222015-07-10 17:54:01 -07001795 }
Dimitry Ivanov77ad6422017-03-06 13:02:29 -08001796
1797 if (buffer_size < required_size) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07001798 __libc_fatal("android_get_LD_LIBRARY_PATH failed, buffer too small: "
Dimitry Ivanov77ad6422017-03-06 13:02:29 -08001799 "buffer len %zu, required len %zu", buffer_size, required_size);
Christopher Ferris052fa3a2014-08-26 20:48:11 -07001800 }
Dimitry Ivanov77ad6422017-03-06 13:02:29 -08001801
Evgenii Stepanovd640b222015-07-10 17:54:01 -07001802 char* end = buffer;
Dimitry Ivanov77ad6422017-03-06 13:02:29 -08001803 for (size_t i = 0; i < default_ld_paths.size(); ++i) {
Evgenii Stepanovd640b222015-07-10 17:54:01 -07001804 if (i > 0) *end++ = ':';
Dimitry Ivanov77ad6422017-03-06 13:02:29 -08001805 end = stpcpy(end, default_ld_paths[i].c_str());
Evgenii Stepanovd640b222015-07-10 17:54:01 -07001806 }
Elliott Hughesa4aafd12014-01-13 16:37:47 -08001807}
1808
Elliott Hughescade4c32012-12-20 14:42:14 -08001809void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path) {
Nick Kralevich6bb01b62015-03-07 13:37:05 -08001810 parse_LD_LIBRARY_PATH(ld_library_path);
Elliott Hughescade4c32012-12-20 14:42:14 -08001811}
1812
Dimitry Ivanovb996d602016-07-11 18:11:39 -07001813static std::string android_dlextinfo_to_string(const android_dlextinfo* info) {
1814 if (info == nullptr) {
1815 return "(null)";
1816 }
1817
1818 return android::base::StringPrintf("[flags=0x%" PRIx64 ","
1819 " reserved_addr=%p,"
1820 " reserved_size=0x%zx,"
1821 " relro_fd=%d,"
1822 " library_fd=%d,"
1823 " library_fd_offset=0x%" PRIx64 ","
1824 " library_namespace=%s@%p]",
1825 info->flags,
1826 info->reserved_addr,
1827 info->reserved_size,
1828 info->relro_fd,
1829 info->library_fd,
1830 info->library_fd_offset,
1831 (info->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0 ?
1832 (info->library_namespace != nullptr ?
1833 info->library_namespace->get_name() : "(null)") : "(n/a)",
1834 (info->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0 ?
1835 info->library_namespace : nullptr);
1836}
1837
Dimitry Ivanovd9e427c2016-11-22 16:55:25 -08001838void* do_dlopen(const char* name, int flags,
1839 const android_dlextinfo* extinfo,
1840 const void* caller_addr) {
Dimitry Ivanov5c4a5802017-03-17 16:41:34 -07001841 std::string trace_prefix = std::string("dlopen: ") + (name == nullptr ? "(nullptr)" : name);
1842 ScopedTrace trace(trace_prefix.c_str());
1843 ScopedTrace loading_trace((trace_prefix + " - loading and linking").c_str());
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001844 soinfo* const caller = find_containing_library(caller_addr);
Dimitry Ivanovb996d602016-07-11 18:11:39 -07001845 android_namespace_t* ns = get_caller_namespace(caller);
1846
1847 LD_LOG(kLogDlopen,
1848 "dlopen(name=\"%s\", flags=0x%x, extinfo=%s, caller=\"%s\", caller_ns=%s@%p) ...",
1849 name,
1850 flags,
1851 android_dlextinfo_to_string(extinfo).c_str(),
1852 caller == nullptr ? "(null)" : caller->get_realpath(),
1853 ns == nullptr ? "(null)" : ns->get_name(),
1854 ns);
1855
1856 auto failure_guard = make_scope_guard([&]() {
1857 LD_LOG(kLogDlopen, "... dlopen failed: %s", linker_get_error_buffer());
1858 });
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001859
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -07001860 if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL|RTLD_NODELETE|RTLD_NOLOAD)) != 0) {
Elliott Hughese66190d2012-12-18 15:57:55 -08001861 DL_ERR("invalid flags to dlopen: %x", flags);
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07001862 return nullptr;
Elliott Hughese66190d2012-12-18 15:57:55 -08001863 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001864
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001865 if (extinfo != nullptr) {
1866 if ((extinfo->flags & ~(ANDROID_DLEXT_VALID_FLAG_BITS)) != 0) {
1867 DL_ERR("invalid extended flags to android_dlopen_ext: 0x%" PRIx64, extinfo->flags);
1868 return nullptr;
1869 }
Dmitriy Ivanov126af752015-10-07 16:34:20 -07001870
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001871 if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) == 0 &&
Dmitriy Ivanova6c12792014-10-21 12:09:18 -07001872 (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07001873 DL_ERR("invalid extended flag combination (ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET without "
1874 "ANDROID_DLEXT_USE_LIBRARY_FD): 0x%" PRIx64, extinfo->flags);
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001875 return nullptr;
1876 }
Dmitriy Ivanov126af752015-10-07 16:34:20 -07001877
1878 if ((extinfo->flags & ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS) != 0 &&
1879 (extinfo->flags & (ANDROID_DLEXT_RESERVED_ADDRESS | ANDROID_DLEXT_RESERVED_ADDRESS_HINT)) != 0) {
1880 DL_ERR("invalid extended flag combination: ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS is not "
1881 "compatible with ANDROID_DLEXT_RESERVED_ADDRESS/ANDROID_DLEXT_RESERVED_ADDRESS_HINT");
1882 return nullptr;
1883 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001884
1885 if ((extinfo->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0) {
1886 if (extinfo->library_namespace == nullptr) {
1887 DL_ERR("ANDROID_DLEXT_USE_NAMESPACE is set but extinfo->library_namespace is null");
1888 return nullptr;
1889 }
1890 ns = extinfo->library_namespace;
1891 }
Torne (Richard Coles)012cb452014-02-06 14:34:21 +00001892 }
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -08001893
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -07001894 std::string asan_name_holder;
1895
1896 const char* translated_name = name;
Dimitry Ivanov6c14f862016-12-05 13:35:47 -08001897 if (g_is_asan && translated_name != nullptr && translated_name[0] == '/') {
1898 char translated_path[PATH_MAX];
1899 if (realpath(translated_name, translated_path) != nullptr) {
Evgenii Stepanov5b715002016-10-03 15:09:28 -07001900 if (file_is_under_dir(translated_path, kSystemLibDir)) {
1901 asan_name_holder = std::string(kAsanSystemLibDir) + "/" +
1902 (translated_path + strlen(kSystemLibDir) + 1);
Dimitry Ivanov6c14f862016-12-05 13:35:47 -08001903 if (file_exists(asan_name_holder.c_str())) {
1904 translated_name = asan_name_holder.c_str();
1905 PRINT("linker_asan dlopen translating \"%s\" -> \"%s\"", name, translated_name);
1906 }
Evgenii Stepanov5b715002016-10-03 15:09:28 -07001907 } else if (file_is_under_dir(translated_path, kVendorLibDir)) {
1908 asan_name_holder = std::string(kAsanVendorLibDir) + "/" +
1909 (translated_path + strlen(kVendorLibDir) + 1);
Dimitry Ivanov6c14f862016-12-05 13:35:47 -08001910 if (file_exists(asan_name_holder.c_str())) {
1911 translated_name = asan_name_holder.c_str();
1912 PRINT("linker_asan dlopen translating \"%s\" -> \"%s\"", name, translated_name);
1913 }
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -07001914 }
1915 }
1916 }
1917
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -08001918 ProtectedDataGuard guard;
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -07001919 soinfo* si = find_library(ns, translated_name, flags, extinfo, caller);
Dimitry Ivanov5c4a5802017-03-17 16:41:34 -07001920 loading_trace.End();
1921
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07001922 if (si != nullptr) {
Dimitry Ivanovb996d602016-07-11 18:11:39 -07001923 void* handle = si->to_handle();
1924 LD_LOG(kLogDlopen,
Dimitry Ivanovae4a0c12016-11-21 10:44:35 -08001925 "... dlopen calling constructors: realpath=\"%s\", soname=\"%s\", handle=%p",
1926 si->get_realpath(), si->get_soname(), handle);
1927 si->call_constructors();
1928 failure_guard.disable();
1929 LD_LOG(kLogDlopen,
Dimitry Ivanovb996d602016-07-11 18:11:39 -07001930 "... dlopen successful: realpath=\"%s\", soname=\"%s\", handle=%p",
1931 si->get_realpath(), si->get_soname(), handle);
1932 return handle;
Elliott Hughesd23736e2012-11-01 15:16:56 -07001933 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001934
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001935 return nullptr;
Elliott Hughesd23736e2012-11-01 15:16:56 -07001936}
1937
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001938int do_dladdr(const void* addr, Dl_info* info) {
1939 // Determine if this address can be found in any library currently mapped.
1940 soinfo* si = find_containing_library(addr);
1941 if (si == nullptr) {
1942 return 0;
1943 }
1944
1945 memset(info, 0, sizeof(Dl_info));
1946
1947 info->dli_fname = si->get_realpath();
1948 // Address at which the shared object is loaded.
1949 info->dli_fbase = reinterpret_cast<void*>(si->base);
1950
1951 // Determine if any symbol in the library contains the specified address.
1952 ElfW(Sym)* sym = si->find_symbol_by_address(addr);
1953 if (sym != nullptr) {
1954 info->dli_sname = si->get_string(sym->st_name);
1955 info->dli_saddr = reinterpret_cast<void*>(si->resolve_symbol_address(sym));
1956 }
1957
1958 return 1;
1959}
1960
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001961static soinfo* soinfo_from_handle(void* handle) {
1962 if ((reinterpret_cast<uintptr_t>(handle) & 1) != 0) {
1963 auto it = g_soinfo_handles_map.find(reinterpret_cast<uintptr_t>(handle));
1964 if (it == g_soinfo_handles_map.end()) {
1965 return nullptr;
1966 } else {
1967 return it->second;
1968 }
1969 }
1970
1971 return static_cast<soinfo*>(handle);
1972}
1973
Dimitry Ivanovd9e427c2016-11-22 16:55:25 -08001974bool do_dlsym(void* handle,
1975 const char* sym_name,
1976 const char* sym_ver,
1977 const void* caller_addr,
1978 void** symbol) {
Dimitry Ivanov6705e8c2017-03-21 10:29:06 -07001979 ScopedTrace trace("dlsym");
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001980#if !defined(__LP64__)
1981 if (handle == nullptr) {
1982 DL_ERR("dlsym failed: library handle is null");
1983 return false;
1984 }
1985#endif
1986
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001987 soinfo* found = nullptr;
1988 const ElfW(Sym)* sym = nullptr;
1989 soinfo* caller = find_containing_library(caller_addr);
Dimitry Ivanovaca299a2016-04-11 12:42:58 -07001990 android_namespace_t* ns = get_caller_namespace(caller);
Dimitry Ivanov4742abd2016-12-12 16:30:15 -08001991 soinfo* si = nullptr;
1992 if (handle != RTLD_DEFAULT && handle != RTLD_NEXT) {
1993 si = soinfo_from_handle(handle);
1994 }
1995
1996 LD_LOG(kLogDlsym,
1997 "dlsym(handle=%p(\"%s\"), sym_name=\"%s\", sym_ver=\"%s\", caller=\"%s\", caller_ns=%s@%p) ...",
1998 handle,
1999 si != nullptr ? si->get_realpath() : "n/a",
2000 sym_name,
2001 sym_ver,
2002 caller == nullptr ? "(null)" : caller->get_realpath(),
2003 ns == nullptr ? "(null)" : ns->get_name(),
2004 ns);
2005
2006 auto failure_guard = make_scope_guard([&]() {
2007 LD_LOG(kLogDlsym, "... dlsym failed: %s", linker_get_error_buffer());
2008 });
2009
2010 if (sym_name == nullptr) {
2011 DL_ERR("dlsym failed: symbol name is null");
2012 return false;
2013 }
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08002014
2015 version_info vi_instance;
2016 version_info* vi = nullptr;
2017
2018 if (sym_ver != nullptr) {
Dimitry Ivanov9cf99cb2015-12-11 14:22:24 -08002019 vi_instance.name = sym_ver;
2020 vi_instance.elf_hash = calculate_elf_hash(sym_ver);
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08002021 vi = &vi_instance;
2022 }
2023
2024 if (handle == RTLD_DEFAULT || handle == RTLD_NEXT) {
2025 sym = dlsym_linear_lookup(ns, sym_name, vi, &found, caller, handle);
2026 } else {
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07002027 if (si == nullptr) {
2028 DL_ERR("dlsym failed: invalid handle: %p", handle);
2029 return false;
2030 }
2031 sym = dlsym_handle_lookup(si, &found, sym_name, vi);
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08002032 }
2033
2034 if (sym != nullptr) {
2035 uint32_t bind = ELF_ST_BIND(sym->st_info);
2036
2037 if ((bind == STB_GLOBAL || bind == STB_WEAK) && sym->st_shndx != 0) {
2038 *symbol = reinterpret_cast<void*>(found->resolve_symbol_address(sym));
Dimitry Ivanov4742abd2016-12-12 16:30:15 -08002039 failure_guard.disable();
2040 LD_LOG(kLogDlsym,
2041 "... dlsym successful: sym_name=\"%s\", sym_ver=\"%s\", found in=\"%s\", address=%p",
2042 sym_name, sym_ver, found->get_soname(), *symbol);
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08002043 return true;
2044 }
2045
2046 DL_ERR("symbol \"%s\" found but not global", symbol_display_name(sym_name, sym_ver).c_str());
2047 return false;
2048 }
2049
2050 DL_ERR("undefined symbol: %s", symbol_display_name(sym_name, sym_ver).c_str());
2051 return false;
2052}
2053
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07002054int do_dlclose(void* handle) {
Dimitry Ivanov6705e8c2017-03-21 10:29:06 -07002055 ScopedTrace trace("dlclose");
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -08002056 ProtectedDataGuard guard;
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07002057 soinfo* si = soinfo_from_handle(handle);
2058 if (si == nullptr) {
2059 DL_ERR("invalid handle: %p", handle);
2060 return -1;
2061 }
2062
Dmitriy Ivanovb648a8a2014-05-19 15:06:58 -07002063 soinfo_unload(si);
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07002064 return 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002065}
2066
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -08002067bool init_anonymous_namespace(const char* shared_lib_sonames, const char* library_search_path) {
2068 if (g_anonymous_namespace_initialized) {
2069 DL_ERR("anonymous namespace has already been initialized.");
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002070 return false;
2071 }
2072
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002073 ProtectedDataGuard guard;
2074
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002075 // create anonymous namespace
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002076 // When the caller is nullptr - create_namespace will take global group
2077 // from the anonymous namespace, which is fine because anonymous namespace
2078 // is still pointing to the default one.
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002079 android_namespace_t* anon_ns =
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -08002080 create_namespace(nullptr,
2081 "(anonymous)",
2082 nullptr,
2083 library_search_path,
Dimitry Ivanovc9dced22017-03-27 15:42:17 -07002084 ANDROID_NAMESPACE_TYPE_ISOLATED,
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -08002085 nullptr,
2086 &g_default_namespace);
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002087
2088 if (anon_ns == nullptr) {
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -08002089 return false;
2090 }
2091
2092 if (!link_namespaces(anon_ns, &g_default_namespace, shared_lib_sonames)) {
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002093 return false;
2094 }
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08002095
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002096 g_anonymous_namespace = anon_ns;
Dimitry Ivanov3e0821d2017-03-07 11:02:10 -08002097 g_anonymous_namespace_initialized = true;
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -08002098
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002099 return true;
2100}
2101
Dimitry Ivanovb943f302016-08-03 16:00:10 -07002102static void add_soinfos_to_namespace(const soinfo_list_t& soinfos, android_namespace_t* ns) {
2103 ns->add_soinfos(soinfos);
2104 for (auto si : soinfos) {
2105 si->add_secondary_namespace(ns);
2106 }
2107}
2108
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002109android_namespace_t* create_namespace(const void* caller_addr,
2110 const char* name,
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002111 const char* ld_library_path,
2112 const char* default_library_path,
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002113 uint64_t type,
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002114 const char* permitted_when_isolated_path,
2115 android_namespace_t* parent_namespace) {
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002116 if (parent_namespace == nullptr) {
Dimitry Ivanov52408632016-05-23 10:31:11 -07002117 // if parent_namespace is nullptr -> set it to the caller namespace
2118 soinfo* caller_soinfo = find_containing_library(caller_addr);
2119
2120 parent_namespace = caller_soinfo != nullptr ?
2121 caller_soinfo->get_primary_namespace() :
2122 g_anonymous_namespace;
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002123 }
2124
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002125 ProtectedDataGuard guard;
2126 std::vector<std::string> ld_library_paths;
2127 std::vector<std::string> default_library_paths;
Dimitry Ivanov284ae352015-12-08 10:47:13 -08002128 std::vector<std::string> permitted_paths;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002129
2130 parse_path(ld_library_path, ":", &ld_library_paths);
2131 parse_path(default_library_path, ":", &default_library_paths);
Dimitry Ivanov284ae352015-12-08 10:47:13 -08002132 parse_path(permitted_when_isolated_path, ":", &permitted_paths);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002133
2134 android_namespace_t* ns = new (g_namespace_allocator.alloc()) android_namespace_t();
2135 ns->set_name(name);
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002136 ns->set_isolated((type & ANDROID_NAMESPACE_TYPE_ISOLATED) != 0);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002137 ns->set_ld_library_paths(std::move(ld_library_paths));
2138 ns->set_default_library_paths(std::move(default_library_paths));
Dimitry Ivanov284ae352015-12-08 10:47:13 -08002139 ns->set_permitted_paths(std::move(permitted_paths));
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002140
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002141 if ((type & ANDROID_NAMESPACE_TYPE_SHARED) != 0) {
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002142 // If shared - clone the parent namespace
Dimitry Ivanovb943f302016-08-03 16:00:10 -07002143 add_soinfos_to_namespace(parent_namespace->soinfo_list(), ns);
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002144 } else {
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002145 // If not shared - copy only the shared group
Dimitry Ivanovb943f302016-08-03 16:00:10 -07002146 add_soinfos_to_namespace(get_shared_group(parent_namespace), ns);
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002147 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002148
2149 return ns;
2150}
2151
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -08002152bool link_namespaces(android_namespace_t* namespace_from,
2153 android_namespace_t* namespace_to,
2154 const char* shared_lib_sonames) {
2155 if (namespace_to == nullptr) {
2156 namespace_to = &g_default_namespace;
2157 }
2158
2159 if (namespace_from == nullptr) {
2160 DL_ERR("error linking namespaces: namespace_from is null.");
2161 return false;
2162 }
2163
2164 if (shared_lib_sonames == nullptr || shared_lib_sonames[0] == '\0') {
2165 DL_ERR("error linking namespaces \"%s\"->\"%s\": the list of shared libraries is empty.",
2166 namespace_from->get_name(), namespace_to->get_name());
2167 return false;
2168 }
2169
2170 auto sonames = android::base::Split(shared_lib_sonames, ":");
2171 std::unordered_set<std::string> sonames_set(sonames.begin(), sonames.end());
2172
2173 ProtectedDataGuard guard;
2174 namespace_from->add_linked_namespace(namespace_to, sonames_set);
2175
2176 return true;
2177}
2178
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002179ElfW(Addr) call_ifunc_resolver(ElfW(Addr) resolver_addr) {
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07002180 typedef ElfW(Addr) (*ifunc_resolver_t)(void);
2181 ifunc_resolver_t ifunc_resolver = reinterpret_cast<ifunc_resolver_t>(resolver_addr);
2182 ElfW(Addr) ifunc_addr = ifunc_resolver();
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002183 TRACE_TYPE(RELO, "Called ifunc_resolver@%p. The result is %p",
2184 ifunc_resolver, reinterpret_cast<void*>(ifunc_addr));
Brigid Smithc5a13ef2014-07-23 11:22:25 -07002185
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07002186 return ifunc_addr;
Brigid Smithc5a13ef2014-07-23 11:22:25 -07002187}
Brigid Smithc5a13ef2014-07-23 11:22:25 -07002188
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002189const version_info* VersionTracker::get_version_info(ElfW(Versym) source_symver) const {
2190 if (source_symver < 2 ||
2191 source_symver >= version_infos.size() ||
2192 version_infos[source_symver].name == nullptr) {
2193 return nullptr;
2194 }
2195
2196 return &version_infos[source_symver];
2197}
2198
2199void VersionTracker::add_version_info(size_t source_index,
2200 ElfW(Word) elf_hash,
2201 const char* ver_name,
2202 const soinfo* target_si) {
2203 if (source_index >= version_infos.size()) {
2204 version_infos.resize(source_index+1);
2205 }
2206
2207 version_infos[source_index].elf_hash = elf_hash;
2208 version_infos[source_index].name = ver_name;
2209 version_infos[source_index].target_si = target_si;
2210}
2211
2212bool VersionTracker::init_verneed(const soinfo* si_from) {
2213 uintptr_t verneed_ptr = si_from->get_verneed_ptr();
2214
2215 if (verneed_ptr == 0) {
2216 return true;
2217 }
2218
2219 size_t verneed_cnt = si_from->get_verneed_cnt();
2220
2221 for (size_t i = 0, offset = 0; i<verneed_cnt; ++i) {
2222 const ElfW(Verneed)* verneed = reinterpret_cast<ElfW(Verneed)*>(verneed_ptr + offset);
2223 size_t vernaux_offset = offset + verneed->vn_aux;
2224 offset += verneed->vn_next;
2225
2226 if (verneed->vn_version != 1) {
2227 DL_ERR("unsupported verneed[%zd] vn_version: %d (expected 1)", i, verneed->vn_version);
2228 return false;
2229 }
2230
2231 const char* target_soname = si_from->get_string(verneed->vn_file);
2232 // find it in dependencies
2233 soinfo* target_si = si_from->get_children().find_if([&](const soinfo* si) {
Dmitriy Ivanov406d9962015-05-06 11:05:27 -07002234 return si->get_soname() != nullptr && strcmp(si->get_soname(), target_soname) == 0;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002235 });
2236
2237 if (target_si == nullptr) {
2238 DL_ERR("cannot find \"%s\" from verneed[%zd] in DT_NEEDED list for \"%s\"",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002239 target_soname, i, si_from->get_realpath());
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002240 return false;
2241 }
2242
2243 for (size_t j = 0; j<verneed->vn_cnt; ++j) {
2244 const ElfW(Vernaux)* vernaux = reinterpret_cast<ElfW(Vernaux)*>(verneed_ptr + vernaux_offset);
2245 vernaux_offset += vernaux->vna_next;
2246
2247 const ElfW(Word) elf_hash = vernaux->vna_hash;
2248 const char* ver_name = si_from->get_string(vernaux->vna_name);
2249 ElfW(Half) source_index = vernaux->vna_other;
2250
2251 add_version_info(source_index, elf_hash, ver_name, target_si);
2252 }
2253 }
2254
2255 return true;
2256}
2257
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002258template <typename F>
2259static bool for_each_verdef(const soinfo* si, F functor) {
2260 if (!si->has_min_version(2)) {
2261 return true;
2262 }
2263
2264 uintptr_t verdef_ptr = si->get_verdef_ptr();
2265 if (verdef_ptr == 0) {
2266 return true;
2267 }
2268
2269 size_t offset = 0;
2270
2271 size_t verdef_cnt = si->get_verdef_cnt();
2272 for (size_t i = 0; i<verdef_cnt; ++i) {
2273 const ElfW(Verdef)* verdef = reinterpret_cast<ElfW(Verdef)*>(verdef_ptr + offset);
2274 size_t verdaux_offset = offset + verdef->vd_aux;
2275 offset += verdef->vd_next;
2276
2277 if (verdef->vd_version != 1) {
2278 DL_ERR("unsupported verdef[%zd] vd_version: %d (expected 1) library: %s",
2279 i, verdef->vd_version, si->get_realpath());
2280 return false;
2281 }
2282
2283 if ((verdef->vd_flags & VER_FLG_BASE) != 0) {
2284 // "this is the version of the file itself. It must not be used for
2285 // matching a symbol. It can be used to match references."
2286 //
2287 // http://www.akkadia.org/drepper/symbol-versioning
2288 continue;
2289 }
2290
2291 if (verdef->vd_cnt == 0) {
2292 DL_ERR("invalid verdef[%zd] vd_cnt == 0 (version without a name)", i);
2293 return false;
2294 }
2295
2296 const ElfW(Verdaux)* verdaux = reinterpret_cast<ElfW(Verdaux)*>(verdef_ptr + verdaux_offset);
2297
2298 if (functor(i, verdef, verdaux) == true) {
2299 break;
2300 }
2301 }
2302
2303 return true;
2304}
2305
2306bool find_verdef_version_index(const soinfo* si, const version_info* vi, ElfW(Versym)* versym) {
2307 if (vi == nullptr) {
2308 *versym = kVersymNotNeeded;
2309 return true;
2310 }
2311
2312 *versym = kVersymGlobal;
2313
2314 return for_each_verdef(si,
2315 [&](size_t, const ElfW(Verdef)* verdef, const ElfW(Verdaux)* verdaux) {
2316 if (verdef->vd_hash == vi->elf_hash &&
2317 strcmp(vi->name, si->get_string(verdaux->vda_name)) == 0) {
2318 *versym = verdef->vd_ndx;
2319 return true;
2320 }
2321
2322 return false;
2323 }
2324 );
2325}
2326
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002327bool VersionTracker::init_verdef(const soinfo* si_from) {
2328 return for_each_verdef(si_from,
2329 [&](size_t, const ElfW(Verdef)* verdef, const ElfW(Verdaux)* verdaux) {
2330 add_version_info(verdef->vd_ndx, verdef->vd_hash,
2331 si_from->get_string(verdaux->vda_name), si_from);
2332 return false;
2333 }
2334 );
2335}
2336
2337bool VersionTracker::init(const soinfo* si_from) {
2338 if (!si_from->has_min_version(2)) {
2339 return true;
2340 }
2341
2342 return init_verneed(si_from) && init_verdef(si_from);
2343}
2344
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002345// TODO (dimitry): Methods below need to be moved out of soinfo
2346// and in more isolated file in order minimize dependencies on
2347// unnecessary object in the linker binary. Consider making them
2348// independent from soinfo (?).
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002349bool soinfo::lookup_version_info(const VersionTracker& version_tracker, ElfW(Word) sym,
2350 const char* sym_name, const version_info** vi) {
2351 const ElfW(Versym)* sym_ver_ptr = get_versym(sym);
2352 ElfW(Versym) sym_ver = sym_ver_ptr == nullptr ? 0 : *sym_ver_ptr;
2353
2354 if (sym_ver != VER_NDX_LOCAL && sym_ver != VER_NDX_GLOBAL) {
2355 *vi = version_tracker.get_version_info(sym_ver);
2356
2357 if (*vi == nullptr) {
2358 DL_ERR("cannot find verneed/verdef for version index=%d "
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002359 "referenced by symbol \"%s\" at \"%s\"", sym_ver, sym_name, get_realpath());
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002360 return false;
2361 }
2362 } else {
2363 // there is no version info
2364 *vi = nullptr;
2365 }
2366
2367 return true;
2368}
2369
Dimitry Ivanov576a3752016-08-09 06:58:55 -07002370#if !defined(__mips__)
2371#if defined(USE_RELA)
2372static ElfW(Addr) get_addend(ElfW(Rela)* rela, ElfW(Addr) reloc_addr __unused) {
2373 return rela->r_addend;
2374}
2375#else
2376static ElfW(Addr) get_addend(ElfW(Rel)* rel, ElfW(Addr) reloc_addr) {
2377 if (ELFW(R_TYPE)(rel->r_info) == R_GENERIC_RELATIVE ||
2378 ELFW(R_TYPE)(rel->r_info) == R_GENERIC_IRELATIVE) {
2379 return *reinterpret_cast<ElfW(Addr)*>(reloc_addr);
2380 }
2381 return 0;
2382}
2383#endif
2384
Dmitriy Ivanovfa26eee2015-02-03 16:06:47 -08002385template<typename ElfRelIteratorT>
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07002386bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& rel_iterator,
2387 const soinfo_list_t& global_group, const soinfo_list_t& local_group) {
Dmitriy Ivanovfa26eee2015-02-03 16:06:47 -08002388 for (size_t idx = 0; rel_iterator.has_next(); ++idx) {
2389 const auto rel = rel_iterator.next();
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002390 if (rel == nullptr) {
2391 return false;
2392 }
2393
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002394 ElfW(Word) type = ELFW(R_TYPE)(rel->r_info);
2395 ElfW(Word) sym = ELFW(R_SYM)(rel->r_info);
2396
2397 ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rel->r_offset + load_bias);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002398 ElfW(Addr) sym_addr = 0;
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07002399 const char* sym_name = nullptr;
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002400 ElfW(Addr) addend = get_addend(rel, reloc);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002401
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07002402 DEBUG("Processing \"%s\" relocation at index %zd", get_realpath(), idx);
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002403 if (type == R_GENERIC_NONE) {
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002404 continue;
2405 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002406
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002407 const ElfW(Sym)* s = nullptr;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002408 soinfo* lsi = nullptr;
2409
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002410 if (sym != 0) {
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002411 sym_name = get_string(symtab_[sym].st_name);
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002412 const version_info* vi = nullptr;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002413
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002414 if (!lookup_version_info(version_tracker, sym, sym_name, &vi)) {
2415 return false;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002416 }
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002417
2418 if (!soinfo_do_lookup(this, sym_name, vi, &lsi, global_group, local_group, &s)) {
2419 return false;
2420 }
2421
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07002422 if (s == nullptr) {
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002423 // We only allow an undefined symbol if this is a weak reference...
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002424 s = &symtab_[sym];
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002425 if (ELF_ST_BIND(s->st_info) != STB_WEAK) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002426 DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, get_realpath());
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002427 return false;
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002428 }
2429
2430 /* IHI0044C AAELF 4.5.1.1:
2431
2432 Libraries are not searched to resolve weak references.
2433 It is not an error for a weak reference to remain unsatisfied.
2434
2435 During linking, the value of an undefined weak reference is:
2436 - Zero if the relocation type is absolute
2437 - The address of the place if the relocation is pc-relative
2438 - The address of nominal base address if the relocation
2439 type is base-relative.
2440 */
2441
2442 switch (type) {
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002443 case R_GENERIC_JUMP_SLOT:
2444 case R_GENERIC_GLOB_DAT:
2445 case R_GENERIC_RELATIVE:
2446 case R_GENERIC_IRELATIVE:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002447#if defined(__aarch64__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002448 case R_AARCH64_ABS64:
2449 case R_AARCH64_ABS32:
2450 case R_AARCH64_ABS16:
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002451#elif defined(__x86_64__)
2452 case R_X86_64_32:
2453 case R_X86_64_64:
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002454#elif defined(__arm__)
2455 case R_ARM_ABS32:
2456#elif defined(__i386__)
2457 case R_386_32:
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002458#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002459 /*
2460 * The sym_addr was initialized to be zero above, or the relocation
2461 * code below does not care about value of sym_addr.
2462 * No need to do anything.
2463 */
2464 break;
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002465#if defined(__x86_64__)
Dimitry Ivanovd338aac2015-01-13 22:31:54 +00002466 case R_X86_64_PC32:
2467 sym_addr = reloc;
2468 break;
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002469#elif defined(__i386__)
2470 case R_386_PC32:
2471 sym_addr = reloc;
2472 break;
2473#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002474 default:
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002475 DL_ERR("unknown weak reloc type %d @ %p (%zu)", type, rel, idx);
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002476 return false;
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002477 }
Dmitriy Ivanovec83a612015-07-26 07:37:09 -07002478 } else { // We got a definition.
2479#if !defined(__LP64__)
2480 // When relocating dso with text_relocation .text segment is
2481 // not executable. We need to restore elf flags before resolving
2482 // STT_GNU_IFUNC symbol.
2483 bool protect_segments = has_text_relocations &&
2484 lsi == this &&
2485 ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC;
2486 if (protect_segments) {
2487 if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
2488 DL_ERR("can't protect segments for \"%s\": %s",
2489 get_realpath(), strerror(errno));
2490 return false;
2491 }
2492 }
2493#endif
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07002494 sym_addr = lsi->resolve_symbol_address(s);
Dmitriy Ivanovec83a612015-07-26 07:37:09 -07002495#if !defined(__LP64__)
2496 if (protect_segments) {
2497 if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
2498 DL_ERR("can't unprotect loadable segments for \"%s\": %s",
2499 get_realpath(), strerror(errno));
2500 return false;
2501 }
2502 }
2503#endif
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002504 }
2505 count_relocation(kRelocSymbol);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002506 }
2507
2508 switch (type) {
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002509 case R_GENERIC_JUMP_SLOT:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002510 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002511 MARK(rel->r_offset);
2512 TRACE_TYPE(RELO, "RELO JMP_SLOT %16p <- %16p %s\n",
2513 reinterpret_cast<void*>(reloc),
2514 reinterpret_cast<void*>(sym_addr + addend), sym_name);
2515
2516 *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002517 break;
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002518 case R_GENERIC_GLOB_DAT:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002519 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002520 MARK(rel->r_offset);
2521 TRACE_TYPE(RELO, "RELO GLOB_DAT %16p <- %16p %s\n",
2522 reinterpret_cast<void*>(reloc),
2523 reinterpret_cast<void*>(sym_addr + addend), sym_name);
2524 *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002525 break;
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002526 case R_GENERIC_RELATIVE:
2527 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002528 MARK(rel->r_offset);
2529 TRACE_TYPE(RELO, "RELO RELATIVE %16p <- %16p\n",
2530 reinterpret_cast<void*>(reloc),
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002531 reinterpret_cast<void*>(load_bias + addend));
2532 *reinterpret_cast<ElfW(Addr)*>(reloc) = (load_bias + addend);
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002533 break;
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002534 case R_GENERIC_IRELATIVE:
2535 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002536 MARK(rel->r_offset);
2537 TRACE_TYPE(RELO, "RELO IRELATIVE %16p <- %16p\n",
2538 reinterpret_cast<void*>(reloc),
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002539 reinterpret_cast<void*>(load_bias + addend));
Dmitriy Ivanovec83a612015-07-26 07:37:09 -07002540 {
2541#if !defined(__LP64__)
2542 // When relocating dso with text_relocation .text segment is
2543 // not executable. We need to restore elf flags for this
2544 // particular call.
2545 if (has_text_relocations) {
2546 if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
2547 DL_ERR("can't protect segments for \"%s\": %s",
2548 get_realpath(), strerror(errno));
2549 return false;
2550 }
2551 }
2552#endif
2553 ElfW(Addr) ifunc_addr = call_ifunc_resolver(load_bias + addend);
2554#if !defined(__LP64__)
2555 // Unprotect it afterwards...
2556 if (has_text_relocations) {
2557 if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
2558 DL_ERR("can't unprotect loadable segments for \"%s\": %s",
2559 get_realpath(), strerror(errno));
2560 return false;
2561 }
2562 }
2563#endif
2564 *reinterpret_cast<ElfW(Addr)*>(reloc) = ifunc_addr;
2565 }
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002566 break;
2567
2568#if defined(__aarch64__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002569 case R_AARCH64_ABS64:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002570 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002571 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002572 TRACE_TYPE(RELO, "RELO ABS64 %16llx <- %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002573 reloc, sym_addr + addend, sym_name);
2574 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend;
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002575 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002576 case R_AARCH64_ABS32:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002577 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002578 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002579 TRACE_TYPE(RELO, "RELO ABS32 %16llx <- %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002580 reloc, sym_addr + addend, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002581 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002582 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT32_MIN);
2583 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT32_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002584 if ((min_value <= (sym_addr + addend)) &&
2585 ((sym_addr + addend) <= max_value)) {
2586 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend;
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002587 } else {
2588 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002589 sym_addr + addend, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002590 return false;
2591 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002592 }
2593 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002594 case R_AARCH64_ABS16:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002595 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002596 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002597 TRACE_TYPE(RELO, "RELO ABS16 %16llx <- %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002598 reloc, sym_addr + addend, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002599 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002600 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN);
2601 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT16_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002602 if ((min_value <= (sym_addr + addend)) &&
2603 ((sym_addr + addend) <= max_value)) {
2604 *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002605 } else {
2606 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002607 sym_addr + addend, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002608 return false;
2609 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002610 }
2611 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002612 case R_AARCH64_PREL64:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002613 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002614 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002615 TRACE_TYPE(RELO, "RELO REL64 %16llx <- %16llx - %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002616 reloc, sym_addr + addend, rel->r_offset, sym_name);
2617 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset;
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002618 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002619 case R_AARCH64_PREL32:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002620 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002621 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002622 TRACE_TYPE(RELO, "RELO REL32 %16llx <- %16llx - %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002623 reloc, sym_addr + addend, rel->r_offset, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002624 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002625 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT32_MIN);
2626 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT32_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002627 if ((min_value <= (sym_addr + addend - rel->r_offset)) &&
2628 ((sym_addr + addend - rel->r_offset) <= max_value)) {
2629 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset;
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002630 } else {
2631 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002632 sym_addr + addend - rel->r_offset, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002633 return false;
2634 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002635 }
2636 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002637 case R_AARCH64_PREL16:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002638 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002639 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002640 TRACE_TYPE(RELO, "RELO REL16 %16llx <- %16llx - %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002641 reloc, sym_addr + addend, rel->r_offset, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002642 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002643 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN);
2644 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT16_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002645 if ((min_value <= (sym_addr + addend - rel->r_offset)) &&
2646 ((sym_addr + addend - rel->r_offset) <= max_value)) {
2647 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset;
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002648 } else {
2649 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002650 sym_addr + addend - rel->r_offset, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002651 return false;
2652 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002653 }
2654 break;
2655
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002656 case R_AARCH64_COPY:
Nick Kralevich76e289c2014-07-03 12:04:31 -07002657 /*
2658 * ET_EXEC is not supported so this should not happen.
2659 *
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002660 * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0056b/IHI0056B_aaelf64.pdf
Nick Kralevich76e289c2014-07-03 12:04:31 -07002661 *
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002662 * Section 4.6.11 "Dynamic relocations"
Nick Kralevich76e289c2014-07-03 12:04:31 -07002663 * R_AARCH64_COPY may only appear in executable objects where e_type is
2664 * set to ET_EXEC.
2665 */
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002666 DL_ERR("%s R_AARCH64_COPY relocations are not supported", get_realpath());
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002667 return false;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002668 case R_AARCH64_TLS_TPREL64:
Elliott Hughes0266ae52014-02-10 17:46:57 -08002669 TRACE_TYPE(RELO, "RELO TLS_TPREL64 *** %16llx <- %16llx - %16llx\n",
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002670 reloc, (sym_addr + addend), rel->r_offset);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002671 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002672 case R_AARCH64_TLS_DTPREL32:
Elliott Hughes0266ae52014-02-10 17:46:57 -08002673 TRACE_TYPE(RELO, "RELO TLS_DTPREL32 *** %16llx <- %16llx - %16llx\n",
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002674 reloc, (sym_addr + addend), rel->r_offset);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002675 break;
2676#elif defined(__x86_64__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002677 case R_X86_64_32:
2678 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002679 MARK(rel->r_offset);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002680 TRACE_TYPE(RELO, "RELO R_X86_64_32 %08zx <- +%08zx %s", static_cast<size_t>(reloc),
2681 static_cast<size_t>(sym_addr), sym_name);
Junichi Uekawaff35b1e2015-11-18 10:18:59 +09002682 *reinterpret_cast<Elf32_Addr*>(reloc) = sym_addr + addend;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002683 break;
2684 case R_X86_64_64:
2685 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002686 MARK(rel->r_offset);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002687 TRACE_TYPE(RELO, "RELO R_X86_64_64 %08zx <- +%08zx %s", static_cast<size_t>(reloc),
2688 static_cast<size_t>(sym_addr), sym_name);
Junichi Uekawaff35b1e2015-11-18 10:18:59 +09002689 *reinterpret_cast<Elf64_Addr*>(reloc) = sym_addr + addend;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002690 break;
2691 case R_X86_64_PC32:
2692 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002693 MARK(rel->r_offset);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002694 TRACE_TYPE(RELO, "RELO R_X86_64_PC32 %08zx <- +%08zx (%08zx - %08zx) %s",
2695 static_cast<size_t>(reloc), static_cast<size_t>(sym_addr - reloc),
2696 static_cast<size_t>(sym_addr), static_cast<size_t>(reloc), sym_name);
Junichi Uekawaff35b1e2015-11-18 10:18:59 +09002697 *reinterpret_cast<Elf32_Addr*>(reloc) = sym_addr + addend - reloc;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002698 break;
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002699#elif defined(__arm__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002700 case R_ARM_ABS32:
2701 count_relocation(kRelocAbsolute);
2702 MARK(rel->r_offset);
2703 TRACE_TYPE(RELO, "RELO ABS %08x <- %08x %s", reloc, sym_addr, sym_name);
2704 *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
2705 break;
2706 case R_ARM_REL32:
2707 count_relocation(kRelocRelative);
2708 MARK(rel->r_offset);
2709 TRACE_TYPE(RELO, "RELO REL32 %08x <- %08x - %08x %s",
2710 reloc, sym_addr, rel->r_offset, sym_name);
2711 *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr - rel->r_offset;
2712 break;
2713 case R_ARM_COPY:
2714 /*
2715 * ET_EXEC is not supported so this should not happen.
2716 *
2717 * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044d/IHI0044D_aaelf.pdf
2718 *
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002719 * Section 4.6.1.10 "Dynamic relocations"
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002720 * R_ARM_COPY may only appear in executable objects where e_type is
2721 * set to ET_EXEC.
2722 */
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002723 DL_ERR("%s R_ARM_COPY relocations are not supported", get_realpath());
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002724 return false;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002725#elif defined(__i386__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002726 case R_386_32:
2727 count_relocation(kRelocRelative);
2728 MARK(rel->r_offset);
2729 TRACE_TYPE(RELO, "RELO R_386_32 %08x <- +%08x %s", reloc, sym_addr, sym_name);
2730 *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
2731 break;
2732 case R_386_PC32:
2733 count_relocation(kRelocRelative);
2734 MARK(rel->r_offset);
2735 TRACE_TYPE(RELO, "RELO R_386_PC32 %08x <- +%08x (%08x - %08x) %s",
2736 reloc, (sym_addr - reloc), sym_addr, reloc, sym_name);
2737 *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr - reloc);
2738 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002739#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002740 default:
2741 DL_ERR("unknown reloc type %d @ %p (%zu)", type, rel, idx);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002742 return false;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002743 }
2744 }
2745 return true;
Raghu Gandhamd7daacb2012-07-31 12:07:22 -07002746}
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002747#endif // !defined(__mips__)
Raghu Gandhamd7daacb2012-07-31 12:07:22 -07002748
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002749// An empty list of soinfos
Dimitry Ivanovb943f302016-08-03 16:00:10 -07002750static soinfo_list_t g_empty_list;
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07002751
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002752bool soinfo::prelink_image() {
Ningsheng Jiane93be992014-09-16 15:22:10 +08002753 /* Extract dynamic section */
2754 ElfW(Word) dynamic_flags = 0;
2755 phdr_table_get_dynamic_section(phdr, phnum, load_bias, &dynamic, &dynamic_flags);
Dmitriy Ivanov498eb182014-09-05 14:57:59 -07002756
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002757 /* We can't log anything until the linker is relocated */
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002758 bool relocating_linker = (flags_ & FLAG_LINKER) != 0;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002759 if (!relocating_linker) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07002760 INFO("[ Linking \"%s\" ]", get_realpath());
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002761 DEBUG("si->base = %p si->flags = 0x%08x", reinterpret_cast<void*>(base), flags_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002762 }
2763
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002764 if (dynamic == nullptr) {
David 'Digit' Turnerb52e4382012-06-19 01:24:17 +02002765 if (!relocating_linker) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002766 DL_ERR("missing PT_DYNAMIC in \"%s\"", get_realpath());
David 'Digit' Turnerb52e4382012-06-19 01:24:17 +02002767 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002768 return false;
2769 } else {
2770 if (!relocating_linker) {
2771 DEBUG("dynamic = %p", dynamic);
David 'Digit' Turner63f99f42012-06-19 00:08:39 +02002772 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002773 }
David 'Digit' Turner63f99f42012-06-19 00:08:39 +02002774
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07002775#if defined(__arm__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002776 (void) phdr_table_get_arm_exidx(phdr, phnum, load_bias,
2777 &ARM_exidx, &ARM_exidx_count);
David 'Digit' Turner63f99f42012-06-19 00:08:39 +02002778#endif
2779
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002780 // Extract useful information from dynamic section.
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07002781 // Note that: "Except for the DT_NULL element at the end of the array,
2782 // and the relative order of DT_NEEDED elements, entries may appear in any order."
2783 //
2784 // source: http://www.sco.com/developers/gabi/1998-04-29/ch5.dynamic.html
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002785 uint32_t needed_count = 0;
2786 for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
2787 DEBUG("d = %p, d[0](tag) = %p d[1](val) = %p",
2788 d, reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
2789 switch (d->d_tag) {
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002790 case DT_SONAME:
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07002791 // this is parsed after we have strtab initialized (see below).
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002792 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002793
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002794 case DT_HASH:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002795 nbucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0];
2796 nchain_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
2797 bucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8);
2798 chain_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8 + nbucket_ * 4);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002799 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002800
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002801 case DT_GNU_HASH:
Dmitriy Ivanov3597b802015-03-09 12:02:02 -07002802 gnu_nbucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0];
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002803 // skip symndx
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002804 gnu_maskwords_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[2];
2805 gnu_shift2_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[3];
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002806
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002807 gnu_bloom_filter_ = reinterpret_cast<ElfW(Addr)*>(load_bias + d->d_un.d_ptr + 16);
Dmitriy Ivanov3597b802015-03-09 12:02:02 -07002808 gnu_bucket_ = reinterpret_cast<uint32_t*>(gnu_bloom_filter_ + gnu_maskwords_);
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002809 // amend chain for symndx = header[1]
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002810 gnu_chain_ = gnu_bucket_ + gnu_nbucket_ -
2811 reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002812
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002813 if (!powerof2(gnu_maskwords_)) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002814 DL_ERR("invalid maskwords for gnu_hash = 0x%x, in \"%s\" expecting power to two",
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002815 gnu_maskwords_, get_realpath());
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002816 return false;
2817 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002818 --gnu_maskwords_;
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002819
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002820 flags_ |= FLAG_GNU_HASH;
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002821 break;
2822
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002823 case DT_STRTAB:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002824 strtab_ = reinterpret_cast<const char*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002825 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002826
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07002827 case DT_STRSZ:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002828 strtab_size_ = d->d_un.d_val;
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07002829 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002830
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002831 case DT_SYMTAB:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002832 symtab_ = reinterpret_cast<ElfW(Sym)*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002833 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002834
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002835 case DT_SYMENT:
2836 if (d->d_un.d_val != sizeof(ElfW(Sym))) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002837 DL_ERR("invalid DT_SYMENT: %zd in \"%s\"",
2838 static_cast<size_t>(d->d_un.d_val), get_realpath());
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002839 return false;
2840 }
2841 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002842
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002843 case DT_PLTREL:
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002844#if defined(USE_RELA)
2845 if (d->d_un.d_val != DT_RELA) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002846 DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_RELA", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002847 return false;
2848 }
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002849#else
2850 if (d->d_un.d_val != DT_REL) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002851 DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_REL", get_realpath());
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002852 return false;
2853 }
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002854#endif
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002855 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002856
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002857 case DT_JMPREL:
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07002858#if defined(USE_RELA)
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002859 plt_rela_ = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002860#else
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002861 plt_rel_ = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002862#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002863 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002864
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002865 case DT_PLTRELSZ:
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07002866#if defined(USE_RELA)
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002867 plt_rela_count_ = d->d_un.d_val / sizeof(ElfW(Rela));
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002868#else
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002869 plt_rel_count_ = d->d_un.d_val / sizeof(ElfW(Rel));
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002870#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002871 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002872
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002873 case DT_PLTGOT:
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002874#if defined(__mips__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002875 // Used by mips and mips64.
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002876 plt_got_ = reinterpret_cast<ElfW(Addr)**>(load_bias + d->d_un.d_ptr);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002877#endif
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002878 // Ignore for other platforms... (because RTLD_LAZY is not supported)
2879 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002880
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002881 case DT_DEBUG:
2882 // Set the DT_DEBUG entry to the address of _r_debug for GDB
2883 // if the dynamic table is writable
Chris Dearman99186652014-02-06 20:36:51 -08002884// FIXME: not working currently for N64
2885// The flags for the LOAD and DYNAMIC program headers do not agree.
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002886// The LOAD section containing the dynamic table has been mapped as
Chris Dearman99186652014-02-06 20:36:51 -08002887// read-only, but the DYNAMIC header claims it is writable.
2888#if !(defined(__mips__) && defined(__LP64__))
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002889 if ((dynamic_flags & PF_W) != 0) {
2890 d->d_un.d_val = reinterpret_cast<uintptr_t>(&_r_debug);
2891 }
Chris Dearman99186652014-02-06 20:36:51 -08002892#endif
Dmitriy Ivanovc6292ea2015-02-13 16:29:50 -08002893 break;
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07002894#if defined(USE_RELA)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002895 case DT_RELA:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002896 rela_ = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002897 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002898
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002899 case DT_RELASZ:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002900 rela_count_ = d->d_un.d_val / sizeof(ElfW(Rela));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002901 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002902
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002903 case DT_ANDROID_RELA:
2904 android_relocs_ = reinterpret_cast<uint8_t*>(load_bias + d->d_un.d_ptr);
2905 break;
2906
2907 case DT_ANDROID_RELASZ:
2908 android_relocs_size_ = d->d_un.d_val;
2909 break;
2910
2911 case DT_ANDROID_REL:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002912 DL_ERR("unsupported DT_ANDROID_REL in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002913 return false;
2914
2915 case DT_ANDROID_RELSZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002916 DL_ERR("unsupported DT_ANDROID_RELSZ in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002917 return false;
2918
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002919 case DT_RELAENT:
2920 if (d->d_un.d_val != sizeof(ElfW(Rela))) {
Dmitriy Ivanovf240aa82014-09-16 23:34:20 -07002921 DL_ERR("invalid DT_RELAENT: %zd", static_cast<size_t>(d->d_un.d_val));
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002922 return false;
2923 }
2924 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002925
2926 // ignored (see DT_RELCOUNT comments for details)
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002927 case DT_RELACOUNT:
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002928 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002929
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002930 case DT_REL:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002931 DL_ERR("unsupported DT_REL in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002932 return false;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002933
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002934 case DT_RELSZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002935 DL_ERR("unsupported DT_RELSZ in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002936 return false;
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002937
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002938#else
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002939 case DT_REL:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002940 rel_ = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002941 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002942
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002943 case DT_RELSZ:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002944 rel_count_ = d->d_un.d_val / sizeof(ElfW(Rel));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002945 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002946
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002947 case DT_RELENT:
2948 if (d->d_un.d_val != sizeof(ElfW(Rel))) {
Dmitriy Ivanovf240aa82014-09-16 23:34:20 -07002949 DL_ERR("invalid DT_RELENT: %zd", static_cast<size_t>(d->d_un.d_val));
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002950 return false;
2951 }
2952 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002953
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002954 case DT_ANDROID_REL:
2955 android_relocs_ = reinterpret_cast<uint8_t*>(load_bias + d->d_un.d_ptr);
2956 break;
2957
2958 case DT_ANDROID_RELSZ:
2959 android_relocs_size_ = d->d_un.d_val;
2960 break;
2961
2962 case DT_ANDROID_RELA:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002963 DL_ERR("unsupported DT_ANDROID_RELA in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002964 return false;
2965
2966 case DT_ANDROID_RELASZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002967 DL_ERR("unsupported DT_ANDROID_RELASZ in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002968 return false;
2969
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002970 // "Indicates that all RELATIVE relocations have been concatenated together,
2971 // and specifies the RELATIVE relocation count."
2972 //
2973 // TODO: Spec also mentions that this can be used to optimize relocation process;
2974 // Not currently used by bionic linker - ignored.
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002975 case DT_RELCOUNT:
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002976 break;
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002977
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002978 case DT_RELA:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002979 DL_ERR("unsupported DT_RELA in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002980 return false;
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002981
2982 case DT_RELASZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002983 DL_ERR("unsupported DT_RELASZ in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002984 return false;
2985
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002986#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002987 case DT_INIT:
Dimitry Ivanov55437462016-07-20 15:33:07 -07002988 init_func_ = reinterpret_cast<linker_ctor_function_t>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002989 DEBUG("%s constructors (DT_INIT) found at %p", get_realpath(), init_func_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002990 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002991
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002992 case DT_FINI:
Dimitry Ivanov55437462016-07-20 15:33:07 -07002993 fini_func_ = reinterpret_cast<linker_dtor_function_t>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002994 DEBUG("%s destructors (DT_FINI) found at %p", get_realpath(), fini_func_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002995 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002996
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002997 case DT_INIT_ARRAY:
Dimitry Ivanov55437462016-07-20 15:33:07 -07002998 init_array_ = reinterpret_cast<linker_ctor_function_t*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002999 DEBUG("%s constructors (DT_INIT_ARRAY) found at %p", get_realpath(), init_array_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003000 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003001
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003002 case DT_INIT_ARRAYSZ:
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -08003003 init_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003004 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003005
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003006 case DT_FINI_ARRAY:
Dimitry Ivanov55437462016-07-20 15:33:07 -07003007 fini_array_ = reinterpret_cast<linker_dtor_function_t*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003008 DEBUG("%s destructors (DT_FINI_ARRAY) found at %p", get_realpath(), fini_array_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003009 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003010
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003011 case DT_FINI_ARRAYSZ:
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -08003012 fini_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003013 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003014
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003015 case DT_PREINIT_ARRAY:
Dimitry Ivanov55437462016-07-20 15:33:07 -07003016 preinit_array_ = reinterpret_cast<linker_ctor_function_t*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003017 DEBUG("%s constructors (DT_PREINIT_ARRAY) found at %p", get_realpath(), preinit_array_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003018 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003019
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003020 case DT_PREINIT_ARRAYSZ:
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -08003021 preinit_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003022 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003023
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003024 case DT_TEXTREL:
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003025#if defined(__LP64__)
Dimitry Ivanov816676e2016-10-19 11:00:28 -07003026 DL_ERR("\"%s\" has text relocations", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003027 return false;
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003028#else
3029 has_text_relocations = true;
3030 break;
3031#endif
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003032
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003033 case DT_SYMBOLIC:
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -07003034 has_DT_SYMBOLIC = true;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003035 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003036
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003037 case DT_NEEDED:
3038 ++needed_count;
3039 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003040
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003041 case DT_FLAGS:
3042 if (d->d_un.d_val & DF_TEXTREL) {
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003043#if defined(__LP64__)
Dimitry Ivanov816676e2016-10-19 11:00:28 -07003044 DL_ERR("\"%s\" has text relocations", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003045 return false;
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003046#else
3047 has_text_relocations = true;
3048#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003049 }
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -07003050 if (d->d_un.d_val & DF_SYMBOLIC) {
3051 has_DT_SYMBOLIC = true;
3052 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003053 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003054
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07003055 case DT_FLAGS_1:
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07003056 set_dt_flags_1(d->d_un.d_val);
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -07003057
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07003058 if ((d->d_un.d_val & ~SUPPORTED_DT_FLAGS_1) != 0) {
Dimitry Ivanov816676e2016-10-19 11:00:28 -07003059 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 -07003060 }
3061 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003062#if defined(__mips__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003063 case DT_MIPS_RLD_MAP:
3064 // Set the DT_MIPS_RLD_MAP entry to the address of _r_debug for GDB.
3065 {
3066 r_debug** dp = reinterpret_cast<r_debug**>(load_bias + d->d_un.d_ptr);
3067 *dp = &_r_debug;
3068 }
3069 break;
Lazar Trsic83b44a92016-04-06 13:39:17 +02003070 case DT_MIPS_RLD_MAP_REL:
3071 // Set the DT_MIPS_RLD_MAP_REL entry to the address of _r_debug for GDB.
Raghu Gandham68815722014-12-18 19:12:19 -08003072 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07003073 r_debug** dp = reinterpret_cast<r_debug**>(
3074 reinterpret_cast<ElfW(Addr)>(d) + d->d_un.d_val);
Raghu Gandham68815722014-12-18 19:12:19 -08003075 *dp = &_r_debug;
3076 }
3077 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003078
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003079 case DT_MIPS_RLD_VERSION:
3080 case DT_MIPS_FLAGS:
3081 case DT_MIPS_BASE_ADDRESS:
3082 case DT_MIPS_UNREFEXTNO:
3083 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003084
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003085 case DT_MIPS_SYMTABNO:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003086 mips_symtabno_ = d->d_un.d_val;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003087 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003088
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003089 case DT_MIPS_LOCAL_GOTNO:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003090 mips_local_gotno_ = d->d_un.d_val;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003091 break;
3092
3093 case DT_MIPS_GOTSYM:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003094 mips_gotsym_ = d->d_un.d_val;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003095 break;
3096#endif
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003097 // Ignored: "Its use has been superseded by the DF_BIND_NOW flag"
3098 case DT_BIND_NOW:
3099 break;
3100
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003101 case DT_VERSYM:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003102 versym_ = reinterpret_cast<ElfW(Versym)*>(load_bias + d->d_un.d_ptr);
3103 break;
3104
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003105 case DT_VERDEF:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003106 verdef_ptr_ = load_bias + d->d_un.d_ptr;
3107 break;
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003108 case DT_VERDEFNUM:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003109 verdef_cnt_ = d->d_un.d_val;
3110 break;
3111
Alexander Ivchenkoe8314332014-12-02 15:32:25 +03003112 case DT_VERNEED:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003113 verneed_ptr_ = load_bias + d->d_un.d_ptr;
3114 break;
3115
Alexander Ivchenkoe8314332014-12-02 15:32:25 +03003116 case DT_VERNEEDNUM:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003117 verneed_cnt_ = d->d_un.d_val;
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003118 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003119
Evgenii Stepanov68650822015-06-10 13:38:39 -07003120 case DT_RUNPATH:
3121 // this is parsed after we have strtab initialized (see below).
3122 break;
3123
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003124 default:
Dmitriy Ivanov8f61d992014-09-16 14:31:06 -07003125 if (!relocating_linker) {
Dimitry Ivanov816676e2016-10-19 11:00:28 -07003126 DL_WARN("\"%s\" unused DT entry: type %p arg %p", get_realpath(),
Dmitriy Ivanov8f61d992014-09-16 14:31:06 -07003127 reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
3128 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003129 break;
Brian Carlstromd4ee82d2013-02-28 15:58:45 -08003130 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003131 }
3132
Duane Sandbc425c72015-06-01 16:29:14 -07003133#if defined(__mips__) && !defined(__LP64__)
3134 if (!mips_check_and_adjust_fp_modes()) {
3135 return false;
3136 }
3137#endif
3138
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003139 DEBUG("si->base = %p, si->strtab = %p, si->symtab = %p",
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003140 reinterpret_cast<void*>(base), strtab_, symtab_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003141
3142 // Sanity checks.
3143 if (relocating_linker && needed_count != 0) {
3144 DL_ERR("linker cannot have DT_NEEDED dependencies on other libraries");
3145 return false;
3146 }
Dmitriy Ivanov3597b802015-03-09 12:02:02 -07003147 if (nbucket_ == 0 && gnu_nbucket_ == 0) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003148 DL_ERR("empty/missing DT_HASH/DT_GNU_HASH in \"%s\" "
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003149 "(new hash type from the future?)", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003150 return false;
3151 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003152 if (strtab_ == 0) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003153 DL_ERR("empty/missing DT_STRTAB in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003154 return false;
3155 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003156 if (symtab_ == 0) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003157 DL_ERR("empty/missing DT_SYMTAB in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003158 return false;
3159 }
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003160
Dmitriy Ivanov624b8f12015-06-08 10:41:33 -07003161 // second pass - parse entries relying on strtab
3162 for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
Evgenii Stepanov68650822015-06-10 13:38:39 -07003163 switch (d->d_tag) {
3164 case DT_SONAME:
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07003165 set_soname(get_string(d->d_un.d_val));
Evgenii Stepanov68650822015-06-10 13:38:39 -07003166 break;
3167 case DT_RUNPATH:
Evgenii Stepanov68650822015-06-10 13:38:39 -07003168 set_dt_runpath(get_string(d->d_un.d_val));
3169 break;
Dmitriy Ivanov624b8f12015-06-08 10:41:33 -07003170 }
3171 }
3172
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003173 // Before M release linker was using basename in place of soname.
Dmitriy Ivanov19133522015-06-02 17:36:54 -07003174 // In the case when dt_soname is absent some apps stop working
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003175 // because they can't find dt_needed library by soname.
3176 // This workaround should keep them working. (applies only
Elliott Hughes5bc78c82016-11-16 11:35:43 -08003177 // for apps targeting sdk version < M). Make an exception for
Dmitriy Ivanov19133522015-06-02 17:36:54 -07003178 // the main executable and linker; they do not need to have dt_soname
Dimitry Ivanov3f660572016-09-09 10:00:39 -07003179 if (soname_ == nullptr &&
3180 this != solist_get_somain() &&
3181 (flags_ & FLAG_LINKER) == 0 &&
Elliott Hughes5bc78c82016-11-16 11:35:43 -08003182 get_application_target_sdk_version() < __ANDROID_API_M__) {
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003183 soname_ = basename(realpath_.c_str());
3184 DL_WARN("%s: is missing DT_SONAME will use basename as a replacement: \"%s\"",
3185 get_realpath(), soname_);
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07003186 // 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 -07003187 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003188 return true;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07003189}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003190
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003191bool soinfo::link_image(const soinfo_list_t& global_group, const soinfo_list_t& local_group,
3192 const android_dlextinfo* extinfo) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003193
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08003194 local_group_root_ = local_group.front();
3195 if (local_group_root_ == nullptr) {
3196 local_group_root_ = this;
3197 }
3198
Dmitriy Ivanov19133522015-06-02 17:36:54 -07003199 if ((flags_ & FLAG_LINKER) == 0 && local_group_root_ == this) {
3200 target_sdk_version_ = get_application_target_sdk_version();
3201 }
3202
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003203 VersionTracker version_tracker;
3204
3205 if (!version_tracker.init(this)) {
3206 return false;
3207 }
3208
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003209#if !defined(__LP64__)
3210 if (has_text_relocations) {
Elliott Hughes5bc78c82016-11-16 11:35:43 -08003211 // Fail if app is targeting M or above.
3212 if (get_application_target_sdk_version() >= __ANDROID_API_M__) {
Dimitry Ivanov816676e2016-10-19 11:00:28 -07003213 DL_ERR_AND_LOG("\"%s\" has text relocations", get_realpath());
Dmitriy Ivanove4ad91f2015-06-12 15:00:31 -07003214 return false;
3215 }
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003216 // Make segments writable to allow text relocations to work properly. We will later call
Dmitriy Ivanov7e039932015-10-01 14:02:19 -07003217 // phdr_table_protect_segments() after all of them are applied.
Dimitry Ivanov816676e2016-10-19 11:00:28 -07003218 DL_WARN("\"%s\" has text relocations. This is wasting memory and prevents "
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003219 "security hardening. Please fix.", get_realpath());
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07003220 add_dlwarning(get_realpath(), "text relocations");
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003221 if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
3222 DL_ERR("can't unprotect loadable segments for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003223 get_realpath(), strerror(errno));
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003224 return false;
3225 }
3226 }
3227#endif
3228
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003229 if (android_relocs_ != nullptr) {
3230 // check signature
3231 if (android_relocs_size_ > 3 &&
3232 android_relocs_[0] == 'A' &&
3233 android_relocs_[1] == 'P' &&
Dmitriy Ivanov18870d32015-04-22 13:10:04 -07003234 android_relocs_[2] == 'S' &&
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003235 android_relocs_[3] == '2') {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003236 DEBUG("[ android relocating %s ]", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003237
3238 bool relocated = false;
3239 const uint8_t* packed_relocs = android_relocs_ + 4;
3240 const size_t packed_relocs_size = android_relocs_size_ - 4;
3241
Dmitriy Ivanov18870d32015-04-22 13:10:04 -07003242 relocated = relocate(
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003243 version_tracker,
Dmitriy Ivanov18870d32015-04-22 13:10:04 -07003244 packed_reloc_iterator<sleb128_decoder>(
3245 sleb128_decoder(packed_relocs, packed_relocs_size)),
3246 global_group, local_group);
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003247
3248 if (!relocated) {
3249 return false;
3250 }
3251 } else {
3252 DL_ERR("bad android relocation header.");
3253 return false;
3254 }
3255 }
3256
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07003257#if defined(USE_RELA)
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003258 if (rela_ != nullptr) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003259 DEBUG("[ relocating %s ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003260 if (!relocate(version_tracker,
3261 plain_reloc_iterator(rela_, rela_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003262 return false;
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07003263 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003264 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003265 if (plt_rela_ != nullptr) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003266 DEBUG("[ relocating %s plt ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003267 if (!relocate(version_tracker,
3268 plain_reloc_iterator(plt_rela_, plt_rela_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003269 return false;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003270 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003271 }
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07003272#else
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003273 if (rel_ != nullptr) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003274 DEBUG("[ relocating %s ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003275 if (!relocate(version_tracker,
3276 plain_reloc_iterator(rel_, rel_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003277 return false;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003278 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003279 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003280 if (plt_rel_ != nullptr) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003281 DEBUG("[ relocating %s plt ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003282 if (!relocate(version_tracker,
3283 plain_reloc_iterator(plt_rel_, plt_rel_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003284 return false;
Brigid Smithc5a13ef2014-07-23 11:22:25 -07003285 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003286 }
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07003287#endif
Brigid Smithc5a13ef2014-07-23 11:22:25 -07003288
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07003289#if defined(__mips__)
Dmitriy Ivanovf39cb632015-04-30 20:17:03 -07003290 if (!mips_relocate_got(version_tracker, global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003291 return false;
3292 }
Raghu Gandhamd7daacb2012-07-31 12:07:22 -07003293#endif
3294
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003295 DEBUG("[ finished linking %s ]", get_realpath());
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003296
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003297#if !defined(__LP64__)
3298 if (has_text_relocations) {
3299 // All relocations are done, we can protect our segments back to read-only.
3300 if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
3301 DL_ERR("can't protect segments for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003302 get_realpath(), strerror(errno));
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003303 return false;
3304 }
3305 }
3306#endif
3307
Mingwei Shibe910522015-11-12 07:02:14 +00003308 // We can also turn on GNU RELRO protection if we're not linking the dynamic linker
3309 // itself --- it can't make system calls yet, and will have to call protect_relro later.
3310 if (!is_linker() && !protect_relro()) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003311 return false;
3312 }
Nick Kralevich9ec0f032012-02-28 10:40:00 -08003313
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003314 /* Handle serializing/sharing the RELRO segment */
3315 if (extinfo && (extinfo->flags & ANDROID_DLEXT_WRITE_RELRO)) {
3316 if (phdr_table_serialize_gnu_relro(phdr, phnum, load_bias,
3317 extinfo->relro_fd) < 0) {
3318 DL_ERR("failed serializing GNU RELRO section for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003319 get_realpath(), strerror(errno));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003320 return false;
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +00003321 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003322 } else if (extinfo && (extinfo->flags & ANDROID_DLEXT_USE_RELRO)) {
3323 if (phdr_table_map_gnu_relro(phdr, phnum, load_bias,
3324 extinfo->relro_fd) < 0) {
3325 DL_ERR("failed mapping GNU RELRO section for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003326 get_realpath(), strerror(errno));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003327 return false;
3328 }
3329 }
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +00003330
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003331 notify_gdb_of_load(this);
3332 return true;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003333}
3334
Mingwei Shibe910522015-11-12 07:02:14 +00003335bool soinfo::protect_relro() {
3336 if (phdr_table_protect_gnu_relro(phdr, phnum, load_bias) < 0) {
3337 DL_ERR("can't enable GNU RELRO protection for \"%s\": %s",
3338 get_realpath(), strerror(errno));
3339 return false;
3340 }
3341 return true;
3342}
3343
Dimitry Ivanov4cabfaa2017-03-07 11:19:05 -08003344static void init_default_namespace_no_config(bool is_asan) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003345 g_default_namespace.set_isolated(false);
Dimitry Ivanov77ad6422017-03-06 13:02:29 -08003346 auto default_ld_paths = is_asan ? kAsanDefaultLdPaths : kDefaultLdPaths;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003347
neo.chae2589f9d2016-10-04 11:00:27 +09003348 char real_path[PATH_MAX];
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003349 std::vector<std::string> ld_default_paths;
Dimitry Ivanov77ad6422017-03-06 13:02:29 -08003350 for (size_t i = 0; default_ld_paths[i] != nullptr; ++i) {
3351 if (realpath(default_ld_paths[i], real_path) != nullptr) {
neo.chae2589f9d2016-10-04 11:00:27 +09003352 ld_default_paths.push_back(real_path);
3353 } else {
Dimitry Ivanov77ad6422017-03-06 13:02:29 -08003354 ld_default_paths.push_back(default_ld_paths[i]);
neo.chae2589f9d2016-10-04 11:00:27 +09003355 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003356 }
3357
3358 g_default_namespace.set_default_library_paths(std::move(ld_default_paths));
Dimitry Ivanov4cabfaa2017-03-07 11:19:05 -08003359}
3360
3361void init_default_namespace(const char* executable_path) {
3362 g_default_namespace.set_name("(default)");
3363
3364 soinfo* somain = solist_get_somain();
3365
3366 const char *interp = phdr_table_get_interpreter_name(somain->phdr, somain->phnum,
3367 somain->load_bias);
3368 const char* bname = basename(interp);
3369
3370 g_is_asan = bname != nullptr &&
3371 (strcmp(bname, "linker_asan") == 0 ||
3372 strcmp(bname, "linker_asan64") == 0);
3373
3374 const Config* config = nullptr;
3375
3376 std::string error_msg;
3377
3378 if (!Config::read_binary_config(kLdConfigFilePath,
3379 executable_path,
3380 g_is_asan,
3381 &config,
3382 &error_msg)) {
3383 if (!error_msg.empty()) {
3384 DL_WARN("error reading config file \"%s\" for \"%s\" (will use default configuration): %s",
3385 kLdConfigFilePath,
3386 executable_path,
3387 error_msg.c_str());
3388 }
3389 config = nullptr;
3390 }
3391
3392 if (config == nullptr) {
3393 init_default_namespace_no_config(g_is_asan);
3394 return;
3395 }
3396
3397 const auto& namespace_configs = config->namespace_configs();
3398 std::unordered_map<std::string, android_namespace_t*> namespaces;
3399
3400 // 1. Initialize default namespace
3401 const NamespaceConfig* default_ns_config = config->default_namespace_config();
3402
3403 g_default_namespace.set_isolated(default_ns_config->isolated());
3404 g_default_namespace.set_default_library_paths(default_ns_config->search_paths());
3405 g_default_namespace.set_permitted_paths(default_ns_config->permitted_paths());
3406
3407 namespaces[default_ns_config->name()] = &g_default_namespace;
3408
3409 // 2. Initialize other namespaces
3410
3411 for (auto& ns_config : namespace_configs) {
3412 if (namespaces.find(ns_config->name()) != namespaces.end()) {
3413 continue;
3414 }
3415
3416 android_namespace_t* ns = new (g_namespace_allocator.alloc()) android_namespace_t();
3417 ns->set_name(ns_config->name());
3418 ns->set_isolated(ns_config->isolated());
3419 ns->set_default_library_paths(ns_config->search_paths());
3420 ns->set_permitted_paths(ns_config->permitted_paths());
3421
3422 namespaces[ns_config->name()] = ns;
3423 }
3424
3425 // 3. Establish links between namespaces
3426 for (auto& ns_config : namespace_configs) {
3427 auto it_from = namespaces.find(ns_config->name());
3428 CHECK(it_from != namespaces.end());
3429 android_namespace_t* namespace_from = it_from->second;
3430 for (const NamespaceLinkConfig& ns_link : ns_config->links()) {
3431 auto it_to = namespaces.find(ns_link.ns_name());
3432 CHECK(it_to != namespaces.end());
3433 android_namespace_t* namespace_to = it_to->second;
3434 link_namespaces(namespace_from, namespace_to, ns_link.shared_libs().c_str());
3435 }
3436 }
3437 // we can no longer rely on the fact that libdl.so is part of default namespace
3438 // this is why we want to add ld-android.so to all namespaces from ld.config.txt
3439 soinfo* ld_android_so = solist_get_head();
3440 for (auto it : namespaces) {
3441 it.second->add_soinfo(ld_android_so);
3442 // TODO (dimitry): somain and ld_preloads should probably be added to all of these namespaces too?
3443 }
3444
3445 set_application_target_sdk_version(config->target_sdk_version());
3446}