blob: 497fc2d378350e00d80b94a6ecba61f4c39c373e [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
Dimitry Ivanovd3e7d082017-03-27 14:11:02 -07001113static bool find_loaded_library_by_inode(android_namespace_t* ns,
1114 const struct stat& file_stat,
1115 off64_t file_offset,
1116 bool search_linked_namespaces,
1117 soinfo** candidate) {
1118
1119 auto predicate = [&](soinfo* si) {
1120 return si->get_st_dev() != 0 &&
1121 si->get_st_ino() != 0 &&
1122 si->get_st_dev() == file_stat.st_dev &&
1123 si->get_st_ino() == file_stat.st_ino &&
1124 si->get_file_offset() == file_offset;
1125 };
1126
1127 *candidate = ns->soinfo_list().find_if(predicate);
1128
1129 if (*candidate == nullptr && search_linked_namespaces) {
1130 for (auto& link : ns->linked_namespaces()) {
1131 android_namespace_t* linked_ns = link.linked_namespace();
1132 soinfo* si = linked_ns->soinfo_list().find_if(predicate);
1133
1134 if (si != nullptr && link.is_accessible(si->get_soname())) {
1135 *candidate = si;
1136 return true;
1137 }
1138 }
1139 }
1140
1141 return *candidate != nullptr;
1142}
1143
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001144static bool load_library(android_namespace_t* ns,
1145 LoadTask* task,
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001146 LoadTaskList* load_tasks,
1147 int rtld_flags,
Dimitry Ivanovd3e7d082017-03-27 14:11:02 -07001148 const std::string& realpath,
1149 bool search_linked_namespaces) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001150 off64_t file_offset = task->get_file_offset();
1151 const char* name = task->get_name();
1152 const android_dlextinfo* extinfo = task->get_extinfo();
1153
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001154 if ((file_offset % PAGE_SIZE) != 0) {
Dmitriy Ivanova6c12792014-10-21 12:09:18 -07001155 DL_ERR("file offset for the library \"%s\" is not page-aligned: %" PRId64, name, file_offset);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001156 return false;
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001157 }
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001158 if (file_offset < 0) {
1159 DL_ERR("file offset for the library \"%s\" is negative: %" PRId64, name, file_offset);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001160 return false;
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001161 }
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001162
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001163 struct stat file_stat;
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001164 if (TEMP_FAILURE_RETRY(fstat(task->get_fd(), &file_stat)) != 0) {
Dmitriy Ivanova6c12792014-10-21 12:09:18 -07001165 DL_ERR("unable to stat file for the library \"%s\": %s", name, strerror(errno));
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001166 return false;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001167 }
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001168 if (file_offset >= file_stat.st_size) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07001169 DL_ERR("file offset for the library \"%s\" >= file size: %" PRId64 " >= %" PRId64,
1170 name, file_offset, file_stat.st_size);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001171 return false;
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001172 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001173
1174 // Check for symlink and other situations where
Dmitriy Ivanov9b821362015-04-02 16:03:56 -07001175 // file can have different names, unless ANDROID_DLEXT_FORCE_LOAD is set
1176 if (extinfo == nullptr || (extinfo->flags & ANDROID_DLEXT_FORCE_LOAD) == 0) {
Dimitry Ivanovd3e7d082017-03-27 14:11:02 -07001177 soinfo* si = nullptr;
1178 if (find_loaded_library_by_inode(ns, file_stat, file_offset, search_linked_namespaces, &si)) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001179 TRACE("library \"%s\" is already loaded under different name/path \"%s\" - "
1180 "will return existing soinfo", name, si->get_realpath());
1181 task->set_soinfo(si);
1182 return true;
1183 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001184 }
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07001185
Dmitriy Ivanove8ba50f2014-09-15 17:00:10 -07001186 if ((rtld_flags & RTLD_NOLOAD) != 0) {
Dmitriy Ivanova6ac54a2014-09-09 10:21:42 -07001187 DL_ERR("library \"%s\" wasn't loaded and RTLD_NOLOAD prevented it", name);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001188 return false;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001189 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001190
Dimitry Ivanov22840aa2015-12-04 18:28:49 -08001191 if (!ns->is_accessible(realpath)) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001192 // TODO(dimitry): workaround for http://b/26394120 - the grey-list
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001193
1194 // TODO(dimitry) before O release: add a namespace attribute to have this enabled
1195 // only for classloader-namespaces
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001196 const soinfo* needed_by = task->is_dt_needed() ? task->get_needed_by() : nullptr;
Dimitry Ivanov35c8e3b2017-02-27 12:17:47 -08001197 if (is_greylisted(ns, name, needed_by)) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001198 // print warning only if needed by non-system library
1199 if (needed_by == nullptr || !is_system_library(needed_by->get_realpath())) {
1200 const soinfo* needed_or_dlopened_by = task->get_needed_by();
1201 const char* sopath = needed_or_dlopened_by == nullptr ? "(unknown)" :
1202 needed_or_dlopened_by->get_realpath();
1203 DL_WARN("library \"%s\" (\"%s\") needed or dlopened by \"%s\" is not accessible for the namespace \"%s\""
1204 " - the access is temporarily granted as a workaround for http://b/26394120, note that the access"
1205 " will be removed in future releases of Android.",
1206 name, realpath.c_str(), sopath, ns->get_name());
1207 add_dlwarning(sopath, "unauthorized access to", name);
1208 }
1209 } else {
1210 // do not load libraries if they are not accessible for the specified namespace.
1211 const char* needed_or_dlopened_by = task->get_needed_by() == nullptr ?
1212 "(unknown)" :
1213 task->get_needed_by()->get_realpath();
Dimitry Ivanovd17a3772016-03-01 13:11:28 -08001214
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001215 DL_ERR("library \"%s\" needed or dlopened by \"%s\" is not accessible for the namespace \"%s\"",
1216 name, needed_or_dlopened_by, ns->get_name());
Dimitry Ivanovd17a3772016-03-01 13:11:28 -08001217
Dimitry Ivanov35c8e3b2017-02-27 12:17:47 -08001218 // do not print this if a library is in the list of shared libraries for linked namespaces
1219 if (!maybe_accessible_via_namespace_links(ns, name)) {
1220 PRINT("library \"%s\" (\"%s\") needed or dlopened by \"%s\" is not accessible for the"
1221 " namespace: [name=\"%s\", ld_library_paths=\"%s\", default_library_paths=\"%s\","
1222 " permitted_paths=\"%s\"]",
1223 name, realpath.c_str(),
1224 needed_or_dlopened_by,
1225 ns->get_name(),
1226 android::base::Join(ns->get_ld_library_paths(), ':').c_str(),
1227 android::base::Join(ns->get_default_library_paths(), ':').c_str(),
1228 android::base::Join(ns->get_permitted_paths(), ':').c_str());
1229 }
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001230 return false;
1231 }
Dimitry Ivanov22840aa2015-12-04 18:28:49 -08001232 }
1233
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001234 soinfo* si = soinfo_alloc(ns, realpath.c_str(), &file_stat, file_offset, rtld_flags);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001235 if (si == nullptr) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001236 return false;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001237 }
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07001238
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001239 task->set_soinfo(si);
1240
1241 // Read the ELF header and some of the segments.
1242 if (!task->read(realpath.c_str(), file_stat.st_size)) {
Dmitriy Ivanovfd7a91e2015-11-06 10:44:37 -08001243 soinfo_free(si);
1244 task->set_soinfo(nullptr);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001245 return false;
1246 }
1247
1248 // find and set DT_RUNPATH and dt_soname
1249 // Note that these field values are temporary and are
1250 // going to be overwritten on soinfo::prelink_image
1251 // with values from PT_LOAD segments.
1252 const ElfReader& elf_reader = task->get_elf_reader();
1253 for (const ElfW(Dyn)* d = elf_reader.dynamic(); d->d_tag != DT_NULL; ++d) {
1254 if (d->d_tag == DT_RUNPATH) {
1255 si->set_dt_runpath(elf_reader.get_string(d->d_un.d_val));
1256 }
1257 if (d->d_tag == DT_SONAME) {
1258 si->set_soname(elf_reader.get_string(d->d_un.d_val));
1259 }
1260 }
1261
1262 for_each_dt_needed(task->get_elf_reader(), [&](const char* name) {
1263 load_tasks->push_back(LoadTask::create(name, si, task->get_readers_map()));
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001264 });
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07001265
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001266 return true;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001267}
1268
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001269static bool load_library(android_namespace_t* ns,
1270 LoadTask* task,
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001271 ZipArchiveCache* zip_archive_cache,
1272 LoadTaskList* load_tasks,
Dimitry Ivanovd3e7d082017-03-27 14:11:02 -07001273 int rtld_flags,
1274 bool search_linked_namespaces) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001275 const char* name = task->get_name();
1276 soinfo* needed_by = task->get_needed_by();
1277 const android_dlextinfo* extinfo = task->get_extinfo();
1278
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001279 off64_t file_offset;
1280 std::string realpath;
Spencer Low0346ad72015-04-22 18:06:51 -07001281 if (extinfo != nullptr && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) {
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001282 file_offset = 0;
Spencer Low0346ad72015-04-22 18:06:51 -07001283 if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
1284 file_offset = extinfo->library_fd_offset;
1285 }
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001286
1287 if (!realpath_fd(extinfo->library_fd, &realpath)) {
1288 PRINT("warning: unable to get realpath for the library \"%s\" by extinfo->library_fd. "
1289 "Will use given name.", name);
1290 realpath = name;
1291 }
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001292
1293 task->set_fd(extinfo->library_fd, false);
1294 task->set_file_offset(file_offset);
Dimitry Ivanovd3e7d082017-03-27 14:11:02 -07001295 return load_library(ns, task, load_tasks, rtld_flags, realpath, search_linked_namespaces);
Spencer Low0346ad72015-04-22 18:06:51 -07001296 }
1297
1298 // Open the file.
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001299 int fd = open_library(ns, zip_archive_cache, name, needed_by, &file_offset, &realpath);
Spencer Low0346ad72015-04-22 18:06:51 -07001300 if (fd == -1) {
1301 DL_ERR("library \"%s\" not found", name);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001302 return false;
Spencer Low0346ad72015-04-22 18:06:51 -07001303 }
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001304
1305 task->set_fd(fd, true);
1306 task->set_file_offset(file_offset);
1307
Dimitry Ivanovd3e7d082017-03-27 14:11:02 -07001308 return load_library(ns, task, load_tasks, rtld_flags, realpath, search_linked_namespaces);
Spencer Low0346ad72015-04-22 18:06:51 -07001309}
1310
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001311static bool find_loaded_library_by_soname(android_namespace_t* ns,
Dimitry Ivanovd3e7d082017-03-27 14:11:02 -07001312 const char* name,
1313 soinfo** candidate) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001314 return !ns->soinfo_list().visit([&](soinfo* si) {
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07001315 const char* soname = si->get_soname();
1316 if (soname != nullptr && (strcmp(name, soname) == 0)) {
Dimitry Ivanov3bd90612017-02-01 08:54:43 -08001317 *candidate = si;
1318 return false;
Ard Biesheuvel12c78bb2012-08-14 12:30:09 +02001319 }
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001320
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001321 return true;
1322 });
Ard Biesheuvel12c78bb2012-08-14 12:30:09 +02001323}
1324
Dimitry Ivanovd3e7d082017-03-27 14:11:02 -07001325// Returns true if library was found and false otherwise
1326static bool find_loaded_library_by_soname(android_namespace_t* ns,
1327 const char* name,
1328 bool search_linked_namespaces,
1329 soinfo** candidate) {
1330 *candidate = nullptr;
1331
1332 // Ignore filename with path.
1333 if (strchr(name, '/') != nullptr) {
1334 return false;
1335 }
1336
1337 bool found = find_loaded_library_by_soname(ns, name, candidate);
1338
1339 if (!found && search_linked_namespaces) {
1340 // if a library was not found - look into linked namespaces
1341 for (auto& link : ns->linked_namespaces()) {
1342 if (!link.is_accessible(name)) {
1343 continue;
1344 }
1345
1346 android_namespace_t* linked_ns = link.linked_namespace();
1347
1348 if (find_loaded_library_by_soname(linked_ns, name, candidate)) {
1349 return true;
1350 }
1351 }
1352 }
1353
1354 return found;
1355}
1356
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001357static bool find_library_in_linked_namespace(const android_namespace_link_t& namespace_link,
1358 LoadTask* task,
1359 int rtld_flags) {
1360 android_namespace_t* ns = namespace_link.linked_namespace();
1361
1362 soinfo* candidate;
1363 bool loaded = false;
1364
1365 std::string soname;
Dimitry Ivanovd3e7d082017-03-27 14:11:02 -07001366 if (find_loaded_library_by_soname(ns, task->get_name(), false, &candidate)) {
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001367 loaded = true;
1368 soname = candidate->get_soname();
1369 } else {
1370 soname = resolve_soname(task->get_name());
1371 }
1372
1373 if (!namespace_link.is_accessible(soname.c_str())) {
1374 // the library is not accessible via namespace_link
1375 return false;
1376 }
1377
1378 // if library is already loaded - return it
1379 if (loaded) {
1380 task->set_soinfo(candidate);
1381 return true;
1382 }
1383
1384 // try to load the library - once namespace boundary is crossed
1385 // we need to load a library within separate load_group
1386 // to avoid using symbols from foreign namespace while.
1387 //
1388 // All symbols during relocation should be resolved within a
1389 // namespace to preserve library locality to a namespace.
1390 const char* name = task->get_name();
1391 if (find_libraries(ns,
1392 task->get_needed_by(),
1393 &name,
1394 1,
1395 &candidate,
1396 nullptr /* ld_preloads */,
1397 0 /* ld_preload_count*/,
1398 rtld_flags,
1399 nullptr /* extinfo*/,
1400 false /* add_as_children */,
1401 false /* search_linked_namespaces */)) {
1402 task->set_soinfo(candidate);
1403 return true;
1404 }
1405
1406 return false;
1407}
1408
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001409static bool find_library_internal(android_namespace_t* ns,
1410 LoadTask* task,
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001411 ZipArchiveCache* zip_archive_cache,
1412 LoadTaskList* load_tasks,
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001413 int rtld_flags,
1414 bool search_linked_namespaces) {
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001415 soinfo* candidate;
1416
Dimitry Ivanovd3e7d082017-03-27 14:11:02 -07001417 if (find_loaded_library_by_soname(ns, task->get_name(), search_linked_namespaces, &candidate)) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001418 task->set_soinfo(candidate);
1419 return true;
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001420 }
Dmitriy Ivanovb648a8a2014-05-19 15:06:58 -07001421
1422 // Library might still be loaded, the accurate detection
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001423 // of this fact is done by load_library.
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001424 TRACE("[ \"%s\" find_loaded_library_by_soname failed (*candidate=%s@%p). Trying harder...]",
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001425 task->get_name(), candidate == nullptr ? "n/a" : candidate->get_realpath(), candidate);
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001426
Dimitry Ivanovd3e7d082017-03-27 14:11:02 -07001427 if (load_library(ns, task, zip_archive_cache, load_tasks, rtld_flags, search_linked_namespaces)) {
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001428 return true;
1429 }
1430
1431 if (search_linked_namespaces) {
1432 // if a library was not found - look into linked namespaces
1433 for (auto& linked_namespace : ns->linked_namespaces()) {
1434 if (find_library_in_linked_namespace(linked_namespace,
1435 task,
1436 rtld_flags)) {
1437 return true;
1438 }
1439 }
1440 }
1441
1442 return false;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001443}
1444
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001445static void soinfo_unload(soinfo* si);
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001446static void soinfo_unload(soinfo* soinfos[], size_t count);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001447
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001448// TODO: this is slightly unusual way to construct
1449// the global group for relocation. Not every RTLD_GLOBAL
1450// library is included in this group for backwards-compatibility
1451// reasons.
1452//
1453// This group consists of the main executable, LD_PRELOADs
1454// and libraries with the DF_1_GLOBAL flag set.
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001455static soinfo_list_t make_global_group(android_namespace_t* ns) {
1456 soinfo_list_t global_group;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001457 ns->soinfo_list().for_each([&](soinfo* si) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001458 if ((si->get_dt_flags_1() & DF_1_GLOBAL) != 0) {
1459 global_group.push_back(si);
1460 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001461 });
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001462
1463 return global_group;
1464}
1465
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07001466// This function provides a list of libraries to be shared
1467// by the namespace. For the default namespace this is the global
1468// group (see make_global_group). For all others this is a group
1469// of RTLD_GLOBAL libraries (which includes the global group from
1470// the default namespace).
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001471static soinfo_list_t get_shared_group(android_namespace_t* ns) {
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07001472 if (ns == &g_default_namespace) {
1473 return make_global_group(ns);
1474 }
1475
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001476 soinfo_list_t shared_group;
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07001477 ns->soinfo_list().for_each([&](soinfo* si) {
1478 if ((si->get_rtld_flags() & RTLD_GLOBAL) != 0) {
1479 shared_group.push_back(si);
1480 }
1481 });
1482
1483 return shared_group;
1484}
1485
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001486static void shuffle(std::vector<LoadTask*>* v) {
1487 for (size_t i = 0, size = v->size(); i < size; ++i) {
1488 size_t n = size - i;
1489 size_t r = arc4random_uniform(n);
1490 std::swap((*v)[n-1], (*v)[r]);
1491 }
1492}
1493
Evgenii Stepanov0cdef7e2015-07-06 17:56:31 -07001494// add_as_children - add first-level loaded libraries (i.e. library_names[], but
1495// not their transitive dependencies) as children of the start_with library.
1496// This is false when find_libraries is called for dlopen(), when newly loaded
1497// libraries must form a disjoint tree.
Dimitry Ivanov3f660572016-09-09 10:00:39 -07001498bool find_libraries(android_namespace_t* ns,
1499 soinfo* start_with,
1500 const char* const library_names[],
1501 size_t library_names_count,
1502 soinfo* soinfos[],
1503 std::vector<soinfo*>* ld_preloads,
1504 size_t ld_preloads_count,
1505 int rtld_flags,
1506 const android_dlextinfo* extinfo,
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001507 bool add_as_children,
1508 bool search_linked_namespaces) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001509 // Step 0: prepare.
1510 LoadTaskList load_tasks;
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001511 std::unordered_map<const soinfo*, ElfReader> readers_map;
1512
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001513 for (size_t i = 0; i < library_names_count; ++i) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001514 const char* name = library_names[i];
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001515 load_tasks.push_back(LoadTask::create(name, start_with, &readers_map));
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001516 }
1517
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001518 // Construct global_group.
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001519 soinfo_list_t global_group = make_global_group(ns);
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001520
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001521 // If soinfos array is null allocate one on stack.
1522 // The array is needed in case of failure; for example
1523 // when library_names[] = {libone.so, libtwo.so} and libone.so
1524 // is loaded correctly but libtwo.so failed for some reason.
1525 // In this case libone.so should be unloaded on return.
1526 // See also implementation of failure_guard below.
1527
1528 if (soinfos == nullptr) {
1529 size_t soinfos_size = sizeof(soinfo*)*library_names_count;
1530 soinfos = reinterpret_cast<soinfo**>(alloca(soinfos_size));
1531 memset(soinfos, 0, soinfos_size);
1532 }
1533
1534 // list of libraries to link - see step 2.
1535 size_t soinfos_count = 0;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001536
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001537 auto scope_guard = make_scope_guard([&]() {
1538 for (LoadTask* t : load_tasks) {
1539 LoadTask::deleter(t);
1540 }
1541 });
1542
Dmitriy Ivanovd9ff7222014-09-08 16:22:22 -07001543 auto failure_guard = make_scope_guard([&]() {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001544 // Housekeeping
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001545 soinfo_unload(soinfos, soinfos_count);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001546 });
1547
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001548 ZipArchiveCache zip_archive_cache;
1549
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001550 // Step 1: expand the list of load_tasks to include
1551 // all DT_NEEDED libraries (do not load them just yet)
1552 for (size_t i = 0; i<load_tasks.size(); ++i) {
1553 LoadTask* task = load_tasks[i];
Evgenii Stepanov68650822015-06-10 13:38:39 -07001554 soinfo* needed_by = task->get_needed_by();
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001555
Dmitriy Ivanovedfc9f62015-09-02 16:32:02 -07001556 bool is_dt_needed = needed_by != nullptr && (needed_by != start_with || add_as_children);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001557 task->set_extinfo(is_dt_needed ? nullptr : extinfo);
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001558 task->set_dt_needed(is_dt_needed);
Dmitriy Ivanovedfc9f62015-09-02 16:32:02 -07001559
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001560 if (!find_library_internal(ns,
1561 task,
1562 &zip_archive_cache,
1563 &load_tasks,
1564 rtld_flags,
1565 search_linked_namespaces || is_dt_needed)) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001566 return false;
1567 }
1568
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001569 soinfo* si = task->get_soinfo();
1570
Dmitriy Ivanovedfc9f62015-09-02 16:32:02 -07001571 if (is_dt_needed) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001572 needed_by->add_child(si);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001573
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001574 if (si->is_linked()) {
1575 si->increment_ref_count();
1576 }
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001577 }
1578
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001579 // When ld_preloads is not null, the first
1580 // ld_preloads_count libs are in fact ld_preloads.
1581 if (ld_preloads != nullptr && soinfos_count < ld_preloads_count) {
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07001582 ld_preloads->push_back(si);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001583 }
1584
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001585 if (soinfos_count < library_names_count) {
1586 soinfos[soinfos_count++] = si;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001587 }
1588 }
1589
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001590 // Step 2: Load libraries in random order (see b/24047022)
1591 LoadTaskList load_list;
1592 for (auto&& task : load_tasks) {
1593 soinfo* si = task->get_soinfo();
1594 auto pred = [&](const LoadTask* t) {
1595 return t->get_soinfo() == si;
1596 };
1597
1598 if (!si->is_linked() &&
1599 std::find_if(load_list.begin(), load_list.end(), pred) == load_list.end() ) {
1600 load_list.push_back(task);
1601 }
1602 }
1603 shuffle(&load_list);
1604
1605 for (auto&& task : load_list) {
1606 if (!task->load()) {
1607 return false;
1608 }
1609 }
1610
1611 // Step 3: pre-link all DT_NEEDED libraries in breadth first order.
1612 for (auto&& task : load_tasks) {
1613 soinfo* si = task->get_soinfo();
1614 if (!si->is_linked() && !si->prelink_image()) {
1615 return false;
1616 }
1617 }
1618
1619 // Step 4: Add LD_PRELOADed libraries to the global group for
1620 // future runs. There is no need to explicitly add them to
1621 // the global group for this run because they are going to
1622 // appear in the local group in the correct order.
1623 if (ld_preloads != nullptr) {
1624 for (auto&& si : *ld_preloads) {
1625 si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL);
1626 }
1627 }
1628
1629
1630 // Step 5: link libraries.
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001631 soinfo_list_t local_group;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001632 walk_dependencies_tree(
Evgenii Stepanov0cdef7e2015-07-06 17:56:31 -07001633 (start_with != nullptr && add_as_children) ? &start_with : soinfos,
1634 (start_with != nullptr && add_as_children) ? 1 : soinfos_count,
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001635 [&] (soinfo* si) {
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -08001636 if (ns->is_accessible(si)) {
1637 local_group.push_back(si);
1638 return kWalkContinue;
1639 } else {
1640 return kWalkSkip;
1641 }
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001642 });
1643
1644 bool linked = local_group.visit([&](soinfo* si) {
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001645 if (!si->is_linked()) {
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -07001646 if (!si->link_image(global_group, local_group, extinfo) ||
1647 !get_cfi_shadow()->AfterLoad(si, solist_get_head())) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001648 return false;
1649 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001650 }
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001651
1652 return true;
1653 });
1654
1655 if (linked) {
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001656 local_group.for_each([](soinfo* si) {
1657 if (!si->is_linked()) {
1658 si->set_linked();
1659 }
1660 });
1661
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001662 failure_guard.disable();
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001663 }
1664
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001665 return linked;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001666}
1667
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001668static soinfo* find_library(android_namespace_t* ns,
1669 const char* name, int rtld_flags,
Evgenii Stepanov0cdef7e2015-07-06 17:56:31 -07001670 const android_dlextinfo* extinfo,
1671 soinfo* needed_by) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001672 soinfo* si;
1673
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001674 if (name == nullptr) {
Dimitry Ivanov3f660572016-09-09 10:00:39 -07001675 si = solist_get_somain();
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001676 } else if (!find_libraries(ns,
1677 needed_by,
1678 &name,
1679 1,
1680 &si,
1681 nullptr,
1682 0,
1683 rtld_flags,
1684 extinfo,
1685 false /* add_as_children */,
1686 true /* search_linked_namespaces */)) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001687 return nullptr;
1688 }
1689
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001690 si->increment_ref_count();
1691
Elliott Hughesd23736e2012-11-01 15:16:56 -07001692 return si;
1693}
Elliott Hughesbedfe382012-08-14 14:07:59 -07001694
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001695static void soinfo_unload(soinfo* root) {
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001696 if (root->is_linked()) {
1697 root = root->get_local_group_root();
1698 }
1699
Dimitry Ivanov6705e8c2017-03-21 10:29:06 -07001700 ScopedTrace trace((std::string("unload ") + root->get_realpath()).c_str());
1701
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001702 if (!root->can_unload()) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001703 TRACE("not unloading \"%s\" - the binary is flagged with NODELETE", root->get_realpath());
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -07001704 return;
1705 }
1706
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001707 soinfo_unload(&root, 1);
1708}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001709
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001710static void soinfo_unload(soinfo* soinfos[], size_t count) {
1711 // Note that the library can be loaded but not linked;
1712 // in which case there is no root but we still need
1713 // to walk the tree and unload soinfos involved.
1714 //
1715 // This happens on unsuccessful dlopen, when one of
1716 // the DT_NEEDED libraries could not be linked/found.
1717 if (count == 0) {
1718 return;
1719 }
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001720
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001721 soinfo_list_t unload_list;
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001722 for (size_t i = 0; i < count; ++i) {
1723 soinfo* si = soinfos[i];
Dmitriy Ivanov5ae82cb2014-12-02 17:08:42 -08001724
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001725 if (si->can_unload()) {
1726 size_t ref_count = si->is_linked() ? si->decrement_ref_count() : 0;
1727 if (ref_count == 0) {
1728 unload_list.push_back(si);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001729 } else {
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001730 TRACE("not unloading '%s' group, decrementing ref_count to %zd",
1731 si->get_realpath(), ref_count);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001732 }
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001733 } else {
1734 TRACE("not unloading '%s' - the binary is flagged with NODELETE", si->get_realpath());
1735 return;
1736 }
1737 }
1738
1739 // This is used to identify soinfos outside of the load-group
1740 // note that we cannot have > 1 in the array and have any of them
1741 // linked. This is why we can safely use the first one.
1742 soinfo* root = soinfos[0];
1743
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001744 soinfo_list_t local_unload_list;
1745 soinfo_list_t external_unload_list;
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001746 soinfo* si = nullptr;
1747
1748 while ((si = unload_list.pop_front()) != nullptr) {
1749 if (local_unload_list.contains(si)) {
1750 continue;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001751 }
Elliott Hughesd23736e2012-11-01 15:16:56 -07001752
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001753 local_unload_list.push_back(si);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001754
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001755 if (si->has_min_version(0)) {
1756 soinfo* child = nullptr;
1757 while ((child = si->get_children().pop_front()) != nullptr) {
1758 TRACE("%s@%p needs to unload %s@%p", si->get_realpath(), si,
1759 child->get_realpath(), child);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001760
Dimitry Ivanovec90e242017-02-10 11:04:20 -08001761 child->get_parents().remove(si);
1762
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001763 if (local_unload_list.contains(child)) {
1764 continue;
1765 } else if (child->is_linked() && child->get_local_group_root() != root) {
1766 external_unload_list.push_back(child);
Dimitry Ivanovec90e242017-02-10 11:04:20 -08001767 } else if (child->get_parents().empty()) {
1768 unload_list.push_back(child);
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001769 }
1770 }
1771 } else {
1772#if !defined(__work_around_b_24465209__)
1773 __libc_fatal("soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
1774#else
1775 PRINT("warning: soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
1776 for_each_dt_needed(si, [&] (const char* library_name) {
1777 TRACE("deprecated (old format of soinfo): %s needs to unload %s",
1778 si->get_realpath(), library_name);
1779
1780 soinfo* needed = find_library(si->get_primary_namespace(),
1781 library_name, RTLD_NOLOAD, nullptr, nullptr);
1782
1783 if (needed != nullptr) {
1784 // Not found: for example if symlink was deleted between dlopen and dlclose
1785 // Since we cannot really handle errors at this point - print and continue.
1786 PRINT("warning: couldn't find %s needed by %s on unload.",
1787 library_name, si->get_realpath());
1788 return;
1789 } else if (local_unload_list.contains(needed)) {
1790 // already visited
1791 return;
1792 } else if (needed->is_linked() && needed->get_local_group_root() != root) {
1793 // external group
1794 external_unload_list.push_back(needed);
1795 } else {
1796 // local group
1797 unload_list.push_front(needed);
1798 }
1799 });
1800#endif
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001801 }
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001802 }
1803
1804 local_unload_list.for_each([](soinfo* si) {
1805 si->call_destructors();
1806 });
1807
1808 while ((si = local_unload_list.pop_front()) != nullptr) {
1809 notify_gdb_of_unload(si);
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -07001810 get_cfi_shadow()->BeforeUnload(si);
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001811 soinfo_free(si);
1812 }
1813
1814 while ((si = external_unload_list.pop_front()) != nullptr) {
1815 soinfo_unload(si);
Dmitriy Ivanova2547052014-11-18 12:03:09 -08001816 }
1817}
1818
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001819static std::string symbol_display_name(const char* sym_name, const char* sym_ver) {
1820 if (sym_ver == nullptr) {
1821 return sym_name;
1822 }
1823
Dimitry Ivanov9cf99cb2015-12-11 14:22:24 -08001824 return std::string(sym_name) + ", version " + sym_ver;
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001825}
1826
Dimitry Ivanovaca299a2016-04-11 12:42:58 -07001827static android_namespace_t* get_caller_namespace(soinfo* caller) {
1828 return caller != nullptr ? caller->get_primary_namespace() : g_anonymous_namespace;
1829}
1830
Elliott Hughesa4aafd12014-01-13 16:37:47 -08001831void do_android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size) {
Christopher Ferris052fa3a2014-08-26 20:48:11 -07001832 // Use basic string manipulation calls to avoid snprintf.
1833 // snprintf indirectly calls pthread_getspecific to get the size of a buffer.
1834 // When debug malloc is enabled, this call returns 0. This in turn causes
1835 // snprintf to do nothing, which causes libraries to fail to load.
1836 // See b/17302493 for further details.
1837 // Once the above bug is fixed, this code can be modified to use
1838 // snprintf again.
Dimitry Ivanov77ad6422017-03-06 13:02:29 -08001839 const auto& default_ld_paths = g_default_namespace.get_default_library_paths();
1840
1841 size_t required_size = 0;
1842 for (const auto& path : default_ld_paths) {
1843 required_size += path.size() + 1;
Evgenii Stepanovd640b222015-07-10 17:54:01 -07001844 }
Dimitry Ivanov77ad6422017-03-06 13:02:29 -08001845
1846 if (buffer_size < required_size) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07001847 __libc_fatal("android_get_LD_LIBRARY_PATH failed, buffer too small: "
Dimitry Ivanov77ad6422017-03-06 13:02:29 -08001848 "buffer len %zu, required len %zu", buffer_size, required_size);
Christopher Ferris052fa3a2014-08-26 20:48:11 -07001849 }
Dimitry Ivanov77ad6422017-03-06 13:02:29 -08001850
Evgenii Stepanovd640b222015-07-10 17:54:01 -07001851 char* end = buffer;
Dimitry Ivanov77ad6422017-03-06 13:02:29 -08001852 for (size_t i = 0; i < default_ld_paths.size(); ++i) {
Evgenii Stepanovd640b222015-07-10 17:54:01 -07001853 if (i > 0) *end++ = ':';
Dimitry Ivanov77ad6422017-03-06 13:02:29 -08001854 end = stpcpy(end, default_ld_paths[i].c_str());
Evgenii Stepanovd640b222015-07-10 17:54:01 -07001855 }
Elliott Hughesa4aafd12014-01-13 16:37:47 -08001856}
1857
Elliott Hughescade4c32012-12-20 14:42:14 -08001858void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path) {
Nick Kralevich6bb01b62015-03-07 13:37:05 -08001859 parse_LD_LIBRARY_PATH(ld_library_path);
Elliott Hughescade4c32012-12-20 14:42:14 -08001860}
1861
Dimitry Ivanovb996d602016-07-11 18:11:39 -07001862static std::string android_dlextinfo_to_string(const android_dlextinfo* info) {
1863 if (info == nullptr) {
1864 return "(null)";
1865 }
1866
1867 return android::base::StringPrintf("[flags=0x%" PRIx64 ","
1868 " reserved_addr=%p,"
1869 " reserved_size=0x%zx,"
1870 " relro_fd=%d,"
1871 " library_fd=%d,"
1872 " library_fd_offset=0x%" PRIx64 ","
1873 " library_namespace=%s@%p]",
1874 info->flags,
1875 info->reserved_addr,
1876 info->reserved_size,
1877 info->relro_fd,
1878 info->library_fd,
1879 info->library_fd_offset,
1880 (info->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0 ?
1881 (info->library_namespace != nullptr ?
1882 info->library_namespace->get_name() : "(null)") : "(n/a)",
1883 (info->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0 ?
1884 info->library_namespace : nullptr);
1885}
1886
Dimitry Ivanovd9e427c2016-11-22 16:55:25 -08001887void* do_dlopen(const char* name, int flags,
1888 const android_dlextinfo* extinfo,
1889 const void* caller_addr) {
Dimitry Ivanov5c4a5802017-03-17 16:41:34 -07001890 std::string trace_prefix = std::string("dlopen: ") + (name == nullptr ? "(nullptr)" : name);
1891 ScopedTrace trace(trace_prefix.c_str());
1892 ScopedTrace loading_trace((trace_prefix + " - loading and linking").c_str());
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001893 soinfo* const caller = find_containing_library(caller_addr);
Dimitry Ivanovb996d602016-07-11 18:11:39 -07001894 android_namespace_t* ns = get_caller_namespace(caller);
1895
1896 LD_LOG(kLogDlopen,
1897 "dlopen(name=\"%s\", flags=0x%x, extinfo=%s, caller=\"%s\", caller_ns=%s@%p) ...",
1898 name,
1899 flags,
1900 android_dlextinfo_to_string(extinfo).c_str(),
1901 caller == nullptr ? "(null)" : caller->get_realpath(),
1902 ns == nullptr ? "(null)" : ns->get_name(),
1903 ns);
1904
1905 auto failure_guard = make_scope_guard([&]() {
1906 LD_LOG(kLogDlopen, "... dlopen failed: %s", linker_get_error_buffer());
1907 });
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001908
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -07001909 if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL|RTLD_NODELETE|RTLD_NOLOAD)) != 0) {
Elliott Hughese66190d2012-12-18 15:57:55 -08001910 DL_ERR("invalid flags to dlopen: %x", flags);
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07001911 return nullptr;
Elliott Hughese66190d2012-12-18 15:57:55 -08001912 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001913
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001914 if (extinfo != nullptr) {
1915 if ((extinfo->flags & ~(ANDROID_DLEXT_VALID_FLAG_BITS)) != 0) {
1916 DL_ERR("invalid extended flags to android_dlopen_ext: 0x%" PRIx64, extinfo->flags);
1917 return nullptr;
1918 }
Dmitriy Ivanov126af752015-10-07 16:34:20 -07001919
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001920 if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) == 0 &&
Dmitriy Ivanova6c12792014-10-21 12:09:18 -07001921 (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07001922 DL_ERR("invalid extended flag combination (ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET without "
1923 "ANDROID_DLEXT_USE_LIBRARY_FD): 0x%" PRIx64, extinfo->flags);
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001924 return nullptr;
1925 }
Dmitriy Ivanov126af752015-10-07 16:34:20 -07001926
1927 if ((extinfo->flags & ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS) != 0 &&
1928 (extinfo->flags & (ANDROID_DLEXT_RESERVED_ADDRESS | ANDROID_DLEXT_RESERVED_ADDRESS_HINT)) != 0) {
1929 DL_ERR("invalid extended flag combination: ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS is not "
1930 "compatible with ANDROID_DLEXT_RESERVED_ADDRESS/ANDROID_DLEXT_RESERVED_ADDRESS_HINT");
1931 return nullptr;
1932 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001933
1934 if ((extinfo->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0) {
1935 if (extinfo->library_namespace == nullptr) {
1936 DL_ERR("ANDROID_DLEXT_USE_NAMESPACE is set but extinfo->library_namespace is null");
1937 return nullptr;
1938 }
1939 ns = extinfo->library_namespace;
1940 }
Torne (Richard Coles)012cb452014-02-06 14:34:21 +00001941 }
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -08001942
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -07001943 std::string asan_name_holder;
1944
1945 const char* translated_name = name;
Dimitry Ivanov6c14f862016-12-05 13:35:47 -08001946 if (g_is_asan && translated_name != nullptr && translated_name[0] == '/') {
1947 char translated_path[PATH_MAX];
1948 if (realpath(translated_name, translated_path) != nullptr) {
Evgenii Stepanov5b715002016-10-03 15:09:28 -07001949 if (file_is_under_dir(translated_path, kSystemLibDir)) {
1950 asan_name_holder = std::string(kAsanSystemLibDir) + "/" +
1951 (translated_path + strlen(kSystemLibDir) + 1);
Dimitry Ivanov6c14f862016-12-05 13:35:47 -08001952 if (file_exists(asan_name_holder.c_str())) {
1953 translated_name = asan_name_holder.c_str();
1954 PRINT("linker_asan dlopen translating \"%s\" -> \"%s\"", name, translated_name);
1955 }
Evgenii Stepanov5b715002016-10-03 15:09:28 -07001956 } else if (file_is_under_dir(translated_path, kVendorLibDir)) {
1957 asan_name_holder = std::string(kAsanVendorLibDir) + "/" +
1958 (translated_path + strlen(kVendorLibDir) + 1);
Dimitry Ivanov6c14f862016-12-05 13:35:47 -08001959 if (file_exists(asan_name_holder.c_str())) {
1960 translated_name = asan_name_holder.c_str();
1961 PRINT("linker_asan dlopen translating \"%s\" -> \"%s\"", name, translated_name);
1962 }
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -07001963 }
1964 }
1965 }
1966
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -08001967 ProtectedDataGuard guard;
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -07001968 soinfo* si = find_library(ns, translated_name, flags, extinfo, caller);
Dimitry Ivanov5c4a5802017-03-17 16:41:34 -07001969 loading_trace.End();
1970
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07001971 if (si != nullptr) {
Dimitry Ivanovb996d602016-07-11 18:11:39 -07001972 void* handle = si->to_handle();
1973 LD_LOG(kLogDlopen,
Dimitry Ivanovae4a0c12016-11-21 10:44:35 -08001974 "... dlopen calling constructors: realpath=\"%s\", soname=\"%s\", handle=%p",
1975 si->get_realpath(), si->get_soname(), handle);
1976 si->call_constructors();
1977 failure_guard.disable();
1978 LD_LOG(kLogDlopen,
Dimitry Ivanovb996d602016-07-11 18:11:39 -07001979 "... dlopen successful: realpath=\"%s\", soname=\"%s\", handle=%p",
1980 si->get_realpath(), si->get_soname(), handle);
1981 return handle;
Elliott Hughesd23736e2012-11-01 15:16:56 -07001982 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001983
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001984 return nullptr;
Elliott Hughesd23736e2012-11-01 15:16:56 -07001985}
1986
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001987int do_dladdr(const void* addr, Dl_info* info) {
1988 // Determine if this address can be found in any library currently mapped.
1989 soinfo* si = find_containing_library(addr);
1990 if (si == nullptr) {
1991 return 0;
1992 }
1993
1994 memset(info, 0, sizeof(Dl_info));
1995
1996 info->dli_fname = si->get_realpath();
1997 // Address at which the shared object is loaded.
1998 info->dli_fbase = reinterpret_cast<void*>(si->base);
1999
2000 // Determine if any symbol in the library contains the specified address.
2001 ElfW(Sym)* sym = si->find_symbol_by_address(addr);
2002 if (sym != nullptr) {
2003 info->dli_sname = si->get_string(sym->st_name);
2004 info->dli_saddr = reinterpret_cast<void*>(si->resolve_symbol_address(sym));
2005 }
2006
2007 return 1;
2008}
2009
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07002010static soinfo* soinfo_from_handle(void* handle) {
2011 if ((reinterpret_cast<uintptr_t>(handle) & 1) != 0) {
2012 auto it = g_soinfo_handles_map.find(reinterpret_cast<uintptr_t>(handle));
2013 if (it == g_soinfo_handles_map.end()) {
2014 return nullptr;
2015 } else {
2016 return it->second;
2017 }
2018 }
2019
2020 return static_cast<soinfo*>(handle);
2021}
2022
Dimitry Ivanovd9e427c2016-11-22 16:55:25 -08002023bool do_dlsym(void* handle,
2024 const char* sym_name,
2025 const char* sym_ver,
2026 const void* caller_addr,
2027 void** symbol) {
Dimitry Ivanov6705e8c2017-03-21 10:29:06 -07002028 ScopedTrace trace("dlsym");
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08002029#if !defined(__LP64__)
2030 if (handle == nullptr) {
2031 DL_ERR("dlsym failed: library handle is null");
2032 return false;
2033 }
2034#endif
2035
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08002036 soinfo* found = nullptr;
2037 const ElfW(Sym)* sym = nullptr;
2038 soinfo* caller = find_containing_library(caller_addr);
Dimitry Ivanovaca299a2016-04-11 12:42:58 -07002039 android_namespace_t* ns = get_caller_namespace(caller);
Dimitry Ivanov4742abd2016-12-12 16:30:15 -08002040 soinfo* si = nullptr;
2041 if (handle != RTLD_DEFAULT && handle != RTLD_NEXT) {
2042 si = soinfo_from_handle(handle);
2043 }
2044
2045 LD_LOG(kLogDlsym,
2046 "dlsym(handle=%p(\"%s\"), sym_name=\"%s\", sym_ver=\"%s\", caller=\"%s\", caller_ns=%s@%p) ...",
2047 handle,
2048 si != nullptr ? si->get_realpath() : "n/a",
2049 sym_name,
2050 sym_ver,
2051 caller == nullptr ? "(null)" : caller->get_realpath(),
2052 ns == nullptr ? "(null)" : ns->get_name(),
2053 ns);
2054
2055 auto failure_guard = make_scope_guard([&]() {
2056 LD_LOG(kLogDlsym, "... dlsym failed: %s", linker_get_error_buffer());
2057 });
2058
2059 if (sym_name == nullptr) {
2060 DL_ERR("dlsym failed: symbol name is null");
2061 return false;
2062 }
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08002063
2064 version_info vi_instance;
2065 version_info* vi = nullptr;
2066
2067 if (sym_ver != nullptr) {
Dimitry Ivanov9cf99cb2015-12-11 14:22:24 -08002068 vi_instance.name = sym_ver;
2069 vi_instance.elf_hash = calculate_elf_hash(sym_ver);
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08002070 vi = &vi_instance;
2071 }
2072
2073 if (handle == RTLD_DEFAULT || handle == RTLD_NEXT) {
2074 sym = dlsym_linear_lookup(ns, sym_name, vi, &found, caller, handle);
2075 } else {
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07002076 if (si == nullptr) {
2077 DL_ERR("dlsym failed: invalid handle: %p", handle);
2078 return false;
2079 }
2080 sym = dlsym_handle_lookup(si, &found, sym_name, vi);
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08002081 }
2082
2083 if (sym != nullptr) {
2084 uint32_t bind = ELF_ST_BIND(sym->st_info);
2085
2086 if ((bind == STB_GLOBAL || bind == STB_WEAK) && sym->st_shndx != 0) {
2087 *symbol = reinterpret_cast<void*>(found->resolve_symbol_address(sym));
Dimitry Ivanov4742abd2016-12-12 16:30:15 -08002088 failure_guard.disable();
2089 LD_LOG(kLogDlsym,
2090 "... dlsym successful: sym_name=\"%s\", sym_ver=\"%s\", found in=\"%s\", address=%p",
2091 sym_name, sym_ver, found->get_soname(), *symbol);
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08002092 return true;
2093 }
2094
2095 DL_ERR("symbol \"%s\" found but not global", symbol_display_name(sym_name, sym_ver).c_str());
2096 return false;
2097 }
2098
2099 DL_ERR("undefined symbol: %s", symbol_display_name(sym_name, sym_ver).c_str());
2100 return false;
2101}
2102
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07002103int do_dlclose(void* handle) {
Dimitry Ivanov6705e8c2017-03-21 10:29:06 -07002104 ScopedTrace trace("dlclose");
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -08002105 ProtectedDataGuard guard;
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07002106 soinfo* si = soinfo_from_handle(handle);
2107 if (si == nullptr) {
2108 DL_ERR("invalid handle: %p", handle);
2109 return -1;
2110 }
2111
Dmitriy Ivanovb648a8a2014-05-19 15:06:58 -07002112 soinfo_unload(si);
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07002113 return 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002114}
2115
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -08002116bool init_anonymous_namespace(const char* shared_lib_sonames, const char* library_search_path) {
2117 if (g_anonymous_namespace_initialized) {
2118 DL_ERR("anonymous namespace has already been initialized.");
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002119 return false;
2120 }
2121
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002122 ProtectedDataGuard guard;
2123
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002124 // create anonymous namespace
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002125 // When the caller is nullptr - create_namespace will take global group
2126 // from the anonymous namespace, which is fine because anonymous namespace
2127 // is still pointing to the default one.
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002128 android_namespace_t* anon_ns =
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -08002129 create_namespace(nullptr,
2130 "(anonymous)",
2131 nullptr,
2132 library_search_path,
Dimitry Ivanovc9dced22017-03-27 15:42:17 -07002133 ANDROID_NAMESPACE_TYPE_ISOLATED,
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -08002134 nullptr,
2135 &g_default_namespace);
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002136
2137 if (anon_ns == nullptr) {
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -08002138 return false;
2139 }
2140
2141 if (!link_namespaces(anon_ns, &g_default_namespace, shared_lib_sonames)) {
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002142 return false;
2143 }
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08002144
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002145 g_anonymous_namespace = anon_ns;
Dimitry Ivanov3e0821d2017-03-07 11:02:10 -08002146 g_anonymous_namespace_initialized = true;
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -08002147
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002148 return true;
2149}
2150
Dimitry Ivanovb943f302016-08-03 16:00:10 -07002151static void add_soinfos_to_namespace(const soinfo_list_t& soinfos, android_namespace_t* ns) {
2152 ns->add_soinfos(soinfos);
2153 for (auto si : soinfos) {
2154 si->add_secondary_namespace(ns);
2155 }
2156}
2157
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002158android_namespace_t* create_namespace(const void* caller_addr,
2159 const char* name,
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002160 const char* ld_library_path,
2161 const char* default_library_path,
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002162 uint64_t type,
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002163 const char* permitted_when_isolated_path,
2164 android_namespace_t* parent_namespace) {
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002165 if (parent_namespace == nullptr) {
Dimitry Ivanov52408632016-05-23 10:31:11 -07002166 // if parent_namespace is nullptr -> set it to the caller namespace
2167 soinfo* caller_soinfo = find_containing_library(caller_addr);
2168
2169 parent_namespace = caller_soinfo != nullptr ?
2170 caller_soinfo->get_primary_namespace() :
2171 g_anonymous_namespace;
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002172 }
2173
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002174 ProtectedDataGuard guard;
2175 std::vector<std::string> ld_library_paths;
2176 std::vector<std::string> default_library_paths;
Dimitry Ivanov284ae352015-12-08 10:47:13 -08002177 std::vector<std::string> permitted_paths;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002178
2179 parse_path(ld_library_path, ":", &ld_library_paths);
2180 parse_path(default_library_path, ":", &default_library_paths);
Dimitry Ivanov284ae352015-12-08 10:47:13 -08002181 parse_path(permitted_when_isolated_path, ":", &permitted_paths);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002182
2183 android_namespace_t* ns = new (g_namespace_allocator.alloc()) android_namespace_t();
2184 ns->set_name(name);
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002185 ns->set_isolated((type & ANDROID_NAMESPACE_TYPE_ISOLATED) != 0);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002186 ns->set_ld_library_paths(std::move(ld_library_paths));
2187 ns->set_default_library_paths(std::move(default_library_paths));
Dimitry Ivanov284ae352015-12-08 10:47:13 -08002188 ns->set_permitted_paths(std::move(permitted_paths));
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002189
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002190 if ((type & ANDROID_NAMESPACE_TYPE_SHARED) != 0) {
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002191 // If shared - clone the parent namespace
Dimitry Ivanovb943f302016-08-03 16:00:10 -07002192 add_soinfos_to_namespace(parent_namespace->soinfo_list(), ns);
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002193 } else {
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002194 // If not shared - copy only the shared group
Dimitry Ivanovb943f302016-08-03 16:00:10 -07002195 add_soinfos_to_namespace(get_shared_group(parent_namespace), ns);
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002196 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002197
2198 return ns;
2199}
2200
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -08002201bool link_namespaces(android_namespace_t* namespace_from,
2202 android_namespace_t* namespace_to,
2203 const char* shared_lib_sonames) {
2204 if (namespace_to == nullptr) {
2205 namespace_to = &g_default_namespace;
2206 }
2207
2208 if (namespace_from == nullptr) {
2209 DL_ERR("error linking namespaces: namespace_from is null.");
2210 return false;
2211 }
2212
2213 if (shared_lib_sonames == nullptr || shared_lib_sonames[0] == '\0') {
2214 DL_ERR("error linking namespaces \"%s\"->\"%s\": the list of shared libraries is empty.",
2215 namespace_from->get_name(), namespace_to->get_name());
2216 return false;
2217 }
2218
2219 auto sonames = android::base::Split(shared_lib_sonames, ":");
2220 std::unordered_set<std::string> sonames_set(sonames.begin(), sonames.end());
2221
2222 ProtectedDataGuard guard;
2223 namespace_from->add_linked_namespace(namespace_to, sonames_set);
2224
2225 return true;
2226}
2227
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002228ElfW(Addr) call_ifunc_resolver(ElfW(Addr) resolver_addr) {
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07002229 typedef ElfW(Addr) (*ifunc_resolver_t)(void);
2230 ifunc_resolver_t ifunc_resolver = reinterpret_cast<ifunc_resolver_t>(resolver_addr);
2231 ElfW(Addr) ifunc_addr = ifunc_resolver();
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002232 TRACE_TYPE(RELO, "Called ifunc_resolver@%p. The result is %p",
2233 ifunc_resolver, reinterpret_cast<void*>(ifunc_addr));
Brigid Smithc5a13ef2014-07-23 11:22:25 -07002234
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07002235 return ifunc_addr;
Brigid Smithc5a13ef2014-07-23 11:22:25 -07002236}
Brigid Smithc5a13ef2014-07-23 11:22:25 -07002237
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002238const version_info* VersionTracker::get_version_info(ElfW(Versym) source_symver) const {
2239 if (source_symver < 2 ||
2240 source_symver >= version_infos.size() ||
2241 version_infos[source_symver].name == nullptr) {
2242 return nullptr;
2243 }
2244
2245 return &version_infos[source_symver];
2246}
2247
2248void VersionTracker::add_version_info(size_t source_index,
2249 ElfW(Word) elf_hash,
2250 const char* ver_name,
2251 const soinfo* target_si) {
2252 if (source_index >= version_infos.size()) {
2253 version_infos.resize(source_index+1);
2254 }
2255
2256 version_infos[source_index].elf_hash = elf_hash;
2257 version_infos[source_index].name = ver_name;
2258 version_infos[source_index].target_si = target_si;
2259}
2260
2261bool VersionTracker::init_verneed(const soinfo* si_from) {
2262 uintptr_t verneed_ptr = si_from->get_verneed_ptr();
2263
2264 if (verneed_ptr == 0) {
2265 return true;
2266 }
2267
2268 size_t verneed_cnt = si_from->get_verneed_cnt();
2269
2270 for (size_t i = 0, offset = 0; i<verneed_cnt; ++i) {
2271 const ElfW(Verneed)* verneed = reinterpret_cast<ElfW(Verneed)*>(verneed_ptr + offset);
2272 size_t vernaux_offset = offset + verneed->vn_aux;
2273 offset += verneed->vn_next;
2274
2275 if (verneed->vn_version != 1) {
2276 DL_ERR("unsupported verneed[%zd] vn_version: %d (expected 1)", i, verneed->vn_version);
2277 return false;
2278 }
2279
2280 const char* target_soname = si_from->get_string(verneed->vn_file);
2281 // find it in dependencies
2282 soinfo* target_si = si_from->get_children().find_if([&](const soinfo* si) {
Dmitriy Ivanov406d9962015-05-06 11:05:27 -07002283 return si->get_soname() != nullptr && strcmp(si->get_soname(), target_soname) == 0;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002284 });
2285
2286 if (target_si == nullptr) {
2287 DL_ERR("cannot find \"%s\" from verneed[%zd] in DT_NEEDED list for \"%s\"",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002288 target_soname, i, si_from->get_realpath());
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002289 return false;
2290 }
2291
2292 for (size_t j = 0; j<verneed->vn_cnt; ++j) {
2293 const ElfW(Vernaux)* vernaux = reinterpret_cast<ElfW(Vernaux)*>(verneed_ptr + vernaux_offset);
2294 vernaux_offset += vernaux->vna_next;
2295
2296 const ElfW(Word) elf_hash = vernaux->vna_hash;
2297 const char* ver_name = si_from->get_string(vernaux->vna_name);
2298 ElfW(Half) source_index = vernaux->vna_other;
2299
2300 add_version_info(source_index, elf_hash, ver_name, target_si);
2301 }
2302 }
2303
2304 return true;
2305}
2306
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002307template <typename F>
2308static bool for_each_verdef(const soinfo* si, F functor) {
2309 if (!si->has_min_version(2)) {
2310 return true;
2311 }
2312
2313 uintptr_t verdef_ptr = si->get_verdef_ptr();
2314 if (verdef_ptr == 0) {
2315 return true;
2316 }
2317
2318 size_t offset = 0;
2319
2320 size_t verdef_cnt = si->get_verdef_cnt();
2321 for (size_t i = 0; i<verdef_cnt; ++i) {
2322 const ElfW(Verdef)* verdef = reinterpret_cast<ElfW(Verdef)*>(verdef_ptr + offset);
2323 size_t verdaux_offset = offset + verdef->vd_aux;
2324 offset += verdef->vd_next;
2325
2326 if (verdef->vd_version != 1) {
2327 DL_ERR("unsupported verdef[%zd] vd_version: %d (expected 1) library: %s",
2328 i, verdef->vd_version, si->get_realpath());
2329 return false;
2330 }
2331
2332 if ((verdef->vd_flags & VER_FLG_BASE) != 0) {
2333 // "this is the version of the file itself. It must not be used for
2334 // matching a symbol. It can be used to match references."
2335 //
2336 // http://www.akkadia.org/drepper/symbol-versioning
2337 continue;
2338 }
2339
2340 if (verdef->vd_cnt == 0) {
2341 DL_ERR("invalid verdef[%zd] vd_cnt == 0 (version without a name)", i);
2342 return false;
2343 }
2344
2345 const ElfW(Verdaux)* verdaux = reinterpret_cast<ElfW(Verdaux)*>(verdef_ptr + verdaux_offset);
2346
2347 if (functor(i, verdef, verdaux) == true) {
2348 break;
2349 }
2350 }
2351
2352 return true;
2353}
2354
2355bool find_verdef_version_index(const soinfo* si, const version_info* vi, ElfW(Versym)* versym) {
2356 if (vi == nullptr) {
2357 *versym = kVersymNotNeeded;
2358 return true;
2359 }
2360
2361 *versym = kVersymGlobal;
2362
2363 return for_each_verdef(si,
2364 [&](size_t, const ElfW(Verdef)* verdef, const ElfW(Verdaux)* verdaux) {
2365 if (verdef->vd_hash == vi->elf_hash &&
2366 strcmp(vi->name, si->get_string(verdaux->vda_name)) == 0) {
2367 *versym = verdef->vd_ndx;
2368 return true;
2369 }
2370
2371 return false;
2372 }
2373 );
2374}
2375
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002376bool VersionTracker::init_verdef(const soinfo* si_from) {
2377 return for_each_verdef(si_from,
2378 [&](size_t, const ElfW(Verdef)* verdef, const ElfW(Verdaux)* verdaux) {
2379 add_version_info(verdef->vd_ndx, verdef->vd_hash,
2380 si_from->get_string(verdaux->vda_name), si_from);
2381 return false;
2382 }
2383 );
2384}
2385
2386bool VersionTracker::init(const soinfo* si_from) {
2387 if (!si_from->has_min_version(2)) {
2388 return true;
2389 }
2390
2391 return init_verneed(si_from) && init_verdef(si_from);
2392}
2393
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002394// TODO (dimitry): Methods below need to be moved out of soinfo
2395// and in more isolated file in order minimize dependencies on
2396// unnecessary object in the linker binary. Consider making them
2397// independent from soinfo (?).
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002398bool soinfo::lookup_version_info(const VersionTracker& version_tracker, ElfW(Word) sym,
2399 const char* sym_name, const version_info** vi) {
2400 const ElfW(Versym)* sym_ver_ptr = get_versym(sym);
2401 ElfW(Versym) sym_ver = sym_ver_ptr == nullptr ? 0 : *sym_ver_ptr;
2402
2403 if (sym_ver != VER_NDX_LOCAL && sym_ver != VER_NDX_GLOBAL) {
2404 *vi = version_tracker.get_version_info(sym_ver);
2405
2406 if (*vi == nullptr) {
2407 DL_ERR("cannot find verneed/verdef for version index=%d "
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002408 "referenced by symbol \"%s\" at \"%s\"", sym_ver, sym_name, get_realpath());
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002409 return false;
2410 }
2411 } else {
2412 // there is no version info
2413 *vi = nullptr;
2414 }
2415
2416 return true;
2417}
2418
Dimitry Ivanov576a3752016-08-09 06:58:55 -07002419#if !defined(__mips__)
2420#if defined(USE_RELA)
2421static ElfW(Addr) get_addend(ElfW(Rela)* rela, ElfW(Addr) reloc_addr __unused) {
2422 return rela->r_addend;
2423}
2424#else
2425static ElfW(Addr) get_addend(ElfW(Rel)* rel, ElfW(Addr) reloc_addr) {
2426 if (ELFW(R_TYPE)(rel->r_info) == R_GENERIC_RELATIVE ||
2427 ELFW(R_TYPE)(rel->r_info) == R_GENERIC_IRELATIVE) {
2428 return *reinterpret_cast<ElfW(Addr)*>(reloc_addr);
2429 }
2430 return 0;
2431}
2432#endif
2433
Dmitriy Ivanovfa26eee2015-02-03 16:06:47 -08002434template<typename ElfRelIteratorT>
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07002435bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& rel_iterator,
2436 const soinfo_list_t& global_group, const soinfo_list_t& local_group) {
Dmitriy Ivanovfa26eee2015-02-03 16:06:47 -08002437 for (size_t idx = 0; rel_iterator.has_next(); ++idx) {
2438 const auto rel = rel_iterator.next();
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002439 if (rel == nullptr) {
2440 return false;
2441 }
2442
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002443 ElfW(Word) type = ELFW(R_TYPE)(rel->r_info);
2444 ElfW(Word) sym = ELFW(R_SYM)(rel->r_info);
2445
2446 ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rel->r_offset + load_bias);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002447 ElfW(Addr) sym_addr = 0;
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07002448 const char* sym_name = nullptr;
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002449 ElfW(Addr) addend = get_addend(rel, reloc);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002450
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07002451 DEBUG("Processing \"%s\" relocation at index %zd", get_realpath(), idx);
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002452 if (type == R_GENERIC_NONE) {
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002453 continue;
2454 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002455
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002456 const ElfW(Sym)* s = nullptr;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002457 soinfo* lsi = nullptr;
2458
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002459 if (sym != 0) {
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002460 sym_name = get_string(symtab_[sym].st_name);
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002461 const version_info* vi = nullptr;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002462
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002463 if (!lookup_version_info(version_tracker, sym, sym_name, &vi)) {
2464 return false;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002465 }
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002466
2467 if (!soinfo_do_lookup(this, sym_name, vi, &lsi, global_group, local_group, &s)) {
2468 return false;
2469 }
2470
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07002471 if (s == nullptr) {
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002472 // We only allow an undefined symbol if this is a weak reference...
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002473 s = &symtab_[sym];
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002474 if (ELF_ST_BIND(s->st_info) != STB_WEAK) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002475 DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, get_realpath());
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002476 return false;
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002477 }
2478
2479 /* IHI0044C AAELF 4.5.1.1:
2480
2481 Libraries are not searched to resolve weak references.
2482 It is not an error for a weak reference to remain unsatisfied.
2483
2484 During linking, the value of an undefined weak reference is:
2485 - Zero if the relocation type is absolute
2486 - The address of the place if the relocation is pc-relative
2487 - The address of nominal base address if the relocation
2488 type is base-relative.
2489 */
2490
2491 switch (type) {
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002492 case R_GENERIC_JUMP_SLOT:
2493 case R_GENERIC_GLOB_DAT:
2494 case R_GENERIC_RELATIVE:
2495 case R_GENERIC_IRELATIVE:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002496#if defined(__aarch64__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002497 case R_AARCH64_ABS64:
2498 case R_AARCH64_ABS32:
2499 case R_AARCH64_ABS16:
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002500#elif defined(__x86_64__)
2501 case R_X86_64_32:
2502 case R_X86_64_64:
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002503#elif defined(__arm__)
2504 case R_ARM_ABS32:
2505#elif defined(__i386__)
2506 case R_386_32:
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002507#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002508 /*
2509 * The sym_addr was initialized to be zero above, or the relocation
2510 * code below does not care about value of sym_addr.
2511 * No need to do anything.
2512 */
2513 break;
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002514#if defined(__x86_64__)
Dimitry Ivanovd338aac2015-01-13 22:31:54 +00002515 case R_X86_64_PC32:
2516 sym_addr = reloc;
2517 break;
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002518#elif defined(__i386__)
2519 case R_386_PC32:
2520 sym_addr = reloc;
2521 break;
2522#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002523 default:
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002524 DL_ERR("unknown weak reloc type %d @ %p (%zu)", type, rel, idx);
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002525 return false;
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002526 }
Dmitriy Ivanovec83a612015-07-26 07:37:09 -07002527 } else { // We got a definition.
2528#if !defined(__LP64__)
2529 // When relocating dso with text_relocation .text segment is
2530 // not executable. We need to restore elf flags before resolving
2531 // STT_GNU_IFUNC symbol.
2532 bool protect_segments = has_text_relocations &&
2533 lsi == this &&
2534 ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC;
2535 if (protect_segments) {
2536 if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
2537 DL_ERR("can't protect segments for \"%s\": %s",
2538 get_realpath(), strerror(errno));
2539 return false;
2540 }
2541 }
2542#endif
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07002543 sym_addr = lsi->resolve_symbol_address(s);
Dmitriy Ivanovec83a612015-07-26 07:37:09 -07002544#if !defined(__LP64__)
2545 if (protect_segments) {
2546 if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
2547 DL_ERR("can't unprotect loadable segments for \"%s\": %s",
2548 get_realpath(), strerror(errno));
2549 return false;
2550 }
2551 }
2552#endif
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002553 }
2554 count_relocation(kRelocSymbol);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002555 }
2556
2557 switch (type) {
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002558 case R_GENERIC_JUMP_SLOT:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002559 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002560 MARK(rel->r_offset);
2561 TRACE_TYPE(RELO, "RELO JMP_SLOT %16p <- %16p %s\n",
2562 reinterpret_cast<void*>(reloc),
2563 reinterpret_cast<void*>(sym_addr + addend), sym_name);
2564
2565 *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002566 break;
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002567 case R_GENERIC_GLOB_DAT:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002568 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002569 MARK(rel->r_offset);
2570 TRACE_TYPE(RELO, "RELO GLOB_DAT %16p <- %16p %s\n",
2571 reinterpret_cast<void*>(reloc),
2572 reinterpret_cast<void*>(sym_addr + addend), sym_name);
2573 *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002574 break;
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002575 case R_GENERIC_RELATIVE:
2576 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002577 MARK(rel->r_offset);
2578 TRACE_TYPE(RELO, "RELO RELATIVE %16p <- %16p\n",
2579 reinterpret_cast<void*>(reloc),
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002580 reinterpret_cast<void*>(load_bias + addend));
2581 *reinterpret_cast<ElfW(Addr)*>(reloc) = (load_bias + addend);
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002582 break;
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002583 case R_GENERIC_IRELATIVE:
2584 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002585 MARK(rel->r_offset);
2586 TRACE_TYPE(RELO, "RELO IRELATIVE %16p <- %16p\n",
2587 reinterpret_cast<void*>(reloc),
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002588 reinterpret_cast<void*>(load_bias + addend));
Dmitriy Ivanovec83a612015-07-26 07:37:09 -07002589 {
2590#if !defined(__LP64__)
2591 // When relocating dso with text_relocation .text segment is
2592 // not executable. We need to restore elf flags for this
2593 // particular call.
2594 if (has_text_relocations) {
2595 if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
2596 DL_ERR("can't protect segments for \"%s\": %s",
2597 get_realpath(), strerror(errno));
2598 return false;
2599 }
2600 }
2601#endif
2602 ElfW(Addr) ifunc_addr = call_ifunc_resolver(load_bias + addend);
2603#if !defined(__LP64__)
2604 // Unprotect it afterwards...
2605 if (has_text_relocations) {
2606 if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
2607 DL_ERR("can't unprotect loadable segments for \"%s\": %s",
2608 get_realpath(), strerror(errno));
2609 return false;
2610 }
2611 }
2612#endif
2613 *reinterpret_cast<ElfW(Addr)*>(reloc) = ifunc_addr;
2614 }
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002615 break;
2616
2617#if defined(__aarch64__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002618 case R_AARCH64_ABS64:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002619 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002620 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002621 TRACE_TYPE(RELO, "RELO ABS64 %16llx <- %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002622 reloc, sym_addr + addend, sym_name);
2623 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend;
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002624 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002625 case R_AARCH64_ABS32:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002626 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002627 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002628 TRACE_TYPE(RELO, "RELO ABS32 %16llx <- %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002629 reloc, sym_addr + addend, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002630 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002631 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT32_MIN);
2632 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT32_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002633 if ((min_value <= (sym_addr + addend)) &&
2634 ((sym_addr + addend) <= max_value)) {
2635 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend;
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002636 } else {
2637 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002638 sym_addr + addend, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002639 return false;
2640 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002641 }
2642 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002643 case R_AARCH64_ABS16:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002644 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002645 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002646 TRACE_TYPE(RELO, "RELO ABS16 %16llx <- %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002647 reloc, sym_addr + addend, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002648 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002649 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN);
2650 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT16_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002651 if ((min_value <= (sym_addr + addend)) &&
2652 ((sym_addr + addend) <= max_value)) {
2653 *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002654 } else {
2655 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002656 sym_addr + addend, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002657 return false;
2658 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002659 }
2660 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002661 case R_AARCH64_PREL64:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002662 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002663 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002664 TRACE_TYPE(RELO, "RELO REL64 %16llx <- %16llx - %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002665 reloc, sym_addr + addend, rel->r_offset, sym_name);
2666 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset;
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002667 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002668 case R_AARCH64_PREL32:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002669 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002670 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002671 TRACE_TYPE(RELO, "RELO REL32 %16llx <- %16llx - %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002672 reloc, sym_addr + addend, rel->r_offset, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002673 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002674 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT32_MIN);
2675 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT32_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002676 if ((min_value <= (sym_addr + addend - rel->r_offset)) &&
2677 ((sym_addr + addend - rel->r_offset) <= max_value)) {
2678 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset;
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002679 } else {
2680 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002681 sym_addr + addend - rel->r_offset, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002682 return false;
2683 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002684 }
2685 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002686 case R_AARCH64_PREL16:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002687 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002688 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002689 TRACE_TYPE(RELO, "RELO REL16 %16llx <- %16llx - %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002690 reloc, sym_addr + addend, rel->r_offset, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002691 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002692 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN);
2693 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT16_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002694 if ((min_value <= (sym_addr + addend - rel->r_offset)) &&
2695 ((sym_addr + addend - rel->r_offset) <= max_value)) {
2696 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset;
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002697 } else {
2698 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002699 sym_addr + addend - rel->r_offset, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002700 return false;
2701 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002702 }
2703 break;
2704
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002705 case R_AARCH64_COPY:
Nick Kralevich76e289c2014-07-03 12:04:31 -07002706 /*
2707 * ET_EXEC is not supported so this should not happen.
2708 *
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002709 * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0056b/IHI0056B_aaelf64.pdf
Nick Kralevich76e289c2014-07-03 12:04:31 -07002710 *
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002711 * Section 4.6.11 "Dynamic relocations"
Nick Kralevich76e289c2014-07-03 12:04:31 -07002712 * R_AARCH64_COPY may only appear in executable objects where e_type is
2713 * set to ET_EXEC.
2714 */
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002715 DL_ERR("%s R_AARCH64_COPY relocations are not supported", get_realpath());
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002716 return false;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002717 case R_AARCH64_TLS_TPREL64:
Elliott Hughes0266ae52014-02-10 17:46:57 -08002718 TRACE_TYPE(RELO, "RELO TLS_TPREL64 *** %16llx <- %16llx - %16llx\n",
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002719 reloc, (sym_addr + addend), rel->r_offset);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002720 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002721 case R_AARCH64_TLS_DTPREL32:
Elliott Hughes0266ae52014-02-10 17:46:57 -08002722 TRACE_TYPE(RELO, "RELO TLS_DTPREL32 *** %16llx <- %16llx - %16llx\n",
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002723 reloc, (sym_addr + addend), rel->r_offset);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002724 break;
2725#elif defined(__x86_64__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002726 case R_X86_64_32:
2727 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002728 MARK(rel->r_offset);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002729 TRACE_TYPE(RELO, "RELO R_X86_64_32 %08zx <- +%08zx %s", static_cast<size_t>(reloc),
2730 static_cast<size_t>(sym_addr), sym_name);
Junichi Uekawaff35b1e2015-11-18 10:18:59 +09002731 *reinterpret_cast<Elf32_Addr*>(reloc) = sym_addr + addend;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002732 break;
2733 case R_X86_64_64:
2734 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002735 MARK(rel->r_offset);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002736 TRACE_TYPE(RELO, "RELO R_X86_64_64 %08zx <- +%08zx %s", static_cast<size_t>(reloc),
2737 static_cast<size_t>(sym_addr), sym_name);
Junichi Uekawaff35b1e2015-11-18 10:18:59 +09002738 *reinterpret_cast<Elf64_Addr*>(reloc) = sym_addr + addend;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002739 break;
2740 case R_X86_64_PC32:
2741 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002742 MARK(rel->r_offset);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002743 TRACE_TYPE(RELO, "RELO R_X86_64_PC32 %08zx <- +%08zx (%08zx - %08zx) %s",
2744 static_cast<size_t>(reloc), static_cast<size_t>(sym_addr - reloc),
2745 static_cast<size_t>(sym_addr), static_cast<size_t>(reloc), sym_name);
Junichi Uekawaff35b1e2015-11-18 10:18:59 +09002746 *reinterpret_cast<Elf32_Addr*>(reloc) = sym_addr + addend - reloc;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002747 break;
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002748#elif defined(__arm__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002749 case R_ARM_ABS32:
2750 count_relocation(kRelocAbsolute);
2751 MARK(rel->r_offset);
2752 TRACE_TYPE(RELO, "RELO ABS %08x <- %08x %s", reloc, sym_addr, sym_name);
2753 *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
2754 break;
2755 case R_ARM_REL32:
2756 count_relocation(kRelocRelative);
2757 MARK(rel->r_offset);
2758 TRACE_TYPE(RELO, "RELO REL32 %08x <- %08x - %08x %s",
2759 reloc, sym_addr, rel->r_offset, sym_name);
2760 *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr - rel->r_offset;
2761 break;
2762 case R_ARM_COPY:
2763 /*
2764 * ET_EXEC is not supported so this should not happen.
2765 *
2766 * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044d/IHI0044D_aaelf.pdf
2767 *
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002768 * Section 4.6.1.10 "Dynamic relocations"
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002769 * R_ARM_COPY may only appear in executable objects where e_type is
2770 * set to ET_EXEC.
2771 */
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002772 DL_ERR("%s R_ARM_COPY relocations are not supported", get_realpath());
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002773 return false;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002774#elif defined(__i386__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002775 case R_386_32:
2776 count_relocation(kRelocRelative);
2777 MARK(rel->r_offset);
2778 TRACE_TYPE(RELO, "RELO R_386_32 %08x <- +%08x %s", reloc, sym_addr, sym_name);
2779 *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
2780 break;
2781 case R_386_PC32:
2782 count_relocation(kRelocRelative);
2783 MARK(rel->r_offset);
2784 TRACE_TYPE(RELO, "RELO R_386_PC32 %08x <- +%08x (%08x - %08x) %s",
2785 reloc, (sym_addr - reloc), sym_addr, reloc, sym_name);
2786 *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr - reloc);
2787 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002788#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002789 default:
2790 DL_ERR("unknown reloc type %d @ %p (%zu)", type, rel, idx);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002791 return false;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002792 }
2793 }
2794 return true;
Raghu Gandhamd7daacb2012-07-31 12:07:22 -07002795}
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002796#endif // !defined(__mips__)
Raghu Gandhamd7daacb2012-07-31 12:07:22 -07002797
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002798// An empty list of soinfos
Dimitry Ivanovb943f302016-08-03 16:00:10 -07002799static soinfo_list_t g_empty_list;
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07002800
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002801bool soinfo::prelink_image() {
Ningsheng Jiane93be992014-09-16 15:22:10 +08002802 /* Extract dynamic section */
2803 ElfW(Word) dynamic_flags = 0;
2804 phdr_table_get_dynamic_section(phdr, phnum, load_bias, &dynamic, &dynamic_flags);
Dmitriy Ivanov498eb182014-09-05 14:57:59 -07002805
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002806 /* We can't log anything until the linker is relocated */
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002807 bool relocating_linker = (flags_ & FLAG_LINKER) != 0;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002808 if (!relocating_linker) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07002809 INFO("[ Linking \"%s\" ]", get_realpath());
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002810 DEBUG("si->base = %p si->flags = 0x%08x", reinterpret_cast<void*>(base), flags_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002811 }
2812
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002813 if (dynamic == nullptr) {
David 'Digit' Turnerb52e4382012-06-19 01:24:17 +02002814 if (!relocating_linker) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002815 DL_ERR("missing PT_DYNAMIC in \"%s\"", get_realpath());
David 'Digit' Turnerb52e4382012-06-19 01:24:17 +02002816 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002817 return false;
2818 } else {
2819 if (!relocating_linker) {
2820 DEBUG("dynamic = %p", dynamic);
David 'Digit' Turner63f99f42012-06-19 00:08:39 +02002821 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002822 }
David 'Digit' Turner63f99f42012-06-19 00:08:39 +02002823
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07002824#if defined(__arm__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002825 (void) phdr_table_get_arm_exidx(phdr, phnum, load_bias,
2826 &ARM_exidx, &ARM_exidx_count);
David 'Digit' Turner63f99f42012-06-19 00:08:39 +02002827#endif
2828
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002829 // Extract useful information from dynamic section.
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07002830 // Note that: "Except for the DT_NULL element at the end of the array,
2831 // and the relative order of DT_NEEDED elements, entries may appear in any order."
2832 //
2833 // source: http://www.sco.com/developers/gabi/1998-04-29/ch5.dynamic.html
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002834 uint32_t needed_count = 0;
2835 for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
2836 DEBUG("d = %p, d[0](tag) = %p d[1](val) = %p",
2837 d, reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
2838 switch (d->d_tag) {
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002839 case DT_SONAME:
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07002840 // this is parsed after we have strtab initialized (see below).
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002841 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002842
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002843 case DT_HASH:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002844 nbucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0];
2845 nchain_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
2846 bucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8);
2847 chain_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8 + nbucket_ * 4);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002848 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002849
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002850 case DT_GNU_HASH:
Dmitriy Ivanov3597b802015-03-09 12:02:02 -07002851 gnu_nbucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0];
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002852 // skip symndx
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002853 gnu_maskwords_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[2];
2854 gnu_shift2_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[3];
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002855
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002856 gnu_bloom_filter_ = reinterpret_cast<ElfW(Addr)*>(load_bias + d->d_un.d_ptr + 16);
Dmitriy Ivanov3597b802015-03-09 12:02:02 -07002857 gnu_bucket_ = reinterpret_cast<uint32_t*>(gnu_bloom_filter_ + gnu_maskwords_);
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002858 // amend chain for symndx = header[1]
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002859 gnu_chain_ = gnu_bucket_ + gnu_nbucket_ -
2860 reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002861
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002862 if (!powerof2(gnu_maskwords_)) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002863 DL_ERR("invalid maskwords for gnu_hash = 0x%x, in \"%s\" expecting power to two",
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002864 gnu_maskwords_, get_realpath());
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002865 return false;
2866 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002867 --gnu_maskwords_;
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002868
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002869 flags_ |= FLAG_GNU_HASH;
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002870 break;
2871
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002872 case DT_STRTAB:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002873 strtab_ = reinterpret_cast<const char*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002874 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002875
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07002876 case DT_STRSZ:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002877 strtab_size_ = d->d_un.d_val;
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07002878 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002879
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002880 case DT_SYMTAB:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002881 symtab_ = reinterpret_cast<ElfW(Sym)*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002882 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002883
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002884 case DT_SYMENT:
2885 if (d->d_un.d_val != sizeof(ElfW(Sym))) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002886 DL_ERR("invalid DT_SYMENT: %zd in \"%s\"",
2887 static_cast<size_t>(d->d_un.d_val), get_realpath());
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002888 return false;
2889 }
2890 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002891
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002892 case DT_PLTREL:
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002893#if defined(USE_RELA)
2894 if (d->d_un.d_val != DT_RELA) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002895 DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_RELA", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002896 return false;
2897 }
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002898#else
2899 if (d->d_un.d_val != DT_REL) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002900 DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_REL", get_realpath());
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002901 return false;
2902 }
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002903#endif
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002904 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002905
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002906 case DT_JMPREL:
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07002907#if defined(USE_RELA)
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002908 plt_rela_ = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002909#else
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002910 plt_rel_ = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002911#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002912 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002913
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002914 case DT_PLTRELSZ:
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07002915#if defined(USE_RELA)
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002916 plt_rela_count_ = d->d_un.d_val / sizeof(ElfW(Rela));
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002917#else
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002918 plt_rel_count_ = d->d_un.d_val / sizeof(ElfW(Rel));
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002919#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002920 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002921
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002922 case DT_PLTGOT:
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002923#if defined(__mips__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002924 // Used by mips and mips64.
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002925 plt_got_ = reinterpret_cast<ElfW(Addr)**>(load_bias + d->d_un.d_ptr);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002926#endif
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002927 // Ignore for other platforms... (because RTLD_LAZY is not supported)
2928 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002929
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002930 case DT_DEBUG:
2931 // Set the DT_DEBUG entry to the address of _r_debug for GDB
2932 // if the dynamic table is writable
Chris Dearman99186652014-02-06 20:36:51 -08002933// FIXME: not working currently for N64
2934// The flags for the LOAD and DYNAMIC program headers do not agree.
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002935// The LOAD section containing the dynamic table has been mapped as
Chris Dearman99186652014-02-06 20:36:51 -08002936// read-only, but the DYNAMIC header claims it is writable.
2937#if !(defined(__mips__) && defined(__LP64__))
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002938 if ((dynamic_flags & PF_W) != 0) {
2939 d->d_un.d_val = reinterpret_cast<uintptr_t>(&_r_debug);
2940 }
Chris Dearman99186652014-02-06 20:36:51 -08002941#endif
Dmitriy Ivanovc6292ea2015-02-13 16:29:50 -08002942 break;
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07002943#if defined(USE_RELA)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002944 case DT_RELA:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002945 rela_ = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002946 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002947
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002948 case DT_RELASZ:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002949 rela_count_ = d->d_un.d_val / sizeof(ElfW(Rela));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002950 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002951
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002952 case DT_ANDROID_RELA:
2953 android_relocs_ = reinterpret_cast<uint8_t*>(load_bias + d->d_un.d_ptr);
2954 break;
2955
2956 case DT_ANDROID_RELASZ:
2957 android_relocs_size_ = d->d_un.d_val;
2958 break;
2959
2960 case DT_ANDROID_REL:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002961 DL_ERR("unsupported DT_ANDROID_REL in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002962 return false;
2963
2964 case DT_ANDROID_RELSZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002965 DL_ERR("unsupported DT_ANDROID_RELSZ in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002966 return false;
2967
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002968 case DT_RELAENT:
2969 if (d->d_un.d_val != sizeof(ElfW(Rela))) {
Dmitriy Ivanovf240aa82014-09-16 23:34:20 -07002970 DL_ERR("invalid DT_RELAENT: %zd", static_cast<size_t>(d->d_un.d_val));
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002971 return false;
2972 }
2973 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002974
2975 // ignored (see DT_RELCOUNT comments for details)
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002976 case DT_RELACOUNT:
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002977 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002978
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002979 case DT_REL:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002980 DL_ERR("unsupported DT_REL in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002981 return false;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002982
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002983 case DT_RELSZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002984 DL_ERR("unsupported DT_RELSZ in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002985 return false;
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002986
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002987#else
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002988 case DT_REL:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002989 rel_ = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
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_RELSZ:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002993 rel_count_ = d->d_un.d_val / sizeof(ElfW(Rel));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002994 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002995
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002996 case DT_RELENT:
2997 if (d->d_un.d_val != sizeof(ElfW(Rel))) {
Dmitriy Ivanovf240aa82014-09-16 23:34:20 -07002998 DL_ERR("invalid DT_RELENT: %zd", static_cast<size_t>(d->d_un.d_val));
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002999 return false;
3000 }
3001 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003002
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003003 case DT_ANDROID_REL:
3004 android_relocs_ = reinterpret_cast<uint8_t*>(load_bias + d->d_un.d_ptr);
3005 break;
3006
3007 case DT_ANDROID_RELSZ:
3008 android_relocs_size_ = d->d_un.d_val;
3009 break;
3010
3011 case DT_ANDROID_RELA:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003012 DL_ERR("unsupported DT_ANDROID_RELA in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003013 return false;
3014
3015 case DT_ANDROID_RELASZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003016 DL_ERR("unsupported DT_ANDROID_RELASZ in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003017 return false;
3018
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003019 // "Indicates that all RELATIVE relocations have been concatenated together,
3020 // and specifies the RELATIVE relocation count."
3021 //
3022 // TODO: Spec also mentions that this can be used to optimize relocation process;
3023 // Not currently used by bionic linker - ignored.
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003024 case DT_RELCOUNT:
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003025 break;
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003026
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003027 case DT_RELA:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003028 DL_ERR("unsupported DT_RELA in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003029 return false;
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003030
3031 case DT_RELASZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003032 DL_ERR("unsupported DT_RELASZ in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003033 return false;
3034
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07003035#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003036 case DT_INIT:
Dimitry Ivanov55437462016-07-20 15:33:07 -07003037 init_func_ = reinterpret_cast<linker_ctor_function_t>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003038 DEBUG("%s constructors (DT_INIT) found at %p", get_realpath(), init_func_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003039 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003040
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003041 case DT_FINI:
Dimitry Ivanov55437462016-07-20 15:33:07 -07003042 fini_func_ = reinterpret_cast<linker_dtor_function_t>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003043 DEBUG("%s destructors (DT_FINI) found at %p", get_realpath(), fini_func_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003044 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003045
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003046 case DT_INIT_ARRAY:
Dimitry Ivanov55437462016-07-20 15:33:07 -07003047 init_array_ = reinterpret_cast<linker_ctor_function_t*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003048 DEBUG("%s constructors (DT_INIT_ARRAY) found at %p", get_realpath(), init_array_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003049 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003050
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003051 case DT_INIT_ARRAYSZ:
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -08003052 init_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003053 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003054
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003055 case DT_FINI_ARRAY:
Dimitry Ivanov55437462016-07-20 15:33:07 -07003056 fini_array_ = reinterpret_cast<linker_dtor_function_t*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003057 DEBUG("%s destructors (DT_FINI_ARRAY) found at %p", get_realpath(), fini_array_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003058 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003059
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003060 case DT_FINI_ARRAYSZ:
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -08003061 fini_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003062 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003063
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003064 case DT_PREINIT_ARRAY:
Dimitry Ivanov55437462016-07-20 15:33:07 -07003065 preinit_array_ = reinterpret_cast<linker_ctor_function_t*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003066 DEBUG("%s constructors (DT_PREINIT_ARRAY) found at %p", get_realpath(), preinit_array_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003067 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003068
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003069 case DT_PREINIT_ARRAYSZ:
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -08003070 preinit_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003071 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003072
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003073 case DT_TEXTREL:
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003074#if defined(__LP64__)
Dimitry Ivanov816676e2016-10-19 11:00:28 -07003075 DL_ERR("\"%s\" has text relocations", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003076 return false;
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003077#else
3078 has_text_relocations = true;
3079 break;
3080#endif
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003081
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003082 case DT_SYMBOLIC:
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -07003083 has_DT_SYMBOLIC = true;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003084 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003085
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003086 case DT_NEEDED:
3087 ++needed_count;
3088 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003089
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003090 case DT_FLAGS:
3091 if (d->d_un.d_val & DF_TEXTREL) {
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003092#if defined(__LP64__)
Dimitry Ivanov816676e2016-10-19 11:00:28 -07003093 DL_ERR("\"%s\" has text relocations", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003094 return false;
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003095#else
3096 has_text_relocations = true;
3097#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003098 }
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -07003099 if (d->d_un.d_val & DF_SYMBOLIC) {
3100 has_DT_SYMBOLIC = true;
3101 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003102 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003103
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07003104 case DT_FLAGS_1:
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07003105 set_dt_flags_1(d->d_un.d_val);
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -07003106
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07003107 if ((d->d_un.d_val & ~SUPPORTED_DT_FLAGS_1) != 0) {
Dimitry Ivanov816676e2016-10-19 11:00:28 -07003108 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 -07003109 }
3110 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003111#if defined(__mips__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003112 case DT_MIPS_RLD_MAP:
3113 // Set the DT_MIPS_RLD_MAP entry to the address of _r_debug for GDB.
3114 {
3115 r_debug** dp = reinterpret_cast<r_debug**>(load_bias + d->d_un.d_ptr);
3116 *dp = &_r_debug;
3117 }
3118 break;
Lazar Trsic83b44a92016-04-06 13:39:17 +02003119 case DT_MIPS_RLD_MAP_REL:
3120 // Set the DT_MIPS_RLD_MAP_REL entry to the address of _r_debug for GDB.
Raghu Gandham68815722014-12-18 19:12:19 -08003121 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07003122 r_debug** dp = reinterpret_cast<r_debug**>(
3123 reinterpret_cast<ElfW(Addr)>(d) + d->d_un.d_val);
Raghu Gandham68815722014-12-18 19:12:19 -08003124 *dp = &_r_debug;
3125 }
3126 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003127
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003128 case DT_MIPS_RLD_VERSION:
3129 case DT_MIPS_FLAGS:
3130 case DT_MIPS_BASE_ADDRESS:
3131 case DT_MIPS_UNREFEXTNO:
3132 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003133
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003134 case DT_MIPS_SYMTABNO:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003135 mips_symtabno_ = d->d_un.d_val;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003136 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003137
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003138 case DT_MIPS_LOCAL_GOTNO:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003139 mips_local_gotno_ = d->d_un.d_val;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003140 break;
3141
3142 case DT_MIPS_GOTSYM:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003143 mips_gotsym_ = d->d_un.d_val;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003144 break;
3145#endif
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003146 // Ignored: "Its use has been superseded by the DF_BIND_NOW flag"
3147 case DT_BIND_NOW:
3148 break;
3149
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003150 case DT_VERSYM:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003151 versym_ = reinterpret_cast<ElfW(Versym)*>(load_bias + d->d_un.d_ptr);
3152 break;
3153
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003154 case DT_VERDEF:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003155 verdef_ptr_ = load_bias + d->d_un.d_ptr;
3156 break;
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003157 case DT_VERDEFNUM:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003158 verdef_cnt_ = d->d_un.d_val;
3159 break;
3160
Alexander Ivchenkoe8314332014-12-02 15:32:25 +03003161 case DT_VERNEED:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003162 verneed_ptr_ = load_bias + d->d_un.d_ptr;
3163 break;
3164
Alexander Ivchenkoe8314332014-12-02 15:32:25 +03003165 case DT_VERNEEDNUM:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003166 verneed_cnt_ = d->d_un.d_val;
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003167 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003168
Evgenii Stepanov68650822015-06-10 13:38:39 -07003169 case DT_RUNPATH:
3170 // this is parsed after we have strtab initialized (see below).
3171 break;
3172
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003173 default:
Dmitriy Ivanov8f61d992014-09-16 14:31:06 -07003174 if (!relocating_linker) {
Dimitry Ivanov816676e2016-10-19 11:00:28 -07003175 DL_WARN("\"%s\" unused DT entry: type %p arg %p", get_realpath(),
Dmitriy Ivanov8f61d992014-09-16 14:31:06 -07003176 reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
3177 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003178 break;
Brian Carlstromd4ee82d2013-02-28 15:58:45 -08003179 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003180 }
3181
Duane Sandbc425c72015-06-01 16:29:14 -07003182#if defined(__mips__) && !defined(__LP64__)
3183 if (!mips_check_and_adjust_fp_modes()) {
3184 return false;
3185 }
3186#endif
3187
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003188 DEBUG("si->base = %p, si->strtab = %p, si->symtab = %p",
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003189 reinterpret_cast<void*>(base), strtab_, symtab_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003190
3191 // Sanity checks.
3192 if (relocating_linker && needed_count != 0) {
3193 DL_ERR("linker cannot have DT_NEEDED dependencies on other libraries");
3194 return false;
3195 }
Dmitriy Ivanov3597b802015-03-09 12:02:02 -07003196 if (nbucket_ == 0 && gnu_nbucket_ == 0) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003197 DL_ERR("empty/missing DT_HASH/DT_GNU_HASH in \"%s\" "
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003198 "(new hash type from the future?)", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003199 return false;
3200 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003201 if (strtab_ == 0) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003202 DL_ERR("empty/missing DT_STRTAB in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003203 return false;
3204 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003205 if (symtab_ == 0) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003206 DL_ERR("empty/missing DT_SYMTAB in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003207 return false;
3208 }
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003209
Dmitriy Ivanov624b8f12015-06-08 10:41:33 -07003210 // second pass - parse entries relying on strtab
3211 for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
Evgenii Stepanov68650822015-06-10 13:38:39 -07003212 switch (d->d_tag) {
3213 case DT_SONAME:
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07003214 set_soname(get_string(d->d_un.d_val));
Evgenii Stepanov68650822015-06-10 13:38:39 -07003215 break;
3216 case DT_RUNPATH:
Evgenii Stepanov68650822015-06-10 13:38:39 -07003217 set_dt_runpath(get_string(d->d_un.d_val));
3218 break;
Dmitriy Ivanov624b8f12015-06-08 10:41:33 -07003219 }
3220 }
3221
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003222 // Before M release linker was using basename in place of soname.
Dmitriy Ivanov19133522015-06-02 17:36:54 -07003223 // In the case when dt_soname is absent some apps stop working
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003224 // because they can't find dt_needed library by soname.
3225 // This workaround should keep them working. (applies only
Elliott Hughes5bc78c82016-11-16 11:35:43 -08003226 // for apps targeting sdk version < M). Make an exception for
Dmitriy Ivanov19133522015-06-02 17:36:54 -07003227 // the main executable and linker; they do not need to have dt_soname
Dimitry Ivanov3f660572016-09-09 10:00:39 -07003228 if (soname_ == nullptr &&
3229 this != solist_get_somain() &&
3230 (flags_ & FLAG_LINKER) == 0 &&
Elliott Hughes5bc78c82016-11-16 11:35:43 -08003231 get_application_target_sdk_version() < __ANDROID_API_M__) {
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003232 soname_ = basename(realpath_.c_str());
3233 DL_WARN("%s: is missing DT_SONAME will use basename as a replacement: \"%s\"",
3234 get_realpath(), soname_);
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07003235 // 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 -07003236 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003237 return true;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07003238}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003239
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003240bool soinfo::link_image(const soinfo_list_t& global_group, const soinfo_list_t& local_group,
3241 const android_dlextinfo* extinfo) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003242
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08003243 local_group_root_ = local_group.front();
3244 if (local_group_root_ == nullptr) {
3245 local_group_root_ = this;
3246 }
3247
Dmitriy Ivanov19133522015-06-02 17:36:54 -07003248 if ((flags_ & FLAG_LINKER) == 0 && local_group_root_ == this) {
3249 target_sdk_version_ = get_application_target_sdk_version();
3250 }
3251
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003252 VersionTracker version_tracker;
3253
3254 if (!version_tracker.init(this)) {
3255 return false;
3256 }
3257
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003258#if !defined(__LP64__)
3259 if (has_text_relocations) {
Elliott Hughes5bc78c82016-11-16 11:35:43 -08003260 // Fail if app is targeting M or above.
3261 if (get_application_target_sdk_version() >= __ANDROID_API_M__) {
Dimitry Ivanov816676e2016-10-19 11:00:28 -07003262 DL_ERR_AND_LOG("\"%s\" has text relocations", get_realpath());
Dmitriy Ivanove4ad91f2015-06-12 15:00:31 -07003263 return false;
3264 }
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003265 // Make segments writable to allow text relocations to work properly. We will later call
Dmitriy Ivanov7e039932015-10-01 14:02:19 -07003266 // phdr_table_protect_segments() after all of them are applied.
Dimitry Ivanov816676e2016-10-19 11:00:28 -07003267 DL_WARN("\"%s\" has text relocations. This is wasting memory and prevents "
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003268 "security hardening. Please fix.", get_realpath());
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07003269 add_dlwarning(get_realpath(), "text relocations");
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003270 if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
3271 DL_ERR("can't unprotect loadable segments for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003272 get_realpath(), strerror(errno));
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003273 return false;
3274 }
3275 }
3276#endif
3277
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003278 if (android_relocs_ != nullptr) {
3279 // check signature
3280 if (android_relocs_size_ > 3 &&
3281 android_relocs_[0] == 'A' &&
3282 android_relocs_[1] == 'P' &&
Dmitriy Ivanov18870d32015-04-22 13:10:04 -07003283 android_relocs_[2] == 'S' &&
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003284 android_relocs_[3] == '2') {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003285 DEBUG("[ android relocating %s ]", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003286
3287 bool relocated = false;
3288 const uint8_t* packed_relocs = android_relocs_ + 4;
3289 const size_t packed_relocs_size = android_relocs_size_ - 4;
3290
Dmitriy Ivanov18870d32015-04-22 13:10:04 -07003291 relocated = relocate(
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003292 version_tracker,
Dmitriy Ivanov18870d32015-04-22 13:10:04 -07003293 packed_reloc_iterator<sleb128_decoder>(
3294 sleb128_decoder(packed_relocs, packed_relocs_size)),
3295 global_group, local_group);
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003296
3297 if (!relocated) {
3298 return false;
3299 }
3300 } else {
3301 DL_ERR("bad android relocation header.");
3302 return false;
3303 }
3304 }
3305
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07003306#if defined(USE_RELA)
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003307 if (rela_ != nullptr) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003308 DEBUG("[ relocating %s ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003309 if (!relocate(version_tracker,
3310 plain_reloc_iterator(rela_, rela_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003311 return false;
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07003312 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003313 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003314 if (plt_rela_ != nullptr) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003315 DEBUG("[ relocating %s plt ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003316 if (!relocate(version_tracker,
3317 plain_reloc_iterator(plt_rela_, plt_rela_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003318 return false;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003319 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003320 }
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07003321#else
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003322 if (rel_ != nullptr) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003323 DEBUG("[ relocating %s ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003324 if (!relocate(version_tracker,
3325 plain_reloc_iterator(rel_, rel_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003326 return false;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003327 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003328 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003329 if (plt_rel_ != nullptr) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003330 DEBUG("[ relocating %s plt ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003331 if (!relocate(version_tracker,
3332 plain_reloc_iterator(plt_rel_, plt_rel_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003333 return false;
Brigid Smithc5a13ef2014-07-23 11:22:25 -07003334 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003335 }
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07003336#endif
Brigid Smithc5a13ef2014-07-23 11:22:25 -07003337
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07003338#if defined(__mips__)
Dmitriy Ivanovf39cb632015-04-30 20:17:03 -07003339 if (!mips_relocate_got(version_tracker, global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003340 return false;
3341 }
Raghu Gandhamd7daacb2012-07-31 12:07:22 -07003342#endif
3343
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003344 DEBUG("[ finished linking %s ]", get_realpath());
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003345
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003346#if !defined(__LP64__)
3347 if (has_text_relocations) {
3348 // All relocations are done, we can protect our segments back to read-only.
3349 if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
3350 DL_ERR("can't protect segments for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003351 get_realpath(), strerror(errno));
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003352 return false;
3353 }
3354 }
3355#endif
3356
Mingwei Shibe910522015-11-12 07:02:14 +00003357 // We can also turn on GNU RELRO protection if we're not linking the dynamic linker
3358 // itself --- it can't make system calls yet, and will have to call protect_relro later.
3359 if (!is_linker() && !protect_relro()) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003360 return false;
3361 }
Nick Kralevich9ec0f032012-02-28 10:40:00 -08003362
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003363 /* Handle serializing/sharing the RELRO segment */
3364 if (extinfo && (extinfo->flags & ANDROID_DLEXT_WRITE_RELRO)) {
3365 if (phdr_table_serialize_gnu_relro(phdr, phnum, load_bias,
3366 extinfo->relro_fd) < 0) {
3367 DL_ERR("failed serializing GNU RELRO section for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003368 get_realpath(), strerror(errno));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003369 return false;
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +00003370 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003371 } else if (extinfo && (extinfo->flags & ANDROID_DLEXT_USE_RELRO)) {
3372 if (phdr_table_map_gnu_relro(phdr, phnum, load_bias,
3373 extinfo->relro_fd) < 0) {
3374 DL_ERR("failed mapping GNU RELRO section for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003375 get_realpath(), strerror(errno));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003376 return false;
3377 }
3378 }
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +00003379
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003380 notify_gdb_of_load(this);
3381 return true;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003382}
3383
Mingwei Shibe910522015-11-12 07:02:14 +00003384bool soinfo::protect_relro() {
3385 if (phdr_table_protect_gnu_relro(phdr, phnum, load_bias) < 0) {
3386 DL_ERR("can't enable GNU RELRO protection for \"%s\": %s",
3387 get_realpath(), strerror(errno));
3388 return false;
3389 }
3390 return true;
3391}
3392
Dimitry Ivanov4cabfaa2017-03-07 11:19:05 -08003393static void init_default_namespace_no_config(bool is_asan) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003394 g_default_namespace.set_isolated(false);
Dimitry Ivanov77ad6422017-03-06 13:02:29 -08003395 auto default_ld_paths = is_asan ? kAsanDefaultLdPaths : kDefaultLdPaths;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003396
neo.chae2589f9d2016-10-04 11:00:27 +09003397 char real_path[PATH_MAX];
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003398 std::vector<std::string> ld_default_paths;
Dimitry Ivanov77ad6422017-03-06 13:02:29 -08003399 for (size_t i = 0; default_ld_paths[i] != nullptr; ++i) {
3400 if (realpath(default_ld_paths[i], real_path) != nullptr) {
neo.chae2589f9d2016-10-04 11:00:27 +09003401 ld_default_paths.push_back(real_path);
3402 } else {
Dimitry Ivanov77ad6422017-03-06 13:02:29 -08003403 ld_default_paths.push_back(default_ld_paths[i]);
neo.chae2589f9d2016-10-04 11:00:27 +09003404 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003405 }
3406
3407 g_default_namespace.set_default_library_paths(std::move(ld_default_paths));
Dimitry Ivanov4cabfaa2017-03-07 11:19:05 -08003408}
3409
3410void init_default_namespace(const char* executable_path) {
3411 g_default_namespace.set_name("(default)");
3412
3413 soinfo* somain = solist_get_somain();
3414
3415 const char *interp = phdr_table_get_interpreter_name(somain->phdr, somain->phnum,
3416 somain->load_bias);
3417 const char* bname = basename(interp);
3418
3419 g_is_asan = bname != nullptr &&
3420 (strcmp(bname, "linker_asan") == 0 ||
3421 strcmp(bname, "linker_asan64") == 0);
3422
3423 const Config* config = nullptr;
3424
3425 std::string error_msg;
3426
3427 if (!Config::read_binary_config(kLdConfigFilePath,
3428 executable_path,
3429 g_is_asan,
3430 &config,
3431 &error_msg)) {
3432 if (!error_msg.empty()) {
3433 DL_WARN("error reading config file \"%s\" for \"%s\" (will use default configuration): %s",
3434 kLdConfigFilePath,
3435 executable_path,
3436 error_msg.c_str());
3437 }
3438 config = nullptr;
3439 }
3440
3441 if (config == nullptr) {
3442 init_default_namespace_no_config(g_is_asan);
3443 return;
3444 }
3445
3446 const auto& namespace_configs = config->namespace_configs();
3447 std::unordered_map<std::string, android_namespace_t*> namespaces;
3448
3449 // 1. Initialize default namespace
3450 const NamespaceConfig* default_ns_config = config->default_namespace_config();
3451
3452 g_default_namespace.set_isolated(default_ns_config->isolated());
3453 g_default_namespace.set_default_library_paths(default_ns_config->search_paths());
3454 g_default_namespace.set_permitted_paths(default_ns_config->permitted_paths());
3455
3456 namespaces[default_ns_config->name()] = &g_default_namespace;
3457
3458 // 2. Initialize other namespaces
3459
3460 for (auto& ns_config : namespace_configs) {
3461 if (namespaces.find(ns_config->name()) != namespaces.end()) {
3462 continue;
3463 }
3464
3465 android_namespace_t* ns = new (g_namespace_allocator.alloc()) android_namespace_t();
3466 ns->set_name(ns_config->name());
3467 ns->set_isolated(ns_config->isolated());
3468 ns->set_default_library_paths(ns_config->search_paths());
3469 ns->set_permitted_paths(ns_config->permitted_paths());
3470
3471 namespaces[ns_config->name()] = ns;
3472 }
3473
3474 // 3. Establish links between namespaces
3475 for (auto& ns_config : namespace_configs) {
3476 auto it_from = namespaces.find(ns_config->name());
3477 CHECK(it_from != namespaces.end());
3478 android_namespace_t* namespace_from = it_from->second;
3479 for (const NamespaceLinkConfig& ns_link : ns_config->links()) {
3480 auto it_to = namespaces.find(ns_link.ns_name());
3481 CHECK(it_to != namespaces.end());
3482 android_namespace_t* namespace_to = it_to->second;
3483 link_namespaces(namespace_from, namespace_to, ns_link.shared_libs().c_str());
3484 }
3485 }
3486 // we can no longer rely on the fact that libdl.so is part of default namespace
3487 // this is why we want to add ld-android.so to all namespaces from ld.config.txt
3488 soinfo* ld_android_so = solist_get_head();
3489 for (auto it : namespaces) {
3490 it.second->add_soinfo(ld_android_so);
3491 // TODO (dimitry): somain and ld_preloads should probably be added to all of these namespaces too?
3492 }
3493
3494 set_application_target_sdk_version(config->target_sdk_version());
3495}