blob: 033aa8fb232da064d556c5b9377a8b54e3ca3236 [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.
Mingwei Shibe910522015-11-12 07:02:14 +000047#include "private/bionic_globals.h"
Elliott Hugheseb847bc2013-10-09 15:50:50 -070048#include "private/bionic_tls.h"
49#include "private/KernelArgumentBlock.h"
50#include "private/ScopedPthreadMutexLocker.h"
Dmitriy Ivanov14669a92014-09-05 16:42:53 -070051#include "private/ScopeGuard.h"
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080052
53#include "linker.h"
Dmitriy Ivanovc9ce70d2015-03-10 15:30:26 -070054#include "linker_block_allocator.h"
Dimitry Ivanov6b788ee2016-02-17 16:08:03 -080055#include "linker_gdb_support.h"
Dimitry Ivanov48ec2882016-08-04 11:50:36 -070056#include "linker_globals.h"
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080057#include "linker_debug.h"
Dimitry Ivanov769b33f2016-07-21 11:33:40 -070058#include "linker_dlwarning.h"
Dimitry Ivanovb943f302016-08-03 16:00:10 -070059#include "linker_namespaces.h"
Dmitriy Ivanov18870d32015-04-22 13:10:04 -070060#include "linker_sleb128.h"
David 'Digit' Turner23363ed2012-06-18 18:13:49 +020061#include "linker_phdr.h"
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -080062#include "linker_relocs.h"
Dmitriy Ivanovfa26eee2015-02-03 16:06:47 -080063#include "linker_reloc_iterators.h"
Dmitriy Ivanova1feb112015-10-01 18:41:57 -070064#include "linker_utils.h"
tony.ys_liub4474402015-07-29 18:00:22 +080065
Elliott Hughes939a7e02015-12-04 15:27:46 -080066#include "android-base/strings.h"
Dimitry Ivanovb996d602016-07-11 18:11:39 -070067#include "android-base/stringprintf.h"
Josh Gao3cc387e2016-06-15 18:33:26 -070068#include "debuggerd/client.h"
Simon Baldwinaef71952015-01-16 13:22:54 +000069#include "ziparchive/zip_archive.h"
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080070
Josh Gao93c0f5e2015-10-06 11:08:13 -070071extern void __libc_init_globals(KernelArgumentBlock&);
Elliott Hughes1801db32015-06-08 18:04:00 -070072extern void __libc_init_AT_SECURE(KernelArgumentBlock&);
73
Mingwei Shibe910522015-11-12 07:02:14 +000074extern "C" void _start();
75
Elliott Hughes1801db32015-06-08 18:04:00 -070076// Override macros to use C++ style casts.
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -080077#undef ELF_ST_TYPE
78#define ELF_ST_TYPE(x) (static_cast<uint32_t>(x) & 0xf)
79
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -070080static android_namespace_t* g_anonymous_namespace = &g_default_namespace;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -070081
Elliott Hughes0266ae52014-02-10 17:46:57 -080082static ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080083
Dmitriy Ivanov600bc3c2015-03-10 15:43:50 -070084static LinkerTypeAllocator<soinfo> g_soinfo_allocator;
85static LinkerTypeAllocator<LinkedListEntry<soinfo>> g_soinfo_links_allocator;
Magnus Malmbornba98d922012-09-12 13:00:55 +020086
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -070087static LinkerTypeAllocator<android_namespace_t> g_namespace_allocator;
Dimitry Ivanovaca299a2016-04-11 12:42:58 -070088static LinkerTypeAllocator<LinkedListEntry<android_namespace_t>> g_namespace_list_allocator;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -070089
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -070090static soinfo* solist;
91static soinfo* sonext;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -070092static soinfo* somain; // main process, always the one after libdl_info
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080093
Elliott Hughes4eeb1f12013-10-25 17:38:02 -070094#if defined(__LP64__)
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -070095static const char* const kSystemLibDir = "/system/lib64";
96static const char* const kVendorLibDir = "/vendor/lib64";
97static const char* const kAsanSystemLibDir = "/data/lib64";
98static const char* const kAsanVendorLibDir = "/data/vendor/lib64";
Elliott Hughes011bc0b2013-10-08 14:27:10 -070099#else
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700100static const char* const kSystemLibDir = "/system/lib";
101static const char* const kVendorLibDir = "/vendor/lib";
102static const char* const kAsanSystemLibDir = "/data/lib";
103static const char* const kAsanVendorLibDir = "/data/vendor/lib";
Elliott Hughes011bc0b2013-10-08 14:27:10 -0700104#endif
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700105
106static const char* const kDefaultLdPaths[] = {
107 kSystemLibDir,
108 kVendorLibDir,
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700109 nullptr
Elliott Hughes124fae92012-10-31 14:20:03 -0700110};
David Bartleybc3a5c22009-06-02 18:27:28 -0700111
Evgenii Stepanovd640b222015-07-10 17:54:01 -0700112static const char* const kAsanDefaultLdPaths[] = {
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700113 kAsanSystemLibDir,
114 kSystemLibDir,
115 kAsanVendorLibDir,
116 kVendorLibDir,
Evgenii Stepanovd640b222015-07-10 17:54:01 -0700117 nullptr
118};
119
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700120// Is ASAN enabled?
121static bool g_is_asan = false;
122
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700123static bool is_system_library(const std::string& realpath) {
124 for (const auto& dir : g_default_namespace.get_default_library_paths()) {
125 if (file_is_in_dir(realpath, dir)) {
126 return true;
127 }
128 }
129 return false;
130}
131
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700132// Checks if the file exists and not a directory.
133static bool file_exists(const char* path) {
Dimitry Ivanov4cf70242016-08-11 11:11:52 -0700134 struct stat s;
135
136 if (stat(path, &s) != 0) {
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700137 return false;
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700138 }
Dimitry Ivanov4cf70242016-08-11 11:11:52 -0700139
140 return S_ISREG(s.st_mode);
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700141}
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700142
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700143// TODO(dimitry): The grey-list is a workaround for http://b/26394120 ---
144// gradually remove libraries from this list until it is gone.
145static bool is_greylisted(const char* name, const soinfo* needed_by) {
146 static const char* const kLibraryGreyList[] = {
147 "libandroid_runtime.so",
148 "libbinder.so",
149 "libcrypto.so",
150 "libcutils.so",
151 "libexpat.so",
152 "libgui.so",
153 "libmedia.so",
154 "libnativehelper.so",
155 "libskia.so",
156 "libssl.so",
157 "libstagefright.so",
158 "libsqlite.so",
159 "libui.so",
160 "libutils.so",
161 "libvorbisidec.so",
162 nullptr
163 };
164
165 // limit greylisting to apps targeting sdk version 23 and below
166 if (get_application_target_sdk_version() > 23) {
167 return false;
168 }
169
170 // if the library needed by a system library - implicitly assume it
171 // is greylisted
172
173 if (needed_by != nullptr && is_system_library(needed_by->get_realpath())) {
174 return true;
175 }
176
177 // if this is an absolute path - make sure it points to /system/lib(64)
178 if (name[0] == '/' && dirname(name) == kSystemLibDir) {
179 // and reduce the path to basename
180 name = basename(name);
181 }
182
183 for (size_t i = 0; kLibraryGreyList[i] != nullptr; ++i) {
184 if (strcmp(name, kLibraryGreyList[i]) == 0) {
185 return true;
186 }
187 }
188
189 return false;
190}
191// END OF WORKAROUND
192
Evgenii Stepanovd640b222015-07-10 17:54:01 -0700193static const char* const* g_default_ld_paths;
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700194static std::vector<std::string> g_ld_preload_names;
Elliott Hughesa4aafd12014-01-13 16:37:47 -0800195
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700196static std::vector<soinfo*> g_ld_preloads;
Matt Fischer4fd42c12009-12-31 12:09:10 -0600197
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700198static bool g_public_namespace_initialized;
Dimitry Ivanovb943f302016-08-03 16:00:10 -0700199static soinfo_list_t g_public_namespace;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700200
Dimitry Ivanovb996d602016-07-11 18:11:39 -0700201int g_ld_debug_verbosity;
202abort_msg_t* g_abort_message = nullptr; // For debuggerd.
Dimitry Ivanov55437462016-07-20 15:33:07 -0700203
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800204#if STATS
Elliott Hughesbedfe382012-08-14 14:07:59 -0700205struct linker_stats_t {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700206 int count[kRelocMax];
Elliott Hughesbedfe382012-08-14 14:07:59 -0700207};
208
209static linker_stats_t linker_stats;
210
Dmitriy Ivanov114ff692015-01-14 11:36:38 -0800211void count_relocation(RelocationKind kind) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700212 ++linker_stats.count[kind];
Elliott Hughesbedfe382012-08-14 14:07:59 -0700213}
214#else
Dmitriy Ivanov114ff692015-01-14 11:36:38 -0800215void count_relocation(RelocationKind) {
Elliott Hughesbedfe382012-08-14 14:07:59 -0700216}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800217#endif
218
219#if COUNT_PAGES
Dmitriy Ivanov114ff692015-01-14 11:36:38 -0800220uint32_t bitmask[4096];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800221#endif
222
Elliott Hughesbedfe382012-08-14 14:07:59 -0700223static void notify_gdb_of_load(soinfo* info) {
Dimitry Ivanove97d8ed2016-03-01 15:55:56 -0800224 if (info->is_linker() || info->is_main_executable()) {
225 // gdb already knows about the linker and the main executable.
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700226 return;
227 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800228
Dimitry Ivanov6b788ee2016-02-17 16:08:03 -0800229 link_map* map = &(info->link_map_head);
Nicolas Geoffray0fa54102016-02-18 09:31:24 +0000230
Dimitry Ivanov6b788ee2016-02-17 16:08:03 -0800231 map->l_addr = info->load_bias;
232 // link_map l_name field is not const.
233 map->l_name = const_cast<char*>(info->get_realpath());
234 map->l_ld = info->dynamic;
Nicolas Geoffray0fa54102016-02-18 09:31:24 +0000235
Dimitry Ivanove97d8ed2016-03-01 15:55:56 -0800236 CHECK(map->l_name != nullptr);
237 CHECK(map->l_name[0] != '\0');
238
Dimitry Ivanov6b788ee2016-02-17 16:08:03 -0800239 notify_gdb_of_load(map);
Iliyan Malchev5e12d7e2009-03-24 19:02:00 -0700240}
241
Elliott Hughesbedfe382012-08-14 14:07:59 -0700242static void notify_gdb_of_unload(soinfo* info) {
Dimitry Ivanov6b788ee2016-02-17 16:08:03 -0800243 notify_gdb_of_unload(&(info->link_map_head));
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800244}
245
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -0700246LinkedListEntry<soinfo>* SoinfoListAllocator::alloc() {
247 return g_soinfo_links_allocator.alloc();
248}
249
250void SoinfoListAllocator::free(LinkedListEntry<soinfo>* entry) {
251 g_soinfo_links_allocator.free(entry);
252}
253
Dimitry Ivanovaca299a2016-04-11 12:42:58 -0700254LinkedListEntry<android_namespace_t>* NamespaceListAllocator::alloc() {
255 return g_namespace_list_allocator.alloc();
256}
257
258void NamespaceListAllocator::free(LinkedListEntry<android_namespace_t>* entry) {
259 g_namespace_list_allocator.free(entry);
260}
261
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700262static soinfo* soinfo_alloc(android_namespace_t* ns, const char* name,
263 struct stat* file_stat, off64_t file_offset,
264 uint32_t rtld_flags) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700265 if (strlen(name) >= PATH_MAX) {
Magnus Malmbornba98d922012-09-12 13:00:55 +0200266 DL_ERR("library name \"%s\" too long", name);
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700267 return nullptr;
Magnus Malmbornba98d922012-09-12 13:00:55 +0200268 }
269
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700270 soinfo* si = new (g_soinfo_allocator.alloc()) soinfo(ns, name, file_stat,
271 file_offset, rtld_flags);
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -0700272
Magnus Malmbornba98d922012-09-12 13:00:55 +0200273 sonext->next = si;
274 sonext = si;
275
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -0700276 si->generate_handle();
277 ns->add_soinfo(si);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700278
Elliott Hughesca0c11b2013-03-12 10:40:45 -0700279 TRACE("name %s: allocated soinfo @ %p", name, si);
Magnus Malmbornba98d922012-09-12 13:00:55 +0200280 return si;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800281}
282
Elliott Hughesfaf05ba2014-02-11 16:59:37 -0800283static void soinfo_free(soinfo* si) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700284 if (si == nullptr) {
285 return;
286 }
287
288 if (si->base != 0 && si->size != 0) {
Dimitry Ivanovf45b0e92016-01-15 11:13:35 -0800289 if (!si->is_mapped_by_caller()) {
290 munmap(reinterpret_cast<void*>(si->base), si->size);
291 } else {
292 // remap the region as PROT_NONE, MAP_ANONYMOUS | MAP_NORESERVE
293 mmap(reinterpret_cast<void*>(si->base), si->size, PROT_NONE,
294 MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
295 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700296 }
297
298 soinfo *prev = nullptr, *trav;
299
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700300 TRACE("name %s: freeing soinfo @ %p", si->get_realpath(), si);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700301
302 for (trav = solist; trav != nullptr; trav = trav->next) {
303 if (trav == si) {
304 break;
Elliott Hughes46882792012-08-03 16:49:39 -0700305 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700306 prev = trav;
307 }
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800308
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700309 if (trav == nullptr) {
310 // si was not in solist
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700311 DL_ERR("name \"%s\"@%p is not in solist!", si->get_realpath(), si);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700312 return;
313 }
Elliott Hughes46882792012-08-03 16:49:39 -0700314
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700315 // clear links to/from si
316 si->remove_all_links();
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -0700317
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700318 // prev will never be null, because the first entry in solist is
319 // always the static libdl_info.
320 prev->next = si->next;
321 if (si == sonext) {
322 sonext = prev;
323 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800324
Dmitriy Ivanov609f11b2015-07-08 15:26:46 -0700325 si->~soinfo();
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700326 g_soinfo_allocator.free(si);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800327}
328
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700329static void parse_path(const char* path, const char* delimiters,
330 std::vector<std::string>* resolved_paths) {
331 std::vector<std::string> paths;
332 split_path(path, delimiters, &paths);
333 resolve_paths(paths, resolved_paths);
334}
335
Elliott Hughescade4c32012-12-20 14:42:14 -0800336static void parse_LD_LIBRARY_PATH(const char* path) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700337 std::vector<std::string> ld_libary_paths;
338 parse_path(path, ":", &ld_libary_paths);
339 g_default_namespace.set_ld_library_paths(std::move(ld_libary_paths));
Elliott Hughescade4c32012-12-20 14:42:14 -0800340}
341
342static void parse_LD_PRELOAD(const char* path) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700343 g_ld_preload_names.clear();
344 if (path != nullptr) {
345 // We have historically supported ':' as well as ' ' in LD_PRELOAD.
346 g_ld_preload_names = android::base::Split(path, " :");
Dimitry Ivanovd799b2b2016-05-24 14:29:56 -0700347 std::remove_if(g_ld_preload_names.begin(),
348 g_ld_preload_names.end(),
349 [] (const std::string& s) { return s.empty(); });
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700350 }
Elliott Hughescade4c32012-12-20 14:42:14 -0800351}
352
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700353static bool realpath_fd(int fd, std::string* realpath) {
354 std::vector<char> buf(PATH_MAX), proc_self_fd(PATH_MAX);
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700355 __libc_format_buffer(&proc_self_fd[0], proc_self_fd.size(), "/proc/self/fd/%d", fd);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700356 if (readlink(&proc_self_fd[0], &buf[0], buf.size()) == -1) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700357 PRINT("readlink(\"%s\") failed: %s [fd=%d]", &proc_self_fd[0], strerror(errno), fd);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700358 return false;
359 }
360
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700361 *realpath = &buf[0];
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700362 return true;
363}
364
Elliott Hughes4eeb1f12013-10-25 17:38:02 -0700365#if defined(__arm__)
Elliott Hughes46882792012-08-03 16:49:39 -0700366
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700367// For a given PC, find the .so that it belongs to.
368// Returns the base address of the .ARM.exidx section
369// for that .so, and the number of 8-byte entries
370// in that section (via *pcount).
371//
372// Intended to be called by libc's __gnu_Unwind_Find_exidx().
373//
374// This function is exposed via dlfcn.cpp and libdl.so.
Elliott Hughesfaf05ba2014-02-11 16:59:37 -0800375_Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr pc, int* pcount) {
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -0800376 uintptr_t addr = reinterpret_cast<uintptr_t>(pc);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800377
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700378 for (soinfo* si = solist; si != 0; si = si->next) {
379 if ((addr >= si->base) && (addr < (si->base + si->size))) {
380 *pcount = si->ARM_exidx_count;
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -0800381 return reinterpret_cast<_Unwind_Ptr>(si->ARM_exidx);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800382 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700383 }
384 *pcount = 0;
385 return nullptr;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800386}
Elliott Hughes46882792012-08-03 16:49:39 -0700387
Christopher Ferris24053a42013-08-19 17:45:09 -0700388#endif
Elliott Hughes46882792012-08-03 16:49:39 -0700389
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700390// Here, we only have to provide a callback to iterate across all the
391// loaded libraries. gcc_eh does the rest.
Dmitriy Ivanov7271caf2015-06-29 14:48:25 -0700392int do_dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void* data) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700393 int rv = 0;
394 for (soinfo* si = solist; si != nullptr; si = si->next) {
395 dl_phdr_info dl_info;
396 dl_info.dlpi_addr = si->link_map_head.l_addr;
397 dl_info.dlpi_name = si->link_map_head.l_name;
398 dl_info.dlpi_phdr = si->phdr;
399 dl_info.dlpi_phnum = si->phnum;
400 rv = cb(&dl_info, sizeof(dl_phdr_info), data);
401 if (rv != 0) {
402 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800403 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700404 }
405 return rv;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800406}
Elliott Hughes46882792012-08-03 16:49:39 -0700407
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800408
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700409bool soinfo_do_lookup(soinfo* si_from, const char* name, const version_info* vi,
Dimitry Ivanovb943f302016-08-03 16:00:10 -0700410 soinfo** si_found_in, const soinfo_list_t& global_group,
411 const soinfo_list_t& local_group, const ElfW(Sym)** symbol) {
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800412 SymbolName symbol_name(name);
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700413 const ElfW(Sym)* s = nullptr;
Iliyan Malchev6ed80c82009-09-28 19:38:04 -0700414
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -0700415 /* "This element's presence in a shared object library alters the dynamic linker's
416 * symbol resolution algorithm for references within the library. Instead of starting
417 * a symbol search with the executable file, the dynamic linker starts from the shared
418 * object itself. If the shared object fails to supply the referenced symbol, the
419 * dynamic linker then searches the executable file and other shared objects as usual."
420 *
421 * http://www.sco.com/developers/gabi/2012-12-31/ch5.dynamic.html
422 *
423 * Note that this is unlikely since static linker avoids generating
424 * relocations for -Bsymbolic linked dynamic executables.
425 */
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700426 if (si_from->has_DT_SYMBOLIC) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700427 DEBUG("%s: looking up %s in local scope (DT_SYMBOLIC)", si_from->get_realpath(), name);
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700428 if (!si_from->find_symbol_by_name(symbol_name, vi, &s)) {
429 return false;
430 }
431
Dmitriy Ivanov8f61d992014-09-16 14:31:06 -0700432 if (s != nullptr) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700433 *si_found_in = si_from;
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -0700434 }
435 }
436
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700437 // 1. Look for it in global_group
438 if (s == nullptr) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700439 bool error = false;
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700440 global_group.visit([&](soinfo* global_si) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700441 DEBUG("%s: looking up %s in %s (from global group)",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700442 si_from->get_realpath(), name, global_si->get_realpath());
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700443 if (!global_si->find_symbol_by_name(symbol_name, vi, &s)) {
444 error = true;
445 return false;
446 }
447
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -0700448 if (s != nullptr) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700449 *si_found_in = global_si;
450 return false;
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -0700451 }
Dmitriy Ivanovc2048942014-08-29 10:15:25 -0700452
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700453 return true;
454 });
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700455
456 if (error) {
457 return false;
458 }
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -0700459 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700460
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700461 // 2. Look for it in the local group
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700462 if (s == nullptr) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700463 bool error = false;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700464 local_group.visit([&](soinfo* local_si) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700465 if (local_si == si_from && si_from->has_DT_SYMBOLIC) {
Dmitriy Ivanove47b3f82014-10-23 14:19:07 -0700466 // we already did this - skip
467 return true;
468 }
469
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700470 DEBUG("%s: looking up %s in %s (from local group)",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700471 si_from->get_realpath(), name, local_si->get_realpath());
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700472 if (!local_si->find_symbol_by_name(symbol_name, vi, &s)) {
473 error = true;
474 return false;
475 }
476
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700477 if (s != nullptr) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700478 *si_found_in = local_si;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700479 return false;
480 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700481
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700482 return true;
483 });
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700484
485 if (error) {
486 return false;
487 }
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700488 }
489
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700490 if (s != nullptr) {
491 TRACE_TYPE(LOOKUP, "si %s sym %s s->st_value = %p, "
492 "found in %s, base = %p, load bias = %p",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700493 si_from->get_realpath(), name, reinterpret_cast<void*>(s->st_value),
494 (*si_found_in)->get_realpath(), reinterpret_cast<void*>((*si_found_in)->base),
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700495 reinterpret_cast<void*>((*si_found_in)->load_bias));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700496 }
Iliyan Malchev6ed80c82009-09-28 19:38:04 -0700497
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700498 *symbol = s;
499 return true;
Iliyan Malchev6ed80c82009-09-28 19:38:04 -0700500}
501
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -0800502class ProtectedDataGuard {
503 public:
504 ProtectedDataGuard() {
505 if (ref_count_++ == 0) {
506 protect_data(PROT_READ | PROT_WRITE);
507 }
508 }
509
510 ~ProtectedDataGuard() {
511 if (ref_count_ == 0) { // overflow
512 __libc_fatal("Too many nested calls to dlopen()");
513 }
514
515 if (--ref_count_ == 0) {
516 protect_data(PROT_READ);
517 }
518 }
519 private:
520 void protect_data(int protection) {
521 g_soinfo_allocator.protect_all(protection);
522 g_soinfo_links_allocator.protect_all(protection);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700523 g_namespace_allocator.protect_all(protection);
Dimitry Ivanovaca299a2016-04-11 12:42:58 -0700524 g_namespace_list_allocator.protect_all(protection);
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -0800525 }
526
527 static size_t ref_count_;
528};
529
530size_t ProtectedDataGuard::ref_count_ = 0;
531
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700532// Each size has it's own allocator.
533template<size_t size>
534class SizeBasedAllocator {
535 public:
536 static void* alloc() {
537 return allocator_.alloc();
538 }
Dmitriy Ivanov4bea4982014-08-29 14:01:48 -0700539
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700540 static void free(void* ptr) {
541 allocator_.free(ptr);
542 }
Dmitriy Ivanov4bea4982014-08-29 14:01:48 -0700543
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700544 private:
545 static LinkerBlockAllocator allocator_;
546};
547
548template<size_t size>
549LinkerBlockAllocator SizeBasedAllocator<size>::allocator_(size);
550
551template<typename T>
552class TypeBasedAllocator {
553 public:
554 static T* alloc() {
555 return reinterpret_cast<T*>(SizeBasedAllocator<sizeof(T)>::alloc());
556 }
557
558 static void free(T* ptr) {
559 SizeBasedAllocator<sizeof(T)>::free(ptr);
560 }
561};
562
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700563class LoadTask {
564 public:
565 struct deleter_t {
566 void operator()(LoadTask* t) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700567 t->~LoadTask();
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700568 TypeBasedAllocator<LoadTask>::free(t);
569 }
570 };
571
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700572 static deleter_t deleter;
573
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700574 static LoadTask* create(const char* name, soinfo* needed_by,
575 std::unordered_map<const soinfo*, ElfReader>* readers_map) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700576 LoadTask* ptr = TypeBasedAllocator<LoadTask>::alloc();
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700577 return new (ptr) LoadTask(name, needed_by, readers_map);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700578 }
579
580 const char* get_name() const {
581 return name_;
582 }
583
584 soinfo* get_needed_by() const {
585 return needed_by_;
586 }
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700587
588 soinfo* get_soinfo() const {
589 return si_;
590 }
591
592 void set_soinfo(soinfo* si) {
593 si_ = si;
594 }
595
596 off64_t get_file_offset() const {
597 return file_offset_;
598 }
599
600 void set_file_offset(off64_t offset) {
601 file_offset_ = offset;
602 }
603
604 int get_fd() const {
605 return fd_;
606 }
607
608 void set_fd(int fd, bool assume_ownership) {
609 fd_ = fd;
610 close_fd_ = assume_ownership;
611 }
612
613 const android_dlextinfo* get_extinfo() const {
614 return extinfo_;
615 }
616
617 void set_extinfo(const android_dlextinfo* extinfo) {
618 extinfo_ = extinfo;
619 }
620
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700621 bool is_dt_needed() const {
622 return is_dt_needed_;
623 }
624
625 void set_dt_needed(bool is_dt_needed) {
626 is_dt_needed_ = is_dt_needed;
627 }
628
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700629 const ElfReader& get_elf_reader() const {
630 CHECK(si_ != nullptr);
631 return (*elf_readers_map_)[si_];
632 }
633
634 ElfReader& get_elf_reader() {
635 CHECK(si_ != nullptr);
636 return (*elf_readers_map_)[si_];
637 }
638
639 std::unordered_map<const soinfo*, ElfReader>* get_readers_map() {
640 return elf_readers_map_;
641 }
642
643 bool read(const char* realpath, off64_t file_size) {
644 ElfReader& elf_reader = get_elf_reader();
645 return elf_reader.Read(realpath, fd_, file_offset_, file_size);
646 }
647
648 bool load() {
649 ElfReader& elf_reader = get_elf_reader();
650 if (!elf_reader.Load(extinfo_)) {
651 return false;
652 }
653
654 si_->base = elf_reader.load_start();
655 si_->size = elf_reader.load_size();
Dimitry Ivanovf45b0e92016-01-15 11:13:35 -0800656 si_->set_mapped_by_caller(elf_reader.is_mapped_by_caller());
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700657 si_->load_bias = elf_reader.load_bias();
658 si_->phnum = elf_reader.phdr_count();
659 si_->phdr = elf_reader.loaded_phdr();
660
661 return true;
662 }
663
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700664 private:
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700665 LoadTask(const char* name, soinfo* needed_by,
666 std::unordered_map<const soinfo*, ElfReader>* readers_map)
667 : name_(name), needed_by_(needed_by), si_(nullptr),
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700668 fd_(-1), close_fd_(false), file_offset_(0), elf_readers_map_(readers_map),
669 is_dt_needed_(false) {}
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700670
671 ~LoadTask() {
672 if (fd_ != -1 && close_fd_) {
673 close(fd_);
674 }
675 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700676
677 const char* name_;
678 soinfo* needed_by_;
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700679 soinfo* si_;
680 const android_dlextinfo* extinfo_;
681 int fd_;
682 bool close_fd_;
683 off64_t file_offset_;
684 std::unordered_map<const soinfo*, ElfReader>* elf_readers_map_;
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700685 // TODO(dimitry): needed by workaround for http://b/26394120 (the grey-list)
686 bool is_dt_needed_;
687 // END OF WORKAROUND
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700688
689 DISALLOW_IMPLICIT_CONSTRUCTORS(LoadTask);
690};
691
Ningsheng Jiane93be992014-09-16 15:22:10 +0800692LoadTask::deleter_t LoadTask::deleter;
693
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700694template <typename T>
695using linked_list_t = LinkedList<T, TypeBasedAllocator<LinkedListEntry<T>>>;
696
697typedef linked_list_t<soinfo> SoinfoLinkedList;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700698typedef linked_list_t<const char> StringLinkedList;
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700699typedef std::vector<LoadTask*> LoadTaskList;
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700700
Dmitriy Ivanovaa0f2bd2014-07-28 17:32:20 -0700701
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700702// This function walks down the tree of soinfo dependencies
703// in breadth-first order and
704// * calls action(soinfo* si) for each node, and
705// * terminates walk if action returns false.
706//
707// walk_dependencies_tree returns false if walk was terminated
708// by the action and true otherwise.
709template<typename F>
710static bool walk_dependencies_tree(soinfo* root_soinfos[], size_t root_soinfos_size, F action) {
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700711 SoinfoLinkedList visit_list;
712 SoinfoLinkedList visited;
713
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700714 for (size_t i = 0; i < root_soinfos_size; ++i) {
715 visit_list.push_back(root_soinfos[i]);
716 }
717
718 soinfo* si;
719 while ((si = visit_list.pop_front()) != nullptr) {
720 if (visited.contains(si)) {
Dmitriy Ivanov042426b2014-08-12 21:02:13 -0700721 continue;
722 }
723
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700724 if (!action(si)) {
725 return false;
Dmitriy Ivanovaa0f2bd2014-07-28 17:32:20 -0700726 }
727
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700728 visited.push_back(si);
729
730 si->get_children().for_each([&](soinfo* child) {
Dmitriy Ivanovaa0f2bd2014-07-28 17:32:20 -0700731 visit_list.push_back(child);
732 });
733 }
734
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700735 return true;
736}
737
738
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700739static const ElfW(Sym)* dlsym_handle_lookup(soinfo* root, soinfo* skip_until,
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800740 soinfo** found, SymbolName& symbol_name,
741 const version_info* vi) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700742 const ElfW(Sym)* result = nullptr;
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700743 bool skip_lookup = skip_until != nullptr;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700744
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700745 walk_dependencies_tree(&root, 1, [&](soinfo* current_soinfo) {
746 if (skip_lookup) {
747 skip_lookup = current_soinfo != skip_until;
748 return true;
749 }
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;
753 return false;
754 }
755
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700756 if (result != nullptr) {
757 *found = current_soinfo;
758 return false;
759 }
760
761 return true;
762 });
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 Ivanov4a2c5aa2015-12-10 16:08:14 -0800776static const ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found,
777 const char* name, const version_info* vi) {
Dmitriy Ivanovf439b5a2015-05-30 13:04:39 -0700778 // According to man dlopen(3) and posix docs in the case when si is handle
779 // of the main executable we need to search not only in the executable and its
780 // dependencies but also in all libraries loaded with RTLD_GLOBAL.
781 //
782 // Since RTLD_GLOBAL is always set for the main executable and all dt_needed shared
783 // libraries and they are loaded in breath-first (correct) order we can just execute
784 // dlsym(RTLD_DEFAULT, ...); instead of doing two stage lookup.
785 if (si == somain) {
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800786 return dlsym_linear_lookup(&g_default_namespace, name, vi, found, nullptr, RTLD_DEFAULT);
Dmitriy Ivanovf439b5a2015-05-30 13:04:39 -0700787 }
788
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700789 SymbolName symbol_name(name);
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800790 return dlsym_handle_lookup(si, nullptr, found, symbol_name, vi);
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700791}
792
Brian Carlstromd4ee82d2013-02-28 15:58:45 -0800793/* This is used by dlsym(3) to performs a global symbol lookup. If the
794 start value is null (for RTLD_DEFAULT), the search starts at the
795 beginning of the global solist. Otherwise the search starts at the
796 specified soinfo (for RTLD_NEXT).
Iliyan Malchev6ed80c82009-09-28 19:38:04 -0700797 */
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800798static const ElfW(Sym)* dlsym_linear_lookup(android_namespace_t* ns,
799 const char* name,
800 const version_info* vi,
801 soinfo** found,
802 soinfo* caller,
803 void* handle) {
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800804 SymbolName symbol_name(name);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800805
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -0700806 auto& soinfo_list = ns->soinfo_list();
807 auto start = soinfo_list.begin();
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -0700808
809 if (handle == RTLD_NEXT) {
Dmitriy Ivanovb96ac412015-05-22 12:34:42 -0700810 if (caller == nullptr) {
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -0700811 return nullptr;
812 } else {
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -0700813 auto it = soinfo_list.find(caller);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700814 CHECK (it != soinfo_list.end());
815 start = ++it;
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -0700816 }
Elliott Hughescade4c32012-12-20 14:42:14 -0800817 }
818
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700819 const ElfW(Sym)* s = nullptr;
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -0700820 for (auto it = start, end = soinfo_list.end(); it != end; ++it) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700821 soinfo* si = *it;
Dmitriy Ivanov19133522015-06-02 17:36:54 -0700822 // Do not skip RTLD_LOCAL libraries in dlsym(RTLD_DEFAULT, ...)
823 // if the library is opened by application with target api level <= 22
824 // See http://b/21565766
825 if ((si->get_rtld_flags() & RTLD_GLOBAL) == 0 && si->get_target_sdk_version() > 22) {
Dmitriy Ivanove8ba50f2014-09-15 17:00:10 -0700826 continue;
827 }
828
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800829 if (!si->find_symbol_by_name(symbol_name, vi, &s)) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700830 return nullptr;
831 }
832
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700833 if (s != nullptr) {
Elliott Hughescade4c32012-12-20 14:42:14 -0800834 *found = si;
835 break;
Matt Fischer1698d9e2009-12-31 12:17:56 -0600836 }
Elliott Hughescade4c32012-12-20 14:42:14 -0800837 }
Matt Fischer1698d9e2009-12-31 12:17:56 -0600838
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700839 // If not found - use dlsym_handle_lookup for caller's
840 // local_group unless it is part of the global group in which
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -0700841 // case we already did it.
842 if (s == nullptr && caller != nullptr &&
843 (caller->get_rtld_flags() & RTLD_GLOBAL) == 0) {
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700844 return dlsym_handle_lookup(caller->get_local_group_root(),
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800845 (handle == RTLD_NEXT) ? caller : nullptr, found, symbol_name, vi);
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -0700846 }
847
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700848 if (s != nullptr) {
Elliott Hughesc00f2cb2013-10-04 17:01:33 -0700849 TRACE_TYPE(LOOKUP, "%s s->st_value = %p, found->base = %p",
850 name, reinterpret_cast<void*>(s->st_value), reinterpret_cast<void*>((*found)->base));
Elliott Hughescade4c32012-12-20 14:42:14 -0800851 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800852
Elliott Hughescade4c32012-12-20 14:42:14 -0800853 return s;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800854}
855
Kito Chengfa8c05d2013-03-12 14:58:06 +0800856soinfo* find_containing_library(const void* p) {
Elliott Hughes0266ae52014-02-10 17:46:57 -0800857 ElfW(Addr) address = reinterpret_cast<ElfW(Addr)>(p);
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700858 for (soinfo* si = solist; si != nullptr; si = si->next) {
Kito Chengfa8c05d2013-03-12 14:58:06 +0800859 if (address >= si->base && address - si->base < si->size) {
860 return si;
Matt Fischere2a8b1f2009-12-31 12:17:40 -0600861 }
Kito Chengfa8c05d2013-03-12 14:58:06 +0800862 }
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700863 return nullptr;
Matt Fischere2a8b1f2009-12-31 12:17:40 -0600864}
865
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700866class ZipArchiveCache {
867 public:
868 ZipArchiveCache() {}
869 ~ZipArchiveCache();
870
871 bool get_or_open(const char* zip_path, ZipArchiveHandle* handle);
872 private:
873 DISALLOW_COPY_AND_ASSIGN(ZipArchiveCache);
874
875 std::unordered_map<std::string, ZipArchiveHandle> cache_;
876};
877
878bool ZipArchiveCache::get_or_open(const char* zip_path, ZipArchiveHandle* handle) {
879 std::string key(zip_path);
880
881 auto it = cache_.find(key);
882 if (it != cache_.end()) {
883 *handle = it->second;
884 return true;
885 }
886
887 int fd = TEMP_FAILURE_RETRY(open(zip_path, O_RDONLY | O_CLOEXEC));
888 if (fd == -1) {
889 return false;
890 }
891
892 if (OpenArchiveFd(fd, "", handle) != 0) {
893 // invalid zip-file (?)
Yabin Cui722072d2016-03-21 17:10:12 -0700894 CloseArchive(handle);
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700895 close(fd);
896 return false;
897 }
898
899 cache_[key] = *handle;
900 return true;
901}
902
903ZipArchiveCache::~ZipArchiveCache() {
Dmitriy Ivanov5dce8942015-10-13 12:14:16 -0700904 for (const auto& it : cache_) {
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700905 CloseArchive(it.second);
906 }
907}
908
909static int open_library_in_zipfile(ZipArchiveCache* zip_archive_cache,
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700910 const char* const input_path,
911 off64_t* file_offset, std::string* realpath) {
912 std::string normalized_path;
913 if (!normalize_path(input_path, &normalized_path)) {
914 return -1;
915 }
916
917 const char* const path = normalized_path.c_str();
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700918 TRACE("Trying zip file open from path \"%s\" -> normalized \"%s\"", input_path, path);
Simon Baldwinaef71952015-01-16 13:22:54 +0000919
Dmitriy Ivanov402a7502015-06-09 13:46:51 -0700920 // Treat an '!/' separator inside a path as the separator between the name
Simon Baldwinaef71952015-01-16 13:22:54 +0000921 // of the zip file on disk and the subdirectory to search within it.
Dmitriy Ivanov402a7502015-06-09 13:46:51 -0700922 // For example, if path is "foo.zip!/bar/bas/x.so", then we search for
Simon Baldwinaef71952015-01-16 13:22:54 +0000923 // "bar/bas/x.so" within "foo.zip".
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700924 const char* const separator = strstr(path, kZipFileSeparator);
Simon Baldwinaef71952015-01-16 13:22:54 +0000925 if (separator == nullptr) {
926 return -1;
Elliott Hughes124fae92012-10-31 14:20:03 -0700927 }
Simon Baldwinaef71952015-01-16 13:22:54 +0000928
929 char buf[512];
930 if (strlcpy(buf, path, sizeof(buf)) >= sizeof(buf)) {
931 PRINT("Warning: ignoring very long library path: %s", path);
932 return -1;
933 }
934
935 buf[separator - path] = '\0';
936
937 const char* zip_path = buf;
Dmitriy Ivanov402a7502015-06-09 13:46:51 -0700938 const char* file_path = &buf[separator - path + 2];
Simon Baldwinaef71952015-01-16 13:22:54 +0000939 int fd = TEMP_FAILURE_RETRY(open(zip_path, O_RDONLY | O_CLOEXEC));
940 if (fd == -1) {
941 return -1;
942 }
943
944 ZipArchiveHandle handle;
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700945 if (!zip_archive_cache->get_or_open(zip_path, &handle)) {
Simon Baldwinaef71952015-01-16 13:22:54 +0000946 // invalid zip-file (?)
947 close(fd);
948 return -1;
949 }
950
Simon Baldwinaef71952015-01-16 13:22:54 +0000951 ZipEntry entry;
952
Yusuke Sato56f40fb2015-06-25 14:56:07 -0700953 if (FindEntry(handle, ZipString(file_path), &entry) != 0) {
Simon Baldwinaef71952015-01-16 13:22:54 +0000954 // Entry was not found.
955 close(fd);
956 return -1;
957 }
958
959 // Check if it is properly stored
960 if (entry.method != kCompressStored || (entry.offset % PAGE_SIZE) != 0) {
961 close(fd);
962 return -1;
963 }
964
965 *file_offset = entry.offset;
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700966
967 if (realpath_fd(fd, realpath)) {
968 *realpath += separator;
969 } else {
970 PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.",
971 normalized_path.c_str());
972 *realpath = normalized_path;
973 }
974
Simon Baldwinaef71952015-01-16 13:22:54 +0000975 return fd;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800976}
977
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700978static bool format_path(char* buf, size_t buf_size, const char* path, const char* name) {
979 int n = __libc_format_buffer(buf, buf_size, "%s/%s", path, name);
980 if (n < 0 || n >= static_cast<int>(buf_size)) {
981 PRINT("Warning: ignoring very long library path: %s/%s", path, name);
982 return false;
983 }
Simon Baldwinaef71952015-01-16 13:22:54 +0000984
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700985 return true;
986}
987
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700988static int open_library_on_paths(ZipArchiveCache* zip_archive_cache,
989 const char* name, off64_t* file_offset,
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700990 const std::vector<std::string>& paths,
991 std::string* realpath) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700992 for (const auto& path : paths) {
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700993 char buf[512];
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700994 if (!format_path(buf, sizeof(buf), path.c_str(), name)) {
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700995 continue;
996 }
997
998 int fd = -1;
Dmitriy Ivanov730ed9d2015-07-16 04:52:06 -0700999 if (strstr(buf, kZipFileSeparator) != nullptr) {
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001000 fd = open_library_in_zipfile(zip_archive_cache, buf, file_offset, realpath);
Simon Baldwinaef71952015-01-16 13:22:54 +00001001 }
1002
1003 if (fd == -1) {
1004 fd = TEMP_FAILURE_RETRY(open(buf, O_RDONLY | O_CLOEXEC));
1005 if (fd != -1) {
1006 *file_offset = 0;
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001007 if (!realpath_fd(fd, realpath)) {
1008 PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.", buf);
1009 *realpath = buf;
1010 }
Simon Baldwinaef71952015-01-16 13:22:54 +00001011 }
1012 }
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07001013
1014 if (fd != -1) {
1015 return fd;
1016 }
Simon Baldwinaef71952015-01-16 13:22:54 +00001017 }
1018
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07001019 return -1;
Simon Baldwinaef71952015-01-16 13:22:54 +00001020}
1021
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001022static int open_library(android_namespace_t* ns,
1023 ZipArchiveCache* zip_archive_cache,
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001024 const char* name, soinfo *needed_by,
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001025 off64_t* file_offset, std::string* realpath) {
Elliott Hughesca0c11b2013-03-12 10:40:45 -07001026 TRACE("[ opening %s ]", name);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001027
Elliott Hughes124fae92012-10-31 14:20:03 -07001028 // 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 -07001029 if (strchr(name, '/') != nullptr) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001030 int fd = -1;
1031
Dmitriy Ivanov730ed9d2015-07-16 04:52:06 -07001032 if (strstr(name, kZipFileSeparator) != nullptr) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001033 fd = open_library_in_zipfile(zip_archive_cache, name, file_offset, realpath);
1034 }
1035
1036 if (fd == -1) {
1037 fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_CLOEXEC));
Simon Baldwinaef71952015-01-16 13:22:54 +00001038 if (fd != -1) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001039 *file_offset = 0;
1040 if (!realpath_fd(fd, realpath)) {
1041 PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.", name);
1042 *realpath = name;
1043 }
Simon Baldwinaef71952015-01-16 13:22:54 +00001044 }
1045 }
1046
Dmitriy Ivanove44fffd2015-03-17 17:12:18 -07001047 return fd;
Elliott Hughes124fae92012-10-31 14:20:03 -07001048 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001049
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001050 // Otherwise we try LD_LIBRARY_PATH first, and fall back to the default library path
1051 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 -07001052 if (fd == -1 && needed_by != nullptr) {
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001053 fd = open_library_on_paths(zip_archive_cache, name, file_offset, needed_by->get_dt_runpath(), realpath);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001054 // Check if the library is accessible
1055 if (fd != -1 && !ns->is_accessible(*realpath)) {
1056 fd = -1;
1057 }
Evgenii Stepanov68650822015-06-10 13:38:39 -07001058 }
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001059
Elliott Hughes124fae92012-10-31 14:20:03 -07001060 if (fd == -1) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001061 fd = open_library_on_paths(zip_archive_cache, name, file_offset, ns->get_default_library_paths(), realpath);
Elliott Hughes124fae92012-10-31 14:20:03 -07001062 }
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001063
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001064 // TODO(dimitry): workaround for http://b/26394120 (the grey-list)
1065 if (fd == -1 && ns != &g_default_namespace && is_greylisted(name, needed_by)) {
1066 // try searching for it on default_namespace default_library_path
1067 fd = open_library_on_paths(zip_archive_cache, name, file_offset,
1068 g_default_namespace.get_default_library_paths(), realpath);
1069 }
1070 // END OF WORKAROUND
1071
Elliott Hughes124fae92012-10-31 14:20:03 -07001072 return fd;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001073}
1074
Dmitriy Ivanovd974e882015-05-27 18:29:41 -07001075static const char* fix_dt_needed(const char* dt_needed, const char* sopath __unused) {
1076#if !defined(__LP64__)
1077 // Work around incorrect DT_NEEDED entries for old apps: http://b/21364029
Dmitriy Ivanov19133522015-06-02 17:36:54 -07001078 if (get_application_target_sdk_version() <= 22) {
Dmitriy Ivanovd974e882015-05-27 18:29:41 -07001079 const char* bname = basename(dt_needed);
1080 if (bname != dt_needed) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001081 DL_WARN("library \"%s\" has invalid DT_NEEDED entry \"%s\"", sopath, dt_needed);
1082 add_dlwarning(sopath, "invalid DT_NEEDED entry", dt_needed);
Dmitriy Ivanovd974e882015-05-27 18:29:41 -07001083 }
1084
1085 return bname;
1086 }
1087#endif
1088 return dt_needed;
1089}
1090
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001091template<typename F>
1092static void for_each_dt_needed(const soinfo* si, F action) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001093 for (const ElfW(Dyn)* d = si->dynamic; d->d_tag != DT_NULL; ++d) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001094 if (d->d_tag == DT_NEEDED) {
Dmitriy Ivanovd974e882015-05-27 18:29:41 -07001095 action(fix_dt_needed(si->get_string(d->d_un.d_val), si->get_realpath()));
Dima Zavin2e855792009-05-20 18:28:09 -07001096 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001097 }
1098}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001099
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001100template<typename F>
1101static void for_each_dt_needed(const ElfReader& elf_reader, F action) {
1102 for (const ElfW(Dyn)* d = elf_reader.dynamic(); d->d_tag != DT_NULL; ++d) {
1103 if (d->d_tag == DT_NEEDED) {
1104 action(fix_dt_needed(elf_reader.get_string(d->d_un.d_val), elf_reader.name()));
1105 }
1106 }
1107}
1108
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001109static bool load_library(android_namespace_t* ns,
1110 LoadTask* task,
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001111 LoadTaskList* load_tasks,
1112 int rtld_flags,
1113 const std::string& realpath) {
1114 off64_t file_offset = task->get_file_offset();
1115 const char* name = task->get_name();
1116 const android_dlextinfo* extinfo = task->get_extinfo();
1117
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001118 if ((file_offset % PAGE_SIZE) != 0) {
Dmitriy Ivanova6c12792014-10-21 12:09:18 -07001119 DL_ERR("file offset for the library \"%s\" is not page-aligned: %" PRId64, name, file_offset);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001120 return false;
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001121 }
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001122 if (file_offset < 0) {
1123 DL_ERR("file offset for the library \"%s\" is negative: %" PRId64, name, file_offset);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001124 return false;
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001125 }
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001126
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001127 struct stat file_stat;
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001128 if (TEMP_FAILURE_RETRY(fstat(task->get_fd(), &file_stat)) != 0) {
Dmitriy Ivanova6c12792014-10-21 12:09:18 -07001129 DL_ERR("unable to stat file for the library \"%s\": %s", name, strerror(errno));
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001130 return false;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001131 }
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001132 if (file_offset >= file_stat.st_size) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07001133 DL_ERR("file offset for the library \"%s\" >= file size: %" PRId64 " >= %" PRId64,
1134 name, file_offset, file_stat.st_size);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001135 return false;
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001136 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001137
1138 // Check for symlink and other situations where
Dmitriy Ivanov9b821362015-04-02 16:03:56 -07001139 // file can have different names, unless ANDROID_DLEXT_FORCE_LOAD is set
1140 if (extinfo == nullptr || (extinfo->flags & ANDROID_DLEXT_FORCE_LOAD) == 0) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001141 auto predicate = [&](soinfo* si) {
1142 return si->get_st_dev() != 0 &&
1143 si->get_st_ino() != 0 &&
1144 si->get_st_dev() == file_stat.st_dev &&
1145 si->get_st_ino() == file_stat.st_ino &&
1146 si->get_file_offset() == file_offset;
1147 };
1148
1149 soinfo* si = ns->soinfo_list().find_if(predicate);
1150
1151 // check public namespace
1152 if (si == nullptr) {
1153 si = g_public_namespace.find_if(predicate);
1154 if (si != nullptr) {
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001155 ns->add_soinfo(si);
Dmitriy Ivanov9b821362015-04-02 16:03:56 -07001156 }
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07001157 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001158
1159 if (si != nullptr) {
1160 TRACE("library \"%s\" is already loaded under different name/path \"%s\" - "
1161 "will return existing soinfo", name, si->get_realpath());
1162 task->set_soinfo(si);
1163 return true;
1164 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001165 }
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07001166
Dmitriy Ivanove8ba50f2014-09-15 17:00:10 -07001167 if ((rtld_flags & RTLD_NOLOAD) != 0) {
Dmitriy Ivanova6ac54a2014-09-09 10:21:42 -07001168 DL_ERR("library \"%s\" wasn't loaded and RTLD_NOLOAD prevented it", name);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001169 return false;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001170 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001171
Dimitry Ivanov22840aa2015-12-04 18:28:49 -08001172 if (!ns->is_accessible(realpath)) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001173 // TODO(dimitry): workaround for http://b/26394120 - the grey-list
1174 const soinfo* needed_by = task->is_dt_needed() ? task->get_needed_by() : nullptr;
1175 if (is_greylisted(name, needed_by)) {
1176 // print warning only if needed by non-system library
1177 if (needed_by == nullptr || !is_system_library(needed_by->get_realpath())) {
1178 const soinfo* needed_or_dlopened_by = task->get_needed_by();
1179 const char* sopath = needed_or_dlopened_by == nullptr ? "(unknown)" :
1180 needed_or_dlopened_by->get_realpath();
1181 DL_WARN("library \"%s\" (\"%s\") needed or dlopened by \"%s\" is not accessible for the namespace \"%s\""
1182 " - the access is temporarily granted as a workaround for http://b/26394120, note that the access"
1183 " will be removed in future releases of Android.",
1184 name, realpath.c_str(), sopath, ns->get_name());
1185 add_dlwarning(sopath, "unauthorized access to", name);
1186 }
1187 } else {
1188 // do not load libraries if they are not accessible for the specified namespace.
1189 const char* needed_or_dlopened_by = task->get_needed_by() == nullptr ?
1190 "(unknown)" :
1191 task->get_needed_by()->get_realpath();
Dimitry Ivanovd17a3772016-03-01 13:11:28 -08001192
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001193 DL_ERR("library \"%s\" needed or dlopened by \"%s\" is not accessible for the namespace \"%s\"",
1194 name, needed_or_dlopened_by, ns->get_name());
Dimitry Ivanovd17a3772016-03-01 13:11:28 -08001195
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001196 PRINT("library \"%s\" (\"%s\") needed or dlopened by \"%s\" is not accessible for the"
1197 " namespace: [name=\"%s\", ld_library_paths=\"%s\", default_library_paths=\"%s\","
1198 " permitted_paths=\"%s\"]",
1199 name, realpath.c_str(),
1200 needed_or_dlopened_by,
1201 ns->get_name(),
1202 android::base::Join(ns->get_ld_library_paths(), ':').c_str(),
1203 android::base::Join(ns->get_default_library_paths(), ':').c_str(),
1204 android::base::Join(ns->get_permitted_paths(), ':').c_str());
1205 return false;
1206 }
Dimitry Ivanov22840aa2015-12-04 18:28:49 -08001207 }
1208
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001209 soinfo* si = soinfo_alloc(ns, realpath.c_str(), &file_stat, file_offset, rtld_flags);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001210 if (si == nullptr) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001211 return false;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001212 }
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07001213
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001214 task->set_soinfo(si);
1215
1216 // Read the ELF header and some of the segments.
1217 if (!task->read(realpath.c_str(), file_stat.st_size)) {
Dmitriy Ivanovfd7a91e2015-11-06 10:44:37 -08001218 soinfo_free(si);
1219 task->set_soinfo(nullptr);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001220 return false;
1221 }
1222
1223 // find and set DT_RUNPATH and dt_soname
1224 // Note that these field values are temporary and are
1225 // going to be overwritten on soinfo::prelink_image
1226 // with values from PT_LOAD segments.
1227 const ElfReader& elf_reader = task->get_elf_reader();
1228 for (const ElfW(Dyn)* d = elf_reader.dynamic(); d->d_tag != DT_NULL; ++d) {
1229 if (d->d_tag == DT_RUNPATH) {
1230 si->set_dt_runpath(elf_reader.get_string(d->d_un.d_val));
1231 }
1232 if (d->d_tag == DT_SONAME) {
1233 si->set_soname(elf_reader.get_string(d->d_un.d_val));
1234 }
1235 }
1236
1237 for_each_dt_needed(task->get_elf_reader(), [&](const char* name) {
1238 load_tasks->push_back(LoadTask::create(name, si, task->get_readers_map()));
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001239 });
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07001240
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001241 return true;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001242}
1243
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001244static bool load_library(android_namespace_t* ns,
1245 LoadTask* task,
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001246 ZipArchiveCache* zip_archive_cache,
1247 LoadTaskList* load_tasks,
1248 int rtld_flags) {
1249 const char* name = task->get_name();
1250 soinfo* needed_by = task->get_needed_by();
1251 const android_dlextinfo* extinfo = task->get_extinfo();
1252
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001253 off64_t file_offset;
1254 std::string realpath;
Spencer Low0346ad72015-04-22 18:06:51 -07001255 if (extinfo != nullptr && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) {
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001256 file_offset = 0;
Spencer Low0346ad72015-04-22 18:06:51 -07001257 if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
1258 file_offset = extinfo->library_fd_offset;
1259 }
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001260
1261 if (!realpath_fd(extinfo->library_fd, &realpath)) {
1262 PRINT("warning: unable to get realpath for the library \"%s\" by extinfo->library_fd. "
1263 "Will use given name.", name);
1264 realpath = name;
1265 }
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001266
1267 task->set_fd(extinfo->library_fd, false);
1268 task->set_file_offset(file_offset);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001269 return load_library(ns, task, load_tasks, rtld_flags, realpath);
Spencer Low0346ad72015-04-22 18:06:51 -07001270 }
1271
1272 // Open the file.
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001273 int fd = open_library(ns, zip_archive_cache, name, needed_by, &file_offset, &realpath);
Spencer Low0346ad72015-04-22 18:06:51 -07001274 if (fd == -1) {
1275 DL_ERR("library \"%s\" not found", name);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001276 return false;
Spencer Low0346ad72015-04-22 18:06:51 -07001277 }
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001278
1279 task->set_fd(fd, true);
1280 task->set_file_offset(file_offset);
1281
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001282 return load_library(ns, task, load_tasks, rtld_flags, realpath);
Spencer Low0346ad72015-04-22 18:06:51 -07001283}
1284
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001285// Returns true if library was found and false in 2 cases
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001286// 1. (for default namespace only) The library was found but loaded under different
1287// target_sdk_version (*candidate != nullptr)
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001288// 2. The library was not found by soname (*candidate is nullptr)
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001289static bool find_loaded_library_by_soname(android_namespace_t* ns,
1290 const char* name, soinfo** candidate) {
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001291 *candidate = nullptr;
1292
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07001293 // Ignore filename with path.
1294 if (strchr(name, '/') != nullptr) {
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001295 return false;
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07001296 }
1297
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001298 uint32_t target_sdk_version = get_application_target_sdk_version();
1299
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001300 return !ns->soinfo_list().visit([&](soinfo* si) {
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07001301 const char* soname = si->get_soname();
1302 if (soname != nullptr && (strcmp(name, soname) == 0)) {
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001303 // If the library was opened under different target sdk version
1304 // skip this step and try to reopen it. The exceptions are
1305 // "libdl.so" and global group. There is no point in skipping
1306 // them because relocation process is going to use them
1307 // in any case.
1308 bool is_libdl = si == solist;
1309 if (is_libdl || (si->get_dt_flags_1() & DF_1_GLOBAL) != 0 ||
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001310 !si->is_linked() || si->get_target_sdk_version() == target_sdk_version ||
1311 ns != &g_default_namespace) {
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001312 *candidate = si;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001313 return false;
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001314 } else if (*candidate == nullptr) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001315 // for the different sdk version in the default namespace
1316 // remember the first library.
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001317 *candidate = si;
1318 }
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
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001325static bool find_library_internal(android_namespace_t* ns,
1326 LoadTask* task,
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001327 ZipArchiveCache* zip_archive_cache,
1328 LoadTaskList* load_tasks,
1329 int rtld_flags) {
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001330 soinfo* candidate;
1331
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001332 if (find_loaded_library_by_soname(ns, task->get_name(), &candidate)) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001333 task->set_soinfo(candidate);
1334 return true;
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001335 }
Dmitriy Ivanovb648a8a2014-05-19 15:06:58 -07001336
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001337 if (ns != &g_default_namespace) {
1338 // check public namespace
1339 candidate = g_public_namespace.find_if([&](soinfo* si) {
1340 return strcmp(task->get_name(), si->get_soname()) == 0;
1341 });
1342
1343 if (candidate != nullptr) {
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001344 ns->add_soinfo(candidate);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001345 task->set_soinfo(candidate);
1346 return true;
1347 }
1348 }
1349
Dmitriy Ivanovb648a8a2014-05-19 15:06:58 -07001350 // Library might still be loaded, the accurate detection
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001351 // of this fact is done by load_library.
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001352 TRACE("[ \"%s\" find_loaded_library_by_soname failed (*candidate=%s@%p). Trying harder...]",
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001353 task->get_name(), candidate == nullptr ? "n/a" : candidate->get_realpath(), candidate);
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001354
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001355 if (load_library(ns, task, zip_archive_cache, load_tasks, rtld_flags)) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001356 return true;
1357 } else {
1358 // In case we were unable to load the library but there
1359 // is a candidate loaded under the same soname but different
1360 // sdk level - return it anyways.
1361 if (candidate != nullptr) {
1362 task->set_soinfo(candidate);
1363 return true;
1364 }
Elliott Hughesd23736e2012-11-01 15:16:56 -07001365 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001366
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001367 return false;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001368}
1369
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001370static void soinfo_unload(soinfo* si);
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001371static void soinfo_unload(soinfo* soinfos[], size_t count);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001372
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001373// TODO: this is slightly unusual way to construct
1374// the global group for relocation. Not every RTLD_GLOBAL
1375// library is included in this group for backwards-compatibility
1376// reasons.
1377//
1378// This group consists of the main executable, LD_PRELOADs
1379// and libraries with the DF_1_GLOBAL flag set.
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001380static soinfo_list_t make_global_group(android_namespace_t* ns) {
1381 soinfo_list_t global_group;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001382 ns->soinfo_list().for_each([&](soinfo* si) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001383 if ((si->get_dt_flags_1() & DF_1_GLOBAL) != 0) {
1384 global_group.push_back(si);
1385 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001386 });
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001387
1388 return global_group;
1389}
1390
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07001391// This function provides a list of libraries to be shared
1392// by the namespace. For the default namespace this is the global
1393// group (see make_global_group). For all others this is a group
1394// of RTLD_GLOBAL libraries (which includes the global group from
1395// the default namespace).
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001396static soinfo_list_t get_shared_group(android_namespace_t* ns) {
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07001397 if (ns == &g_default_namespace) {
1398 return make_global_group(ns);
1399 }
1400
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001401 soinfo_list_t shared_group;
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07001402 ns->soinfo_list().for_each([&](soinfo* si) {
1403 if ((si->get_rtld_flags() & RTLD_GLOBAL) != 0) {
1404 shared_group.push_back(si);
1405 }
1406 });
1407
1408 return shared_group;
1409}
1410
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001411static void shuffle(std::vector<LoadTask*>* v) {
1412 for (size_t i = 0, size = v->size(); i < size; ++i) {
1413 size_t n = size - i;
1414 size_t r = arc4random_uniform(n);
1415 std::swap((*v)[n-1], (*v)[r]);
1416 }
1417}
1418
Evgenii Stepanov0cdef7e2015-07-06 17:56:31 -07001419// add_as_children - add first-level loaded libraries (i.e. library_names[], but
1420// not their transitive dependencies) as children of the start_with library.
1421// This is false when find_libraries is called for dlopen(), when newly loaded
1422// libraries must form a disjoint tree.
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001423static bool find_libraries(android_namespace_t* ns,
1424 soinfo* start_with,
Evgenii Stepanov0cdef7e2015-07-06 17:56:31 -07001425 const char* const library_names[],
1426 size_t library_names_count, soinfo* soinfos[],
1427 std::vector<soinfo*>* ld_preloads,
1428 size_t ld_preloads_count, int rtld_flags,
1429 const android_dlextinfo* extinfo,
1430 bool add_as_children) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001431 // Step 0: prepare.
1432 LoadTaskList load_tasks;
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001433 std::unordered_map<const soinfo*, ElfReader> readers_map;
1434
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001435 for (size_t i = 0; i < library_names_count; ++i) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001436 const char* name = library_names[i];
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001437 load_tasks.push_back(LoadTask::create(name, start_with, &readers_map));
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001438 }
1439
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001440 // Construct global_group.
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001441 soinfo_list_t global_group = make_global_group(ns);
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001442
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001443 // If soinfos array is null allocate one on stack.
1444 // The array is needed in case of failure; for example
1445 // when library_names[] = {libone.so, libtwo.so} and libone.so
1446 // is loaded correctly but libtwo.so failed for some reason.
1447 // In this case libone.so should be unloaded on return.
1448 // See also implementation of failure_guard below.
1449
1450 if (soinfos == nullptr) {
1451 size_t soinfos_size = sizeof(soinfo*)*library_names_count;
1452 soinfos = reinterpret_cast<soinfo**>(alloca(soinfos_size));
1453 memset(soinfos, 0, soinfos_size);
1454 }
1455
1456 // list of libraries to link - see step 2.
1457 size_t soinfos_count = 0;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001458
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001459 auto scope_guard = make_scope_guard([&]() {
1460 for (LoadTask* t : load_tasks) {
1461 LoadTask::deleter(t);
1462 }
1463 });
1464
Dmitriy Ivanovd9ff7222014-09-08 16:22:22 -07001465 auto failure_guard = make_scope_guard([&]() {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001466 // Housekeeping
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001467 soinfo_unload(soinfos, soinfos_count);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001468 });
1469
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001470 ZipArchiveCache zip_archive_cache;
1471
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001472 // Step 1: expand the list of load_tasks to include
1473 // all DT_NEEDED libraries (do not load them just yet)
1474 for (size_t i = 0; i<load_tasks.size(); ++i) {
1475 LoadTask* task = load_tasks[i];
Evgenii Stepanov68650822015-06-10 13:38:39 -07001476 soinfo* needed_by = task->get_needed_by();
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001477
Dmitriy Ivanovedfc9f62015-09-02 16:32:02 -07001478 bool is_dt_needed = needed_by != nullptr && (needed_by != start_with || add_as_children);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001479 task->set_extinfo(is_dt_needed ? nullptr : extinfo);
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001480 task->set_dt_needed(is_dt_needed);
Dmitriy Ivanovedfc9f62015-09-02 16:32:02 -07001481
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001482 if(!find_library_internal(ns, task, &zip_archive_cache, &load_tasks, rtld_flags)) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001483 return false;
1484 }
1485
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001486 soinfo* si = task->get_soinfo();
1487
Dmitriy Ivanovedfc9f62015-09-02 16:32:02 -07001488 if (is_dt_needed) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001489 needed_by->add_child(si);
1490 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001491
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001492 if (si->is_linked()) {
1493 si->increment_ref_count();
1494 }
1495
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001496 // When ld_preloads is not null, the first
1497 // ld_preloads_count libs are in fact ld_preloads.
1498 if (ld_preloads != nullptr && soinfos_count < ld_preloads_count) {
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07001499 ld_preloads->push_back(si);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001500 }
1501
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001502 if (soinfos_count < library_names_count) {
1503 soinfos[soinfos_count++] = si;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001504 }
1505 }
1506
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001507 // Step 2: Load libraries in random order (see b/24047022)
1508 LoadTaskList load_list;
1509 for (auto&& task : load_tasks) {
1510 soinfo* si = task->get_soinfo();
1511 auto pred = [&](const LoadTask* t) {
1512 return t->get_soinfo() == si;
1513 };
1514
1515 if (!si->is_linked() &&
1516 std::find_if(load_list.begin(), load_list.end(), pred) == load_list.end() ) {
1517 load_list.push_back(task);
1518 }
1519 }
1520 shuffle(&load_list);
1521
1522 for (auto&& task : load_list) {
1523 if (!task->load()) {
1524 return false;
1525 }
1526 }
1527
1528 // Step 3: pre-link all DT_NEEDED libraries in breadth first order.
1529 for (auto&& task : load_tasks) {
1530 soinfo* si = task->get_soinfo();
1531 if (!si->is_linked() && !si->prelink_image()) {
1532 return false;
1533 }
1534 }
1535
1536 // Step 4: Add LD_PRELOADed libraries to the global group for
1537 // future runs. There is no need to explicitly add them to
1538 // the global group for this run because they are going to
1539 // appear in the local group in the correct order.
1540 if (ld_preloads != nullptr) {
1541 for (auto&& si : *ld_preloads) {
1542 si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL);
1543 }
1544 }
1545
1546
1547 // Step 5: link libraries.
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001548 soinfo_list_t local_group;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001549 walk_dependencies_tree(
Evgenii Stepanov0cdef7e2015-07-06 17:56:31 -07001550 (start_with != nullptr && add_as_children) ? &start_with : soinfos,
1551 (start_with != nullptr && add_as_children) ? 1 : soinfos_count,
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001552 [&] (soinfo* si) {
1553 local_group.push_back(si);
1554 return true;
1555 });
1556
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001557 // We need to increment ref_count in case
1558 // the root of the local group was not linked.
1559 bool was_local_group_root_linked = local_group.front()->is_linked();
1560
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001561 bool linked = local_group.visit([&](soinfo* si) {
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001562 if (!si->is_linked()) {
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08001563 if (!si->link_image(global_group, local_group, extinfo)) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001564 return false;
1565 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001566 }
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001567
1568 return true;
1569 });
1570
1571 if (linked) {
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001572 local_group.for_each([](soinfo* si) {
1573 if (!si->is_linked()) {
1574 si->set_linked();
1575 }
1576 });
1577
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001578 failure_guard.disable();
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001579 }
1580
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001581 if (!was_local_group_root_linked) {
1582 local_group.front()->increment_ref_count();
1583 }
1584
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001585 return linked;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001586}
1587
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001588static soinfo* find_library(android_namespace_t* ns,
1589 const char* name, int rtld_flags,
Evgenii Stepanov0cdef7e2015-07-06 17:56:31 -07001590 const android_dlextinfo* extinfo,
1591 soinfo* needed_by) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001592 soinfo* si;
1593
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001594 if (name == nullptr) {
1595 si = somain;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001596 } else if (!find_libraries(ns, needed_by, &name, 1, &si, nullptr, 0, rtld_flags,
Evgenii Stepanov0cdef7e2015-07-06 17:56:31 -07001597 extinfo, /* add_as_children */ false)) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001598 return nullptr;
1599 }
1600
Elliott Hughesd23736e2012-11-01 15:16:56 -07001601 return si;
1602}
Elliott Hughesbedfe382012-08-14 14:07:59 -07001603
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001604static void soinfo_unload(soinfo* root) {
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001605 if (root->is_linked()) {
1606 root = root->get_local_group_root();
1607 }
1608
1609 if (!root->can_unload()) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001610 TRACE("not unloading \"%s\" - the binary is flagged with NODELETE", root->get_realpath());
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -07001611 return;
1612 }
1613
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001614 soinfo_unload(&root, 1);
1615}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001616
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001617static void soinfo_unload(soinfo* soinfos[], size_t count) {
1618 // Note that the library can be loaded but not linked;
1619 // in which case there is no root but we still need
1620 // to walk the tree and unload soinfos involved.
1621 //
1622 // This happens on unsuccessful dlopen, when one of
1623 // the DT_NEEDED libraries could not be linked/found.
1624 if (count == 0) {
1625 return;
1626 }
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001627
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001628 soinfo_list_t unload_list;
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001629 for (size_t i = 0; i < count; ++i) {
1630 soinfo* si = soinfos[i];
Dmitriy Ivanov5ae82cb2014-12-02 17:08:42 -08001631
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001632 if (si->can_unload()) {
1633 size_t ref_count = si->is_linked() ? si->decrement_ref_count() : 0;
1634 if (ref_count == 0) {
1635 unload_list.push_back(si);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001636 } else {
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001637 TRACE("not unloading '%s' group, decrementing ref_count to %zd",
1638 si->get_realpath(), ref_count);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001639 }
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001640 } else {
1641 TRACE("not unloading '%s' - the binary is flagged with NODELETE", si->get_realpath());
1642 return;
1643 }
1644 }
1645
1646 // This is used to identify soinfos outside of the load-group
1647 // note that we cannot have > 1 in the array and have any of them
1648 // linked. This is why we can safely use the first one.
1649 soinfo* root = soinfos[0];
1650
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001651 soinfo_list_t local_unload_list;
1652 soinfo_list_t external_unload_list;
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001653 soinfo* si = nullptr;
1654
1655 while ((si = unload_list.pop_front()) != nullptr) {
1656 if (local_unload_list.contains(si)) {
1657 continue;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001658 }
Elliott Hughesd23736e2012-11-01 15:16:56 -07001659
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001660 local_unload_list.push_back(si);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001661
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001662 if (si->has_min_version(0)) {
1663 soinfo* child = nullptr;
1664 while ((child = si->get_children().pop_front()) != nullptr) {
1665 TRACE("%s@%p needs to unload %s@%p", si->get_realpath(), si,
1666 child->get_realpath(), child);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001667
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001668 if (local_unload_list.contains(child)) {
1669 continue;
1670 } else if (child->is_linked() && child->get_local_group_root() != root) {
1671 external_unload_list.push_back(child);
1672 } else {
1673 unload_list.push_front(child);
1674 }
1675 }
1676 } else {
1677#if !defined(__work_around_b_24465209__)
1678 __libc_fatal("soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
1679#else
1680 PRINT("warning: soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
1681 for_each_dt_needed(si, [&] (const char* library_name) {
1682 TRACE("deprecated (old format of soinfo): %s needs to unload %s",
1683 si->get_realpath(), library_name);
1684
1685 soinfo* needed = find_library(si->get_primary_namespace(),
1686 library_name, RTLD_NOLOAD, nullptr, nullptr);
1687
1688 if (needed != nullptr) {
1689 // Not found: for example if symlink was deleted between dlopen and dlclose
1690 // Since we cannot really handle errors at this point - print and continue.
1691 PRINT("warning: couldn't find %s needed by %s on unload.",
1692 library_name, si->get_realpath());
1693 return;
1694 } else if (local_unload_list.contains(needed)) {
1695 // already visited
1696 return;
1697 } else if (needed->is_linked() && needed->get_local_group_root() != root) {
1698 // external group
1699 external_unload_list.push_back(needed);
1700 } else {
1701 // local group
1702 unload_list.push_front(needed);
1703 }
1704 });
1705#endif
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001706 }
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001707 }
1708
1709 local_unload_list.for_each([](soinfo* si) {
1710 si->call_destructors();
1711 });
1712
1713 while ((si = local_unload_list.pop_front()) != nullptr) {
1714 notify_gdb_of_unload(si);
1715 soinfo_free(si);
1716 }
1717
1718 while ((si = external_unload_list.pop_front()) != nullptr) {
1719 soinfo_unload(si);
Dmitriy Ivanova2547052014-11-18 12:03:09 -08001720 }
1721}
1722
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001723static std::string symbol_display_name(const char* sym_name, const char* sym_ver) {
1724 if (sym_ver == nullptr) {
1725 return sym_name;
1726 }
1727
Dimitry Ivanov9cf99cb2015-12-11 14:22:24 -08001728 return std::string(sym_name) + ", version " + sym_ver;
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001729}
1730
Dimitry Ivanovaca299a2016-04-11 12:42:58 -07001731static android_namespace_t* get_caller_namespace(soinfo* caller) {
1732 return caller != nullptr ? caller->get_primary_namespace() : g_anonymous_namespace;
1733}
1734
Elliott Hughesa4aafd12014-01-13 16:37:47 -08001735void do_android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size) {
Christopher Ferris052fa3a2014-08-26 20:48:11 -07001736 // Use basic string manipulation calls to avoid snprintf.
1737 // snprintf indirectly calls pthread_getspecific to get the size of a buffer.
1738 // When debug malloc is enabled, this call returns 0. This in turn causes
1739 // snprintf to do nothing, which causes libraries to fail to load.
1740 // See b/17302493 for further details.
1741 // Once the above bug is fixed, this code can be modified to use
1742 // snprintf again.
Evgenii Stepanovd640b222015-07-10 17:54:01 -07001743 size_t required_len = 0;
1744 for (size_t i = 0; g_default_ld_paths[i] != nullptr; ++i) {
1745 required_len += strlen(g_default_ld_paths[i]) + 1;
1746 }
Christopher Ferris052fa3a2014-08-26 20:48:11 -07001747 if (buffer_size < required_len) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07001748 __libc_fatal("android_get_LD_LIBRARY_PATH failed, buffer too small: "
1749 "buffer len %zu, required len %zu", buffer_size, required_len);
Christopher Ferris052fa3a2014-08-26 20:48:11 -07001750 }
Evgenii Stepanovd640b222015-07-10 17:54:01 -07001751 char* end = buffer;
1752 for (size_t i = 0; g_default_ld_paths[i] != nullptr; ++i) {
1753 if (i > 0) *end++ = ':';
1754 end = stpcpy(end, g_default_ld_paths[i]);
1755 }
Elliott Hughesa4aafd12014-01-13 16:37:47 -08001756}
1757
Elliott Hughescade4c32012-12-20 14:42:14 -08001758void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path) {
Nick Kralevich6bb01b62015-03-07 13:37:05 -08001759 parse_LD_LIBRARY_PATH(ld_library_path);
Elliott Hughescade4c32012-12-20 14:42:14 -08001760}
1761
Dimitry Ivanovb996d602016-07-11 18:11:39 -07001762static std::string android_dlextinfo_to_string(const android_dlextinfo* info) {
1763 if (info == nullptr) {
1764 return "(null)";
1765 }
1766
1767 return android::base::StringPrintf("[flags=0x%" PRIx64 ","
1768 " reserved_addr=%p,"
1769 " reserved_size=0x%zx,"
1770 " relro_fd=%d,"
1771 " library_fd=%d,"
1772 " library_fd_offset=0x%" PRIx64 ","
1773 " library_namespace=%s@%p]",
1774 info->flags,
1775 info->reserved_addr,
1776 info->reserved_size,
1777 info->relro_fd,
1778 info->library_fd,
1779 info->library_fd_offset,
1780 (info->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0 ?
1781 (info->library_namespace != nullptr ?
1782 info->library_namespace->get_name() : "(null)") : "(n/a)",
1783 (info->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0 ?
1784 info->library_namespace : nullptr);
1785}
1786
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001787void* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo,
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001788 void* caller_addr) {
1789 soinfo* const caller = find_containing_library(caller_addr);
Dimitry Ivanovb996d602016-07-11 18:11:39 -07001790 android_namespace_t* ns = get_caller_namespace(caller);
1791
1792 LD_LOG(kLogDlopen,
1793 "dlopen(name=\"%s\", flags=0x%x, extinfo=%s, caller=\"%s\", caller_ns=%s@%p) ...",
1794 name,
1795 flags,
1796 android_dlextinfo_to_string(extinfo).c_str(),
1797 caller == nullptr ? "(null)" : caller->get_realpath(),
1798 ns == nullptr ? "(null)" : ns->get_name(),
1799 ns);
1800
1801 auto failure_guard = make_scope_guard([&]() {
1802 LD_LOG(kLogDlopen, "... dlopen failed: %s", linker_get_error_buffer());
1803 });
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001804
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -07001805 if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL|RTLD_NODELETE|RTLD_NOLOAD)) != 0) {
Elliott Hughese66190d2012-12-18 15:57:55 -08001806 DL_ERR("invalid flags to dlopen: %x", flags);
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07001807 return nullptr;
Elliott Hughese66190d2012-12-18 15:57:55 -08001808 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001809
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001810 if (extinfo != nullptr) {
1811 if ((extinfo->flags & ~(ANDROID_DLEXT_VALID_FLAG_BITS)) != 0) {
1812 DL_ERR("invalid extended flags to android_dlopen_ext: 0x%" PRIx64, extinfo->flags);
1813 return nullptr;
1814 }
Dmitriy Ivanov126af752015-10-07 16:34:20 -07001815
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001816 if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) == 0 &&
Dmitriy Ivanova6c12792014-10-21 12:09:18 -07001817 (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07001818 DL_ERR("invalid extended flag combination (ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET without "
1819 "ANDROID_DLEXT_USE_LIBRARY_FD): 0x%" PRIx64, extinfo->flags);
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001820 return nullptr;
1821 }
Dmitriy Ivanov126af752015-10-07 16:34:20 -07001822
1823 if ((extinfo->flags & ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS) != 0 &&
1824 (extinfo->flags & (ANDROID_DLEXT_RESERVED_ADDRESS | ANDROID_DLEXT_RESERVED_ADDRESS_HINT)) != 0) {
1825 DL_ERR("invalid extended flag combination: ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS is not "
1826 "compatible with ANDROID_DLEXT_RESERVED_ADDRESS/ANDROID_DLEXT_RESERVED_ADDRESS_HINT");
1827 return nullptr;
1828 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001829
1830 if ((extinfo->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0) {
1831 if (extinfo->library_namespace == nullptr) {
1832 DL_ERR("ANDROID_DLEXT_USE_NAMESPACE is set but extinfo->library_namespace is null");
1833 return nullptr;
1834 }
1835 ns = extinfo->library_namespace;
1836 }
Torne (Richard Coles)012cb452014-02-06 14:34:21 +00001837 }
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -08001838
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -07001839 std::string asan_name_holder;
1840
1841 const char* translated_name = name;
1842 if (g_is_asan) {
1843 if (file_is_in_dir(name, kSystemLibDir)) {
1844 asan_name_holder = std::string(kAsanSystemLibDir) + "/" + basename(name);
1845 if (file_exists(asan_name_holder.c_str())) {
1846 translated_name = asan_name_holder.c_str();
1847 PRINT("linker_asan dlopen translating \"%s\" -> \"%s\"", name, translated_name);
1848 }
1849 } else if (file_is_in_dir(name, kVendorLibDir)) {
1850 asan_name_holder = std::string(kAsanVendorLibDir) + "/" + basename(name);
1851 if (file_exists(asan_name_holder.c_str())) {
1852 translated_name = asan_name_holder.c_str();
1853 PRINT("linker_asan dlopen translating \"%s\" -> \"%s\"", name, translated_name);
1854 }
1855 }
1856 }
1857
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -08001858 ProtectedDataGuard guard;
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -07001859 soinfo* si = find_library(ns, translated_name, flags, extinfo, caller);
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07001860 if (si != nullptr) {
Dimitry Ivanovb996d602016-07-11 18:11:39 -07001861 failure_guard.disable();
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08001862 si->call_constructors();
Dimitry Ivanovb996d602016-07-11 18:11:39 -07001863 void* handle = si->to_handle();
1864 LD_LOG(kLogDlopen,
1865 "... dlopen successful: realpath=\"%s\", soname=\"%s\", handle=%p",
1866 si->get_realpath(), si->get_soname(), handle);
1867 return handle;
Elliott Hughesd23736e2012-11-01 15:16:56 -07001868 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001869
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001870 return nullptr;
Elliott Hughesd23736e2012-11-01 15:16:56 -07001871}
1872
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001873int do_dladdr(const void* addr, Dl_info* info) {
1874 // Determine if this address can be found in any library currently mapped.
1875 soinfo* si = find_containing_library(addr);
1876 if (si == nullptr) {
1877 return 0;
1878 }
1879
1880 memset(info, 0, sizeof(Dl_info));
1881
1882 info->dli_fname = si->get_realpath();
1883 // Address at which the shared object is loaded.
1884 info->dli_fbase = reinterpret_cast<void*>(si->base);
1885
1886 // Determine if any symbol in the library contains the specified address.
1887 ElfW(Sym)* sym = si->find_symbol_by_address(addr);
1888 if (sym != nullptr) {
1889 info->dli_sname = si->get_string(sym->st_name);
1890 info->dli_saddr = reinterpret_cast<void*>(si->resolve_symbol_address(sym));
1891 }
1892
1893 return 1;
1894}
1895
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001896static soinfo* soinfo_from_handle(void* handle) {
1897 if ((reinterpret_cast<uintptr_t>(handle) & 1) != 0) {
1898 auto it = g_soinfo_handles_map.find(reinterpret_cast<uintptr_t>(handle));
1899 if (it == g_soinfo_handles_map.end()) {
1900 return nullptr;
1901 } else {
1902 return it->second;
1903 }
1904 }
1905
1906 return static_cast<soinfo*>(handle);
1907}
1908
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001909bool do_dlsym(void* handle, const char* sym_name, const char* sym_ver,
1910 void* caller_addr, void** symbol) {
1911#if !defined(__LP64__)
1912 if (handle == nullptr) {
1913 DL_ERR("dlsym failed: library handle is null");
1914 return false;
1915 }
1916#endif
1917
1918 if (sym_name == nullptr) {
1919 DL_ERR("dlsym failed: symbol name is null");
1920 return false;
1921 }
1922
1923 soinfo* found = nullptr;
1924 const ElfW(Sym)* sym = nullptr;
1925 soinfo* caller = find_containing_library(caller_addr);
Dimitry Ivanovaca299a2016-04-11 12:42:58 -07001926 android_namespace_t* ns = get_caller_namespace(caller);
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001927
1928 version_info vi_instance;
1929 version_info* vi = nullptr;
1930
1931 if (sym_ver != nullptr) {
Dimitry Ivanov9cf99cb2015-12-11 14:22:24 -08001932 vi_instance.name = sym_ver;
1933 vi_instance.elf_hash = calculate_elf_hash(sym_ver);
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001934 vi = &vi_instance;
1935 }
1936
1937 if (handle == RTLD_DEFAULT || handle == RTLD_NEXT) {
1938 sym = dlsym_linear_lookup(ns, sym_name, vi, &found, caller, handle);
1939 } else {
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001940 soinfo* si = soinfo_from_handle(handle);
1941 if (si == nullptr) {
1942 DL_ERR("dlsym failed: invalid handle: %p", handle);
1943 return false;
1944 }
1945 sym = dlsym_handle_lookup(si, &found, sym_name, vi);
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001946 }
1947
1948 if (sym != nullptr) {
1949 uint32_t bind = ELF_ST_BIND(sym->st_info);
1950
1951 if ((bind == STB_GLOBAL || bind == STB_WEAK) && sym->st_shndx != 0) {
1952 *symbol = reinterpret_cast<void*>(found->resolve_symbol_address(sym));
1953 return true;
1954 }
1955
1956 DL_ERR("symbol \"%s\" found but not global", symbol_display_name(sym_name, sym_ver).c_str());
1957 return false;
1958 }
1959
1960 DL_ERR("undefined symbol: %s", symbol_display_name(sym_name, sym_ver).c_str());
1961 return false;
1962}
1963
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001964int do_dlclose(void* handle) {
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -08001965 ProtectedDataGuard guard;
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001966 soinfo* si = soinfo_from_handle(handle);
1967 if (si == nullptr) {
1968 DL_ERR("invalid handle: %p", handle);
1969 return -1;
1970 }
1971
Dmitriy Ivanovb648a8a2014-05-19 15:06:58 -07001972 soinfo_unload(si);
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001973 return 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001974}
1975
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08001976bool init_namespaces(const char* public_ns_sonames, const char* anon_ns_library_path) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001977 if (g_public_namespace_initialized) {
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08001978 DL_ERR("public namespace has already been initialized.");
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001979 return false;
1980 }
1981
Dimitry Ivanov54807612016-04-21 14:57:38 -07001982 if (public_ns_sonames == nullptr || public_ns_sonames[0] == '\0') {
1983 DL_ERR("error initializing public namespace: the list of public libraries is empty.");
1984 return false;
1985 }
1986
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08001987 std::vector<std::string> sonames = android::base::Split(public_ns_sonames, ":");
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001988
1989 ProtectedDataGuard guard;
1990
1991 auto failure_guard = make_scope_guard([&]() {
1992 g_public_namespace.clear();
1993 });
1994
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001995 for (const auto& soname : sonames) {
Dmitriy Ivanov3cc35e22015-11-17 18:36:50 -08001996 soinfo* candidate = nullptr;
1997
1998 find_loaded_library_by_soname(&g_default_namespace, soname.c_str(), &candidate);
1999
2000 if (candidate == nullptr) {
Christopher Ferris523e2a92016-06-17 13:46:36 -07002001 DL_ERR("error initializing public namespace: a library with soname \"%s\""
2002 " was not found in the default namespace", soname.c_str());
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002003 return false;
2004 }
2005
2006 candidate->set_nodelete();
2007 g_public_namespace.push_back(candidate);
2008 }
2009
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002010 g_public_namespace_initialized = true;
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002011
2012 // create anonymous namespace
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002013 // When the caller is nullptr - create_namespace will take global group
2014 // from the anonymous namespace, which is fine because anonymous namespace
2015 // is still pointing to the default one.
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002016 android_namespace_t* anon_ns =
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002017 create_namespace(nullptr, "(anonymous)", nullptr, anon_ns_library_path,
Dimitry Ivanov52408632016-05-23 10:31:11 -07002018 ANDROID_NAMESPACE_TYPE_REGULAR, nullptr, &g_default_namespace);
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002019
2020 if (anon_ns == nullptr) {
2021 g_public_namespace_initialized = false;
2022 return false;
2023 }
2024 g_anonymous_namespace = anon_ns;
2025 failure_guard.disable();
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002026 return true;
2027}
2028
Dimitry Ivanovb943f302016-08-03 16:00:10 -07002029static void add_soinfos_to_namespace(const soinfo_list_t& soinfos, android_namespace_t* ns) {
2030 ns->add_soinfos(soinfos);
2031 for (auto si : soinfos) {
2032 si->add_secondary_namespace(ns);
2033 }
2034}
2035
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002036android_namespace_t* create_namespace(const void* caller_addr,
2037 const char* name,
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002038 const char* ld_library_path,
2039 const char* default_library_path,
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002040 uint64_t type,
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002041 const char* permitted_when_isolated_path,
2042 android_namespace_t* parent_namespace) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002043 if (!g_public_namespace_initialized) {
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002044 DL_ERR("cannot create namespace: public namespace is not initialized.");
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002045 return nullptr;
2046 }
2047
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002048 if (parent_namespace == nullptr) {
Dimitry Ivanov52408632016-05-23 10:31:11 -07002049 // if parent_namespace is nullptr -> set it to the caller namespace
2050 soinfo* caller_soinfo = find_containing_library(caller_addr);
2051
2052 parent_namespace = caller_soinfo != nullptr ?
2053 caller_soinfo->get_primary_namespace() :
2054 g_anonymous_namespace;
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002055 }
2056
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002057 ProtectedDataGuard guard;
2058 std::vector<std::string> ld_library_paths;
2059 std::vector<std::string> default_library_paths;
Dimitry Ivanov284ae352015-12-08 10:47:13 -08002060 std::vector<std::string> permitted_paths;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002061
2062 parse_path(ld_library_path, ":", &ld_library_paths);
2063 parse_path(default_library_path, ":", &default_library_paths);
Dimitry Ivanov284ae352015-12-08 10:47:13 -08002064 parse_path(permitted_when_isolated_path, ":", &permitted_paths);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002065
2066 android_namespace_t* ns = new (g_namespace_allocator.alloc()) android_namespace_t();
2067 ns->set_name(name);
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002068 ns->set_isolated((type & ANDROID_NAMESPACE_TYPE_ISOLATED) != 0);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002069 ns->set_ld_library_paths(std::move(ld_library_paths));
2070 ns->set_default_library_paths(std::move(default_library_paths));
Dimitry Ivanov284ae352015-12-08 10:47:13 -08002071 ns->set_permitted_paths(std::move(permitted_paths));
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002072
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002073 if ((type & ANDROID_NAMESPACE_TYPE_SHARED) != 0) {
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002074 // If shared - clone the parent namespace
Dimitry Ivanovb943f302016-08-03 16:00:10 -07002075 add_soinfos_to_namespace(parent_namespace->soinfo_list(), ns);
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002076 } else {
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002077 // If not shared - copy only the shared group
Dimitry Ivanovb943f302016-08-03 16:00:10 -07002078 add_soinfos_to_namespace(get_shared_group(parent_namespace), ns);
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002079 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002080
2081 return ns;
2082}
2083
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002084ElfW(Addr) call_ifunc_resolver(ElfW(Addr) resolver_addr) {
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07002085 typedef ElfW(Addr) (*ifunc_resolver_t)(void);
2086 ifunc_resolver_t ifunc_resolver = reinterpret_cast<ifunc_resolver_t>(resolver_addr);
2087 ElfW(Addr) ifunc_addr = ifunc_resolver();
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002088 TRACE_TYPE(RELO, "Called ifunc_resolver@%p. The result is %p",
2089 ifunc_resolver, reinterpret_cast<void*>(ifunc_addr));
Brigid Smithc5a13ef2014-07-23 11:22:25 -07002090
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07002091 return ifunc_addr;
Brigid Smithc5a13ef2014-07-23 11:22:25 -07002092}
Brigid Smithc5a13ef2014-07-23 11:22:25 -07002093
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002094const version_info* VersionTracker::get_version_info(ElfW(Versym) source_symver) const {
2095 if (source_symver < 2 ||
2096 source_symver >= version_infos.size() ||
2097 version_infos[source_symver].name == nullptr) {
2098 return nullptr;
2099 }
2100
2101 return &version_infos[source_symver];
2102}
2103
2104void VersionTracker::add_version_info(size_t source_index,
2105 ElfW(Word) elf_hash,
2106 const char* ver_name,
2107 const soinfo* target_si) {
2108 if (source_index >= version_infos.size()) {
2109 version_infos.resize(source_index+1);
2110 }
2111
2112 version_infos[source_index].elf_hash = elf_hash;
2113 version_infos[source_index].name = ver_name;
2114 version_infos[source_index].target_si = target_si;
2115}
2116
2117bool VersionTracker::init_verneed(const soinfo* si_from) {
2118 uintptr_t verneed_ptr = si_from->get_verneed_ptr();
2119
2120 if (verneed_ptr == 0) {
2121 return true;
2122 }
2123
2124 size_t verneed_cnt = si_from->get_verneed_cnt();
2125
2126 for (size_t i = 0, offset = 0; i<verneed_cnt; ++i) {
2127 const ElfW(Verneed)* verneed = reinterpret_cast<ElfW(Verneed)*>(verneed_ptr + offset);
2128 size_t vernaux_offset = offset + verneed->vn_aux;
2129 offset += verneed->vn_next;
2130
2131 if (verneed->vn_version != 1) {
2132 DL_ERR("unsupported verneed[%zd] vn_version: %d (expected 1)", i, verneed->vn_version);
2133 return false;
2134 }
2135
2136 const char* target_soname = si_from->get_string(verneed->vn_file);
2137 // find it in dependencies
2138 soinfo* target_si = si_from->get_children().find_if([&](const soinfo* si) {
Dmitriy Ivanov406d9962015-05-06 11:05:27 -07002139 return si->get_soname() != nullptr && strcmp(si->get_soname(), target_soname) == 0;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002140 });
2141
2142 if (target_si == nullptr) {
2143 DL_ERR("cannot find \"%s\" from verneed[%zd] in DT_NEEDED list for \"%s\"",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002144 target_soname, i, si_from->get_realpath());
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002145 return false;
2146 }
2147
2148 for (size_t j = 0; j<verneed->vn_cnt; ++j) {
2149 const ElfW(Vernaux)* vernaux = reinterpret_cast<ElfW(Vernaux)*>(verneed_ptr + vernaux_offset);
2150 vernaux_offset += vernaux->vna_next;
2151
2152 const ElfW(Word) elf_hash = vernaux->vna_hash;
2153 const char* ver_name = si_from->get_string(vernaux->vna_name);
2154 ElfW(Half) source_index = vernaux->vna_other;
2155
2156 add_version_info(source_index, elf_hash, ver_name, target_si);
2157 }
2158 }
2159
2160 return true;
2161}
2162
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002163template <typename F>
2164static bool for_each_verdef(const soinfo* si, F functor) {
2165 if (!si->has_min_version(2)) {
2166 return true;
2167 }
2168
2169 uintptr_t verdef_ptr = si->get_verdef_ptr();
2170 if (verdef_ptr == 0) {
2171 return true;
2172 }
2173
2174 size_t offset = 0;
2175
2176 size_t verdef_cnt = si->get_verdef_cnt();
2177 for (size_t i = 0; i<verdef_cnt; ++i) {
2178 const ElfW(Verdef)* verdef = reinterpret_cast<ElfW(Verdef)*>(verdef_ptr + offset);
2179 size_t verdaux_offset = offset + verdef->vd_aux;
2180 offset += verdef->vd_next;
2181
2182 if (verdef->vd_version != 1) {
2183 DL_ERR("unsupported verdef[%zd] vd_version: %d (expected 1) library: %s",
2184 i, verdef->vd_version, si->get_realpath());
2185 return false;
2186 }
2187
2188 if ((verdef->vd_flags & VER_FLG_BASE) != 0) {
2189 // "this is the version of the file itself. It must not be used for
2190 // matching a symbol. It can be used to match references."
2191 //
2192 // http://www.akkadia.org/drepper/symbol-versioning
2193 continue;
2194 }
2195
2196 if (verdef->vd_cnt == 0) {
2197 DL_ERR("invalid verdef[%zd] vd_cnt == 0 (version without a name)", i);
2198 return false;
2199 }
2200
2201 const ElfW(Verdaux)* verdaux = reinterpret_cast<ElfW(Verdaux)*>(verdef_ptr + verdaux_offset);
2202
2203 if (functor(i, verdef, verdaux) == true) {
2204 break;
2205 }
2206 }
2207
2208 return true;
2209}
2210
2211bool find_verdef_version_index(const soinfo* si, const version_info* vi, ElfW(Versym)* versym) {
2212 if (vi == nullptr) {
2213 *versym = kVersymNotNeeded;
2214 return true;
2215 }
2216
2217 *versym = kVersymGlobal;
2218
2219 return for_each_verdef(si,
2220 [&](size_t, const ElfW(Verdef)* verdef, const ElfW(Verdaux)* verdaux) {
2221 if (verdef->vd_hash == vi->elf_hash &&
2222 strcmp(vi->name, si->get_string(verdaux->vda_name)) == 0) {
2223 *versym = verdef->vd_ndx;
2224 return true;
2225 }
2226
2227 return false;
2228 }
2229 );
2230}
2231
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002232bool VersionTracker::init_verdef(const soinfo* si_from) {
2233 return for_each_verdef(si_from,
2234 [&](size_t, const ElfW(Verdef)* verdef, const ElfW(Verdaux)* verdaux) {
2235 add_version_info(verdef->vd_ndx, verdef->vd_hash,
2236 si_from->get_string(verdaux->vda_name), si_from);
2237 return false;
2238 }
2239 );
2240}
2241
2242bool VersionTracker::init(const soinfo* si_from) {
2243 if (!si_from->has_min_version(2)) {
2244 return true;
2245 }
2246
2247 return init_verneed(si_from) && init_verdef(si_from);
2248}
2249
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002250// TODO (dimitry): Methods below need to be moved out of soinfo
2251// and in more isolated file in order minimize dependencies on
2252// unnecessary object in the linker binary. Consider making them
2253// independent from soinfo (?).
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002254bool soinfo::lookup_version_info(const VersionTracker& version_tracker, ElfW(Word) sym,
2255 const char* sym_name, const version_info** vi) {
2256 const ElfW(Versym)* sym_ver_ptr = get_versym(sym);
2257 ElfW(Versym) sym_ver = sym_ver_ptr == nullptr ? 0 : *sym_ver_ptr;
2258
2259 if (sym_ver != VER_NDX_LOCAL && sym_ver != VER_NDX_GLOBAL) {
2260 *vi = version_tracker.get_version_info(sym_ver);
2261
2262 if (*vi == nullptr) {
2263 DL_ERR("cannot find verneed/verdef for version index=%d "
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002264 "referenced by symbol \"%s\" at \"%s\"", sym_ver, sym_name, get_realpath());
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002265 return false;
2266 }
2267 } else {
2268 // there is no version info
2269 *vi = nullptr;
2270 }
2271
2272 return true;
2273}
2274
Dimitry Ivanov576a3752016-08-09 06:58:55 -07002275#if !defined(__mips__)
2276#if defined(USE_RELA)
2277static ElfW(Addr) get_addend(ElfW(Rela)* rela, ElfW(Addr) reloc_addr __unused) {
2278 return rela->r_addend;
2279}
2280#else
2281static ElfW(Addr) get_addend(ElfW(Rel)* rel, ElfW(Addr) reloc_addr) {
2282 if (ELFW(R_TYPE)(rel->r_info) == R_GENERIC_RELATIVE ||
2283 ELFW(R_TYPE)(rel->r_info) == R_GENERIC_IRELATIVE) {
2284 return *reinterpret_cast<ElfW(Addr)*>(reloc_addr);
2285 }
2286 return 0;
2287}
2288#endif
2289
Dmitriy Ivanovfa26eee2015-02-03 16:06:47 -08002290template<typename ElfRelIteratorT>
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07002291bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& rel_iterator,
2292 const soinfo_list_t& global_group, const soinfo_list_t& local_group) {
Dmitriy Ivanovfa26eee2015-02-03 16:06:47 -08002293 for (size_t idx = 0; rel_iterator.has_next(); ++idx) {
2294 const auto rel = rel_iterator.next();
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002295 if (rel == nullptr) {
2296 return false;
2297 }
2298
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002299 ElfW(Word) type = ELFW(R_TYPE)(rel->r_info);
2300 ElfW(Word) sym = ELFW(R_SYM)(rel->r_info);
2301
2302 ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rel->r_offset + load_bias);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002303 ElfW(Addr) sym_addr = 0;
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07002304 const char* sym_name = nullptr;
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002305 ElfW(Addr) addend = get_addend(rel, reloc);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002306
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07002307 DEBUG("Processing \"%s\" relocation at index %zd", get_realpath(), idx);
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002308 if (type == R_GENERIC_NONE) {
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002309 continue;
2310 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002311
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002312 const ElfW(Sym)* s = nullptr;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002313 soinfo* lsi = nullptr;
2314
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002315 if (sym != 0) {
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002316 sym_name = get_string(symtab_[sym].st_name);
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002317 const version_info* vi = nullptr;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002318
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002319 if (!lookup_version_info(version_tracker, sym, sym_name, &vi)) {
2320 return false;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002321 }
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002322
2323 if (!soinfo_do_lookup(this, sym_name, vi, &lsi, global_group, local_group, &s)) {
2324 return false;
2325 }
2326
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07002327 if (s == nullptr) {
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002328 // We only allow an undefined symbol if this is a weak reference...
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002329 s = &symtab_[sym];
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002330 if (ELF_ST_BIND(s->st_info) != STB_WEAK) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002331 DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, get_realpath());
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002332 return false;
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002333 }
2334
2335 /* IHI0044C AAELF 4.5.1.1:
2336
2337 Libraries are not searched to resolve weak references.
2338 It is not an error for a weak reference to remain unsatisfied.
2339
2340 During linking, the value of an undefined weak reference is:
2341 - Zero if the relocation type is absolute
2342 - The address of the place if the relocation is pc-relative
2343 - The address of nominal base address if the relocation
2344 type is base-relative.
2345 */
2346
2347 switch (type) {
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002348 case R_GENERIC_JUMP_SLOT:
2349 case R_GENERIC_GLOB_DAT:
2350 case R_GENERIC_RELATIVE:
2351 case R_GENERIC_IRELATIVE:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002352#if defined(__aarch64__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002353 case R_AARCH64_ABS64:
2354 case R_AARCH64_ABS32:
2355 case R_AARCH64_ABS16:
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002356#elif defined(__x86_64__)
2357 case R_X86_64_32:
2358 case R_X86_64_64:
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002359#elif defined(__arm__)
2360 case R_ARM_ABS32:
2361#elif defined(__i386__)
2362 case R_386_32:
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002363#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002364 /*
2365 * The sym_addr was initialized to be zero above, or the relocation
2366 * code below does not care about value of sym_addr.
2367 * No need to do anything.
2368 */
2369 break;
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002370#if defined(__x86_64__)
Dimitry Ivanovd338aac2015-01-13 22:31:54 +00002371 case R_X86_64_PC32:
2372 sym_addr = reloc;
2373 break;
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002374#elif defined(__i386__)
2375 case R_386_PC32:
2376 sym_addr = reloc;
2377 break;
2378#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002379 default:
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002380 DL_ERR("unknown weak reloc type %d @ %p (%zu)", type, rel, idx);
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002381 return false;
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002382 }
Dmitriy Ivanovec83a612015-07-26 07:37:09 -07002383 } else { // We got a definition.
2384#if !defined(__LP64__)
2385 // When relocating dso with text_relocation .text segment is
2386 // not executable. We need to restore elf flags before resolving
2387 // STT_GNU_IFUNC symbol.
2388 bool protect_segments = has_text_relocations &&
2389 lsi == this &&
2390 ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC;
2391 if (protect_segments) {
2392 if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
2393 DL_ERR("can't protect segments for \"%s\": %s",
2394 get_realpath(), strerror(errno));
2395 return false;
2396 }
2397 }
2398#endif
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07002399 sym_addr = lsi->resolve_symbol_address(s);
Dmitriy Ivanovec83a612015-07-26 07:37:09 -07002400#if !defined(__LP64__)
2401 if (protect_segments) {
2402 if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
2403 DL_ERR("can't unprotect loadable segments for \"%s\": %s",
2404 get_realpath(), strerror(errno));
2405 return false;
2406 }
2407 }
2408#endif
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002409 }
2410 count_relocation(kRelocSymbol);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002411 }
2412
2413 switch (type) {
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002414 case R_GENERIC_JUMP_SLOT:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002415 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002416 MARK(rel->r_offset);
2417 TRACE_TYPE(RELO, "RELO JMP_SLOT %16p <- %16p %s\n",
2418 reinterpret_cast<void*>(reloc),
2419 reinterpret_cast<void*>(sym_addr + addend), sym_name);
2420
2421 *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002422 break;
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002423 case R_GENERIC_GLOB_DAT:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002424 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002425 MARK(rel->r_offset);
2426 TRACE_TYPE(RELO, "RELO GLOB_DAT %16p <- %16p %s\n",
2427 reinterpret_cast<void*>(reloc),
2428 reinterpret_cast<void*>(sym_addr + addend), sym_name);
2429 *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002430 break;
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002431 case R_GENERIC_RELATIVE:
2432 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002433 MARK(rel->r_offset);
2434 TRACE_TYPE(RELO, "RELO RELATIVE %16p <- %16p\n",
2435 reinterpret_cast<void*>(reloc),
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002436 reinterpret_cast<void*>(load_bias + addend));
2437 *reinterpret_cast<ElfW(Addr)*>(reloc) = (load_bias + addend);
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002438 break;
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002439 case R_GENERIC_IRELATIVE:
2440 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002441 MARK(rel->r_offset);
2442 TRACE_TYPE(RELO, "RELO IRELATIVE %16p <- %16p\n",
2443 reinterpret_cast<void*>(reloc),
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002444 reinterpret_cast<void*>(load_bias + addend));
Dmitriy Ivanovec83a612015-07-26 07:37:09 -07002445 {
2446#if !defined(__LP64__)
2447 // When relocating dso with text_relocation .text segment is
2448 // not executable. We need to restore elf flags for this
2449 // particular call.
2450 if (has_text_relocations) {
2451 if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
2452 DL_ERR("can't protect segments for \"%s\": %s",
2453 get_realpath(), strerror(errno));
2454 return false;
2455 }
2456 }
2457#endif
2458 ElfW(Addr) ifunc_addr = call_ifunc_resolver(load_bias + addend);
2459#if !defined(__LP64__)
2460 // Unprotect it afterwards...
2461 if (has_text_relocations) {
2462 if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
2463 DL_ERR("can't unprotect loadable segments for \"%s\": %s",
2464 get_realpath(), strerror(errno));
2465 return false;
2466 }
2467 }
2468#endif
2469 *reinterpret_cast<ElfW(Addr)*>(reloc) = ifunc_addr;
2470 }
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002471 break;
2472
2473#if defined(__aarch64__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002474 case R_AARCH64_ABS64:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002475 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002476 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002477 TRACE_TYPE(RELO, "RELO ABS64 %16llx <- %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002478 reloc, sym_addr + addend, sym_name);
2479 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend;
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002480 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002481 case R_AARCH64_ABS32:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002482 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002483 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002484 TRACE_TYPE(RELO, "RELO ABS32 %16llx <- %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002485 reloc, sym_addr + addend, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002486 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002487 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT32_MIN);
2488 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT32_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002489 if ((min_value <= (sym_addr + addend)) &&
2490 ((sym_addr + addend) <= max_value)) {
2491 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend;
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002492 } else {
2493 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002494 sym_addr + addend, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002495 return false;
2496 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002497 }
2498 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002499 case R_AARCH64_ABS16:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002500 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002501 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002502 TRACE_TYPE(RELO, "RELO ABS16 %16llx <- %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002503 reloc, sym_addr + addend, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002504 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002505 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN);
2506 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT16_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002507 if ((min_value <= (sym_addr + addend)) &&
2508 ((sym_addr + addend) <= max_value)) {
2509 *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002510 } else {
2511 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002512 sym_addr + addend, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002513 return false;
2514 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002515 }
2516 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002517 case R_AARCH64_PREL64:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002518 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002519 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002520 TRACE_TYPE(RELO, "RELO REL64 %16llx <- %16llx - %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002521 reloc, sym_addr + addend, rel->r_offset, sym_name);
2522 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset;
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002523 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002524 case R_AARCH64_PREL32:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002525 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002526 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002527 TRACE_TYPE(RELO, "RELO REL32 %16llx <- %16llx - %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002528 reloc, sym_addr + addend, rel->r_offset, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002529 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002530 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT32_MIN);
2531 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT32_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002532 if ((min_value <= (sym_addr + addend - rel->r_offset)) &&
2533 ((sym_addr + addend - rel->r_offset) <= max_value)) {
2534 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset;
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002535 } else {
2536 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002537 sym_addr + addend - rel->r_offset, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002538 return false;
2539 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002540 }
2541 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002542 case R_AARCH64_PREL16:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002543 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002544 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002545 TRACE_TYPE(RELO, "RELO REL16 %16llx <- %16llx - %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002546 reloc, sym_addr + addend, rel->r_offset, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002547 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002548 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN);
2549 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT16_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002550 if ((min_value <= (sym_addr + addend - rel->r_offset)) &&
2551 ((sym_addr + addend - rel->r_offset) <= max_value)) {
2552 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset;
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002553 } else {
2554 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002555 sym_addr + addend - rel->r_offset, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002556 return false;
2557 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002558 }
2559 break;
2560
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002561 case R_AARCH64_COPY:
Nick Kralevich76e289c2014-07-03 12:04:31 -07002562 /*
2563 * ET_EXEC is not supported so this should not happen.
2564 *
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002565 * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0056b/IHI0056B_aaelf64.pdf
Nick Kralevich76e289c2014-07-03 12:04:31 -07002566 *
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002567 * Section 4.6.11 "Dynamic relocations"
Nick Kralevich76e289c2014-07-03 12:04:31 -07002568 * R_AARCH64_COPY may only appear in executable objects where e_type is
2569 * set to ET_EXEC.
2570 */
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002571 DL_ERR("%s R_AARCH64_COPY relocations are not supported", get_realpath());
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002572 return false;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002573 case R_AARCH64_TLS_TPREL64:
Elliott Hughes0266ae52014-02-10 17:46:57 -08002574 TRACE_TYPE(RELO, "RELO TLS_TPREL64 *** %16llx <- %16llx - %16llx\n",
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002575 reloc, (sym_addr + addend), rel->r_offset);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002576 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002577 case R_AARCH64_TLS_DTPREL32:
Elliott Hughes0266ae52014-02-10 17:46:57 -08002578 TRACE_TYPE(RELO, "RELO TLS_DTPREL32 *** %16llx <- %16llx - %16llx\n",
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002579 reloc, (sym_addr + addend), rel->r_offset);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002580 break;
2581#elif defined(__x86_64__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002582 case R_X86_64_32:
2583 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002584 MARK(rel->r_offset);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002585 TRACE_TYPE(RELO, "RELO R_X86_64_32 %08zx <- +%08zx %s", static_cast<size_t>(reloc),
2586 static_cast<size_t>(sym_addr), sym_name);
Junichi Uekawaff35b1e2015-11-18 10:18:59 +09002587 *reinterpret_cast<Elf32_Addr*>(reloc) = sym_addr + addend;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002588 break;
2589 case R_X86_64_64:
2590 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002591 MARK(rel->r_offset);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002592 TRACE_TYPE(RELO, "RELO R_X86_64_64 %08zx <- +%08zx %s", static_cast<size_t>(reloc),
2593 static_cast<size_t>(sym_addr), sym_name);
Junichi Uekawaff35b1e2015-11-18 10:18:59 +09002594 *reinterpret_cast<Elf64_Addr*>(reloc) = sym_addr + addend;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002595 break;
2596 case R_X86_64_PC32:
2597 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002598 MARK(rel->r_offset);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002599 TRACE_TYPE(RELO, "RELO R_X86_64_PC32 %08zx <- +%08zx (%08zx - %08zx) %s",
2600 static_cast<size_t>(reloc), static_cast<size_t>(sym_addr - reloc),
2601 static_cast<size_t>(sym_addr), static_cast<size_t>(reloc), sym_name);
Junichi Uekawaff35b1e2015-11-18 10:18:59 +09002602 *reinterpret_cast<Elf32_Addr*>(reloc) = sym_addr + addend - reloc;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002603 break;
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002604#elif defined(__arm__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002605 case R_ARM_ABS32:
2606 count_relocation(kRelocAbsolute);
2607 MARK(rel->r_offset);
2608 TRACE_TYPE(RELO, "RELO ABS %08x <- %08x %s", reloc, sym_addr, sym_name);
2609 *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
2610 break;
2611 case R_ARM_REL32:
2612 count_relocation(kRelocRelative);
2613 MARK(rel->r_offset);
2614 TRACE_TYPE(RELO, "RELO REL32 %08x <- %08x - %08x %s",
2615 reloc, sym_addr, rel->r_offset, sym_name);
2616 *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr - rel->r_offset;
2617 break;
2618 case R_ARM_COPY:
2619 /*
2620 * ET_EXEC is not supported so this should not happen.
2621 *
2622 * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044d/IHI0044D_aaelf.pdf
2623 *
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002624 * Section 4.6.1.10 "Dynamic relocations"
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002625 * R_ARM_COPY may only appear in executable objects where e_type is
2626 * set to ET_EXEC.
2627 */
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002628 DL_ERR("%s R_ARM_COPY relocations are not supported", get_realpath());
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002629 return false;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002630#elif defined(__i386__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002631 case R_386_32:
2632 count_relocation(kRelocRelative);
2633 MARK(rel->r_offset);
2634 TRACE_TYPE(RELO, "RELO R_386_32 %08x <- +%08x %s", reloc, sym_addr, sym_name);
2635 *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
2636 break;
2637 case R_386_PC32:
2638 count_relocation(kRelocRelative);
2639 MARK(rel->r_offset);
2640 TRACE_TYPE(RELO, "RELO R_386_PC32 %08x <- +%08x (%08x - %08x) %s",
2641 reloc, (sym_addr - reloc), sym_addr, reloc, sym_name);
2642 *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr - reloc);
2643 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002644#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002645 default:
2646 DL_ERR("unknown reloc type %d @ %p (%zu)", type, rel, idx);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002647 return false;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002648 }
2649 }
2650 return true;
Raghu Gandhamd7daacb2012-07-31 12:07:22 -07002651}
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002652#endif // !defined(__mips__)
Raghu Gandhamd7daacb2012-07-31 12:07:22 -07002653
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002654// An empty list of soinfos
Dimitry Ivanovb943f302016-08-03 16:00:10 -07002655static soinfo_list_t g_empty_list;
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07002656
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002657bool soinfo::prelink_image() {
Ningsheng Jiane93be992014-09-16 15:22:10 +08002658 /* Extract dynamic section */
2659 ElfW(Word) dynamic_flags = 0;
2660 phdr_table_get_dynamic_section(phdr, phnum, load_bias, &dynamic, &dynamic_flags);
Dmitriy Ivanov498eb182014-09-05 14:57:59 -07002661
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002662 /* We can't log anything until the linker is relocated */
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002663 bool relocating_linker = (flags_ & FLAG_LINKER) != 0;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002664 if (!relocating_linker) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07002665 INFO("[ Linking \"%s\" ]", get_realpath());
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002666 DEBUG("si->base = %p si->flags = 0x%08x", reinterpret_cast<void*>(base), flags_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002667 }
2668
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002669 if (dynamic == nullptr) {
David 'Digit' Turnerb52e4382012-06-19 01:24:17 +02002670 if (!relocating_linker) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002671 DL_ERR("missing PT_DYNAMIC in \"%s\"", get_realpath());
David 'Digit' Turnerb52e4382012-06-19 01:24:17 +02002672 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002673 return false;
2674 } else {
2675 if (!relocating_linker) {
2676 DEBUG("dynamic = %p", dynamic);
David 'Digit' Turner63f99f42012-06-19 00:08:39 +02002677 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002678 }
David 'Digit' Turner63f99f42012-06-19 00:08:39 +02002679
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07002680#if defined(__arm__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002681 (void) phdr_table_get_arm_exidx(phdr, phnum, load_bias,
2682 &ARM_exidx, &ARM_exidx_count);
David 'Digit' Turner63f99f42012-06-19 00:08:39 +02002683#endif
2684
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002685 // Extract useful information from dynamic section.
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07002686 // Note that: "Except for the DT_NULL element at the end of the array,
2687 // and the relative order of DT_NEEDED elements, entries may appear in any order."
2688 //
2689 // source: http://www.sco.com/developers/gabi/1998-04-29/ch5.dynamic.html
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002690 uint32_t needed_count = 0;
2691 for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
2692 DEBUG("d = %p, d[0](tag) = %p d[1](val) = %p",
2693 d, reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
2694 switch (d->d_tag) {
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002695 case DT_SONAME:
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07002696 // this is parsed after we have strtab initialized (see below).
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002697 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002698
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002699 case DT_HASH:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002700 nbucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0];
2701 nchain_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
2702 bucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8);
2703 chain_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8 + nbucket_ * 4);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002704 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002705
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002706 case DT_GNU_HASH:
Dmitriy Ivanov3597b802015-03-09 12:02:02 -07002707 gnu_nbucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0];
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002708 // skip symndx
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002709 gnu_maskwords_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[2];
2710 gnu_shift2_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[3];
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002711
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002712 gnu_bloom_filter_ = reinterpret_cast<ElfW(Addr)*>(load_bias + d->d_un.d_ptr + 16);
Dmitriy Ivanov3597b802015-03-09 12:02:02 -07002713 gnu_bucket_ = reinterpret_cast<uint32_t*>(gnu_bloom_filter_ + gnu_maskwords_);
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002714 // amend chain for symndx = header[1]
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002715 gnu_chain_ = gnu_bucket_ + gnu_nbucket_ -
2716 reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002717
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002718 if (!powerof2(gnu_maskwords_)) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002719 DL_ERR("invalid maskwords for gnu_hash = 0x%x, in \"%s\" expecting power to two",
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002720 gnu_maskwords_, get_realpath());
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002721 return false;
2722 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002723 --gnu_maskwords_;
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002724
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002725 flags_ |= FLAG_GNU_HASH;
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002726 break;
2727
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002728 case DT_STRTAB:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002729 strtab_ = reinterpret_cast<const char*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002730 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002731
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07002732 case DT_STRSZ:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002733 strtab_size_ = d->d_un.d_val;
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07002734 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002735
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002736 case DT_SYMTAB:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002737 symtab_ = reinterpret_cast<ElfW(Sym)*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002738 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002739
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002740 case DT_SYMENT:
2741 if (d->d_un.d_val != sizeof(ElfW(Sym))) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002742 DL_ERR("invalid DT_SYMENT: %zd in \"%s\"",
2743 static_cast<size_t>(d->d_un.d_val), get_realpath());
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002744 return false;
2745 }
2746 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002747
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002748 case DT_PLTREL:
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002749#if defined(USE_RELA)
2750 if (d->d_un.d_val != DT_RELA) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002751 DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_RELA", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002752 return false;
2753 }
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002754#else
2755 if (d->d_un.d_val != DT_REL) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002756 DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_REL", get_realpath());
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002757 return false;
2758 }
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002759#endif
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002760 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002761
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002762 case DT_JMPREL:
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07002763#if defined(USE_RELA)
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002764 plt_rela_ = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002765#else
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002766 plt_rel_ = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002767#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002768 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002769
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002770 case DT_PLTRELSZ:
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07002771#if defined(USE_RELA)
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002772 plt_rela_count_ = d->d_un.d_val / sizeof(ElfW(Rela));
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002773#else
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002774 plt_rel_count_ = d->d_un.d_val / sizeof(ElfW(Rel));
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002775#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002776 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002777
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002778 case DT_PLTGOT:
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002779#if defined(__mips__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002780 // Used by mips and mips64.
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002781 plt_got_ = reinterpret_cast<ElfW(Addr)**>(load_bias + d->d_un.d_ptr);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002782#endif
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002783 // Ignore for other platforms... (because RTLD_LAZY is not supported)
2784 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002785
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002786 case DT_DEBUG:
2787 // Set the DT_DEBUG entry to the address of _r_debug for GDB
2788 // if the dynamic table is writable
Chris Dearman99186652014-02-06 20:36:51 -08002789// FIXME: not working currently for N64
2790// The flags for the LOAD and DYNAMIC program headers do not agree.
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002791// The LOAD section containing the dynamic table has been mapped as
Chris Dearman99186652014-02-06 20:36:51 -08002792// read-only, but the DYNAMIC header claims it is writable.
2793#if !(defined(__mips__) && defined(__LP64__))
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002794 if ((dynamic_flags & PF_W) != 0) {
2795 d->d_un.d_val = reinterpret_cast<uintptr_t>(&_r_debug);
2796 }
Chris Dearman99186652014-02-06 20:36:51 -08002797#endif
Dmitriy Ivanovc6292ea2015-02-13 16:29:50 -08002798 break;
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07002799#if defined(USE_RELA)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002800 case DT_RELA:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002801 rela_ = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002802 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002803
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002804 case DT_RELASZ:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002805 rela_count_ = d->d_un.d_val / sizeof(ElfW(Rela));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002806 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002807
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002808 case DT_ANDROID_RELA:
2809 android_relocs_ = reinterpret_cast<uint8_t*>(load_bias + d->d_un.d_ptr);
2810 break;
2811
2812 case DT_ANDROID_RELASZ:
2813 android_relocs_size_ = d->d_un.d_val;
2814 break;
2815
2816 case DT_ANDROID_REL:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002817 DL_ERR("unsupported DT_ANDROID_REL in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002818 return false;
2819
2820 case DT_ANDROID_RELSZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002821 DL_ERR("unsupported DT_ANDROID_RELSZ in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002822 return false;
2823
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002824 case DT_RELAENT:
2825 if (d->d_un.d_val != sizeof(ElfW(Rela))) {
Dmitriy Ivanovf240aa82014-09-16 23:34:20 -07002826 DL_ERR("invalid DT_RELAENT: %zd", static_cast<size_t>(d->d_un.d_val));
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002827 return false;
2828 }
2829 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002830
2831 // ignored (see DT_RELCOUNT comments for details)
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002832 case DT_RELACOUNT:
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002833 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002834
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002835 case DT_REL:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002836 DL_ERR("unsupported DT_REL in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002837 return false;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002838
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002839 case DT_RELSZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002840 DL_ERR("unsupported DT_RELSZ in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002841 return false;
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002842
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002843#else
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002844 case DT_REL:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002845 rel_ = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002846 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002847
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002848 case DT_RELSZ:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002849 rel_count_ = d->d_un.d_val / sizeof(ElfW(Rel));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002850 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002851
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002852 case DT_RELENT:
2853 if (d->d_un.d_val != sizeof(ElfW(Rel))) {
Dmitriy Ivanovf240aa82014-09-16 23:34:20 -07002854 DL_ERR("invalid DT_RELENT: %zd", static_cast<size_t>(d->d_un.d_val));
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002855 return false;
2856 }
2857 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002858
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002859 case DT_ANDROID_REL:
2860 android_relocs_ = reinterpret_cast<uint8_t*>(load_bias + d->d_un.d_ptr);
2861 break;
2862
2863 case DT_ANDROID_RELSZ:
2864 android_relocs_size_ = d->d_un.d_val;
2865 break;
2866
2867 case DT_ANDROID_RELA:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002868 DL_ERR("unsupported DT_ANDROID_RELA in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002869 return false;
2870
2871 case DT_ANDROID_RELASZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002872 DL_ERR("unsupported DT_ANDROID_RELASZ in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002873 return false;
2874
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002875 // "Indicates that all RELATIVE relocations have been concatenated together,
2876 // and specifies the RELATIVE relocation count."
2877 //
2878 // TODO: Spec also mentions that this can be used to optimize relocation process;
2879 // Not currently used by bionic linker - ignored.
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002880 case DT_RELCOUNT:
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002881 break;
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002882
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002883 case DT_RELA:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002884 DL_ERR("unsupported DT_RELA in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002885 return false;
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002886
2887 case DT_RELASZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002888 DL_ERR("unsupported DT_RELASZ in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002889 return false;
2890
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002891#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002892 case DT_INIT:
Dimitry Ivanov55437462016-07-20 15:33:07 -07002893 init_func_ = reinterpret_cast<linker_ctor_function_t>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002894 DEBUG("%s constructors (DT_INIT) found at %p", get_realpath(), init_func_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002895 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002896
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002897 case DT_FINI:
Dimitry Ivanov55437462016-07-20 15:33:07 -07002898 fini_func_ = reinterpret_cast<linker_dtor_function_t>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002899 DEBUG("%s destructors (DT_FINI) found at %p", get_realpath(), fini_func_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002900 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002901
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002902 case DT_INIT_ARRAY:
Dimitry Ivanov55437462016-07-20 15:33:07 -07002903 init_array_ = reinterpret_cast<linker_ctor_function_t*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002904 DEBUG("%s constructors (DT_INIT_ARRAY) found at %p", get_realpath(), init_array_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002905 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002906
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002907 case DT_INIT_ARRAYSZ:
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -08002908 init_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002909 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002910
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002911 case DT_FINI_ARRAY:
Dimitry Ivanov55437462016-07-20 15:33:07 -07002912 fini_array_ = reinterpret_cast<linker_dtor_function_t*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002913 DEBUG("%s destructors (DT_FINI_ARRAY) found at %p", get_realpath(), fini_array_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002914 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002915
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002916 case DT_FINI_ARRAYSZ:
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -08002917 fini_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002918 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002919
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002920 case DT_PREINIT_ARRAY:
Dimitry Ivanov55437462016-07-20 15:33:07 -07002921 preinit_array_ = reinterpret_cast<linker_ctor_function_t*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002922 DEBUG("%s constructors (DT_PREINIT_ARRAY) found at %p", get_realpath(), preinit_array_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002923 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002924
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002925 case DT_PREINIT_ARRAYSZ:
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -08002926 preinit_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002927 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002928
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002929 case DT_TEXTREL:
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00002930#if defined(__LP64__)
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002931 DL_ERR("text relocations (DT_TEXTREL) found in 64-bit ELF file \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002932 return false;
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00002933#else
2934 has_text_relocations = true;
2935 break;
2936#endif
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002937
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002938 case DT_SYMBOLIC:
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -07002939 has_DT_SYMBOLIC = true;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002940 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002941
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002942 case DT_NEEDED:
2943 ++needed_count;
2944 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002945
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002946 case DT_FLAGS:
2947 if (d->d_un.d_val & DF_TEXTREL) {
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00002948#if defined(__LP64__)
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002949 DL_ERR("text relocations (DF_TEXTREL) found in 64-bit ELF file \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002950 return false;
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00002951#else
2952 has_text_relocations = true;
2953#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002954 }
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -07002955 if (d->d_un.d_val & DF_SYMBOLIC) {
2956 has_DT_SYMBOLIC = true;
2957 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002958 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002959
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07002960 case DT_FLAGS_1:
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07002961 set_dt_flags_1(d->d_un.d_val);
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -07002962
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07002963 if ((d->d_un.d_val & ~SUPPORTED_DT_FLAGS_1) != 0) {
Dmitriy Ivanov087005f2015-05-28 11:44:31 -07002964 DL_WARN("%s: unsupported flags DT_FLAGS_1=%p", get_realpath(), reinterpret_cast<void*>(d->d_un.d_val));
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07002965 }
2966 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002967#if defined(__mips__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002968 case DT_MIPS_RLD_MAP:
2969 // Set the DT_MIPS_RLD_MAP entry to the address of _r_debug for GDB.
2970 {
2971 r_debug** dp = reinterpret_cast<r_debug**>(load_bias + d->d_un.d_ptr);
2972 *dp = &_r_debug;
2973 }
2974 break;
Lazar Trsic83b44a92016-04-06 13:39:17 +02002975 case DT_MIPS_RLD_MAP_REL:
2976 // Set the DT_MIPS_RLD_MAP_REL entry to the address of _r_debug for GDB.
Raghu Gandham68815722014-12-18 19:12:19 -08002977 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002978 r_debug** dp = reinterpret_cast<r_debug**>(
2979 reinterpret_cast<ElfW(Addr)>(d) + d->d_un.d_val);
Raghu Gandham68815722014-12-18 19:12:19 -08002980 *dp = &_r_debug;
2981 }
2982 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002983
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002984 case DT_MIPS_RLD_VERSION:
2985 case DT_MIPS_FLAGS:
2986 case DT_MIPS_BASE_ADDRESS:
2987 case DT_MIPS_UNREFEXTNO:
2988 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002989
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002990 case DT_MIPS_SYMTABNO:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002991 mips_symtabno_ = d->d_un.d_val;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002992 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002993
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002994 case DT_MIPS_LOCAL_GOTNO:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002995 mips_local_gotno_ = d->d_un.d_val;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002996 break;
2997
2998 case DT_MIPS_GOTSYM:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002999 mips_gotsym_ = d->d_un.d_val;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003000 break;
3001#endif
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003002 // Ignored: "Its use has been superseded by the DF_BIND_NOW flag"
3003 case DT_BIND_NOW:
3004 break;
3005
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003006 case DT_VERSYM:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003007 versym_ = reinterpret_cast<ElfW(Versym)*>(load_bias + d->d_un.d_ptr);
3008 break;
3009
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003010 case DT_VERDEF:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003011 verdef_ptr_ = load_bias + d->d_un.d_ptr;
3012 break;
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003013 case DT_VERDEFNUM:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003014 verdef_cnt_ = d->d_un.d_val;
3015 break;
3016
Alexander Ivchenkoe8314332014-12-02 15:32:25 +03003017 case DT_VERNEED:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003018 verneed_ptr_ = load_bias + d->d_un.d_ptr;
3019 break;
3020
Alexander Ivchenkoe8314332014-12-02 15:32:25 +03003021 case DT_VERNEEDNUM:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003022 verneed_cnt_ = d->d_un.d_val;
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003023 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003024
Evgenii Stepanov68650822015-06-10 13:38:39 -07003025 case DT_RUNPATH:
3026 // this is parsed after we have strtab initialized (see below).
3027 break;
3028
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003029 default:
Dmitriy Ivanov8f61d992014-09-16 14:31:06 -07003030 if (!relocating_linker) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003031 DL_WARN("%s: unused DT entry: type %p arg %p", get_realpath(),
Dmitriy Ivanov8f61d992014-09-16 14:31:06 -07003032 reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
3033 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003034 break;
Brian Carlstromd4ee82d2013-02-28 15:58:45 -08003035 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003036 }
3037
Duane Sandbc425c72015-06-01 16:29:14 -07003038#if defined(__mips__) && !defined(__LP64__)
3039 if (!mips_check_and_adjust_fp_modes()) {
3040 return false;
3041 }
3042#endif
3043
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003044 DEBUG("si->base = %p, si->strtab = %p, si->symtab = %p",
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003045 reinterpret_cast<void*>(base), strtab_, symtab_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003046
3047 // Sanity checks.
3048 if (relocating_linker && needed_count != 0) {
3049 DL_ERR("linker cannot have DT_NEEDED dependencies on other libraries");
3050 return false;
3051 }
Dmitriy Ivanov3597b802015-03-09 12:02:02 -07003052 if (nbucket_ == 0 && gnu_nbucket_ == 0) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003053 DL_ERR("empty/missing DT_HASH/DT_GNU_HASH in \"%s\" "
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003054 "(new hash type from the future?)", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003055 return false;
3056 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003057 if (strtab_ == 0) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003058 DL_ERR("empty/missing DT_STRTAB in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003059 return false;
3060 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003061 if (symtab_ == 0) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003062 DL_ERR("empty/missing DT_SYMTAB in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003063 return false;
3064 }
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003065
Dmitriy Ivanov624b8f12015-06-08 10:41:33 -07003066 // second pass - parse entries relying on strtab
3067 for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
Evgenii Stepanov68650822015-06-10 13:38:39 -07003068 switch (d->d_tag) {
3069 case DT_SONAME:
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07003070 set_soname(get_string(d->d_un.d_val));
Evgenii Stepanov68650822015-06-10 13:38:39 -07003071 break;
3072 case DT_RUNPATH:
Evgenii Stepanov68650822015-06-10 13:38:39 -07003073 set_dt_runpath(get_string(d->d_un.d_val));
3074 break;
Dmitriy Ivanov624b8f12015-06-08 10:41:33 -07003075 }
3076 }
3077
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003078 // Before M release linker was using basename in place of soname.
Dmitriy Ivanov19133522015-06-02 17:36:54 -07003079 // In the case when dt_soname is absent some apps stop working
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003080 // because they can't find dt_needed library by soname.
3081 // This workaround should keep them working. (applies only
Dmitriy Ivanov19133522015-06-02 17:36:54 -07003082 // for apps targeting sdk version <=22). Make an exception for
3083 // the main executable and linker; they do not need to have dt_soname
3084 if (soname_ == nullptr && this != somain && (flags_ & FLAG_LINKER) == 0 &&
3085 get_application_target_sdk_version() <= 22) {
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003086 soname_ = basename(realpath_.c_str());
3087 DL_WARN("%s: is missing DT_SONAME will use basename as a replacement: \"%s\"",
3088 get_realpath(), soname_);
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07003089 // 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 -07003090 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003091 return true;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07003092}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003093
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003094bool soinfo::link_image(const soinfo_list_t& global_group, const soinfo_list_t& local_group,
3095 const android_dlextinfo* extinfo) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003096
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08003097 local_group_root_ = local_group.front();
3098 if (local_group_root_ == nullptr) {
3099 local_group_root_ = this;
3100 }
3101
Dmitriy Ivanov19133522015-06-02 17:36:54 -07003102 if ((flags_ & FLAG_LINKER) == 0 && local_group_root_ == this) {
3103 target_sdk_version_ = get_application_target_sdk_version();
3104 }
3105
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003106 VersionTracker version_tracker;
3107
3108 if (!version_tracker.init(this)) {
3109 return false;
3110 }
3111
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003112#if !defined(__LP64__)
3113 if (has_text_relocations) {
Dmitriy Ivanove4ad91f2015-06-12 15:00:31 -07003114 // Fail if app is targeting sdk version > 22
Dmitriy Ivanov80687862015-10-09 13:58:46 -07003115 if (get_application_target_sdk_version() > 22) {
Dmitriy Ivanovfae39d22015-10-13 11:07:56 -07003116 PRINT("%s: has text relocations", get_realpath());
Dmitriy Ivanove4ad91f2015-06-12 15:00:31 -07003117 DL_ERR("%s: has text relocations", get_realpath());
3118 return false;
3119 }
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003120 // Make segments writable to allow text relocations to work properly. We will later call
Dmitriy Ivanov7e039932015-10-01 14:02:19 -07003121 // phdr_table_protect_segments() after all of them are applied.
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003122 DL_WARN("%s has text relocations. This is wasting memory and prevents "
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003123 "security hardening. Please fix.", get_realpath());
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07003124 add_dlwarning(get_realpath(), "text relocations");
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003125 if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
3126 DL_ERR("can't unprotect loadable segments for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003127 get_realpath(), strerror(errno));
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003128 return false;
3129 }
3130 }
3131#endif
3132
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003133 if (android_relocs_ != nullptr) {
3134 // check signature
3135 if (android_relocs_size_ > 3 &&
3136 android_relocs_[0] == 'A' &&
3137 android_relocs_[1] == 'P' &&
Dmitriy Ivanov18870d32015-04-22 13:10:04 -07003138 android_relocs_[2] == 'S' &&
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003139 android_relocs_[3] == '2') {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003140 DEBUG("[ android relocating %s ]", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003141
3142 bool relocated = false;
3143 const uint8_t* packed_relocs = android_relocs_ + 4;
3144 const size_t packed_relocs_size = android_relocs_size_ - 4;
3145
Dmitriy Ivanov18870d32015-04-22 13:10:04 -07003146 relocated = relocate(
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003147 version_tracker,
Dmitriy Ivanov18870d32015-04-22 13:10:04 -07003148 packed_reloc_iterator<sleb128_decoder>(
3149 sleb128_decoder(packed_relocs, packed_relocs_size)),
3150 global_group, local_group);
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003151
3152 if (!relocated) {
3153 return false;
3154 }
3155 } else {
3156 DL_ERR("bad android relocation header.");
3157 return false;
3158 }
3159 }
3160
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07003161#if defined(USE_RELA)
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003162 if (rela_ != nullptr) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003163 DEBUG("[ relocating %s ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003164 if (!relocate(version_tracker,
3165 plain_reloc_iterator(rela_, rela_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003166 return false;
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07003167 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003168 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003169 if (plt_rela_ != nullptr) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003170 DEBUG("[ relocating %s plt ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003171 if (!relocate(version_tracker,
3172 plain_reloc_iterator(plt_rela_, plt_rela_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003173 return false;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003174 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003175 }
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07003176#else
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003177 if (rel_ != nullptr) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003178 DEBUG("[ relocating %s ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003179 if (!relocate(version_tracker,
3180 plain_reloc_iterator(rel_, rel_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003181 return false;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003182 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003183 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003184 if (plt_rel_ != nullptr) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003185 DEBUG("[ relocating %s plt ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003186 if (!relocate(version_tracker,
3187 plain_reloc_iterator(plt_rel_, plt_rel_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003188 return false;
Brigid Smithc5a13ef2014-07-23 11:22:25 -07003189 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003190 }
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07003191#endif
Brigid Smithc5a13ef2014-07-23 11:22:25 -07003192
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07003193#if defined(__mips__)
Dmitriy Ivanovf39cb632015-04-30 20:17:03 -07003194 if (!mips_relocate_got(version_tracker, global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003195 return false;
3196 }
Raghu Gandhamd7daacb2012-07-31 12:07:22 -07003197#endif
3198
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003199 DEBUG("[ finished linking %s ]", get_realpath());
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003200
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003201#if !defined(__LP64__)
3202 if (has_text_relocations) {
3203 // All relocations are done, we can protect our segments back to read-only.
3204 if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
3205 DL_ERR("can't protect segments for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003206 get_realpath(), strerror(errno));
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003207 return false;
3208 }
3209 }
3210#endif
3211
Mingwei Shibe910522015-11-12 07:02:14 +00003212 // We can also turn on GNU RELRO protection if we're not linking the dynamic linker
3213 // itself --- it can't make system calls yet, and will have to call protect_relro later.
3214 if (!is_linker() && !protect_relro()) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003215 return false;
3216 }
Nick Kralevich9ec0f032012-02-28 10:40:00 -08003217
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003218 /* Handle serializing/sharing the RELRO segment */
3219 if (extinfo && (extinfo->flags & ANDROID_DLEXT_WRITE_RELRO)) {
3220 if (phdr_table_serialize_gnu_relro(phdr, phnum, load_bias,
3221 extinfo->relro_fd) < 0) {
3222 DL_ERR("failed serializing GNU RELRO section for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003223 get_realpath(), strerror(errno));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003224 return false;
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +00003225 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003226 } else if (extinfo && (extinfo->flags & ANDROID_DLEXT_USE_RELRO)) {
3227 if (phdr_table_map_gnu_relro(phdr, phnum, load_bias,
3228 extinfo->relro_fd) < 0) {
3229 DL_ERR("failed mapping GNU RELRO section for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003230 get_realpath(), strerror(errno));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003231 return false;
3232 }
3233 }
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +00003234
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003235 notify_gdb_of_load(this);
3236 return true;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003237}
3238
Mingwei Shibe910522015-11-12 07:02:14 +00003239bool soinfo::protect_relro() {
3240 if (phdr_table_protect_gnu_relro(phdr, phnum, load_bias) < 0) {
3241 DL_ERR("can't enable GNU RELRO protection for \"%s\": %s",
3242 get_realpath(), strerror(errno));
3243 return false;
3244 }
3245 return true;
3246}
3247
Nick Kralevich468319c2011-11-11 15:53:17 -08003248/*
Sergey Melnikovc45087b2013-01-25 16:40:13 +04003249 * This function add vdso to internal dso list.
3250 * It helps to stack unwinding through signal handlers.
3251 * Also, it makes bionic more like glibc.
3252 */
Kito Cheng812fd422014-03-25 22:53:56 +08003253static void add_vdso(KernelArgumentBlock& args __unused) {
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07003254#if defined(AT_SYSINFO_EHDR)
Elliott Hughes0266ae52014-02-10 17:46:57 -08003255 ElfW(Ehdr)* ehdr_vdso = reinterpret_cast<ElfW(Ehdr)*>(args.getauxval(AT_SYSINFO_EHDR));
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07003256 if (ehdr_vdso == nullptr) {
Elliott Hughes0266ae52014-02-10 17:46:57 -08003257 return;
3258 }
Sergey Melnikovc45087b2013-01-25 16:40:13 +04003259
Dmitriy Ivanovd9b08a02015-11-16 13:17:27 -08003260 soinfo* si = soinfo_alloc(&g_default_namespace, "[vdso]", nullptr, 0, 0);
Sergey Melnikovebd506c2013-10-31 18:02:12 +04003261
Elliott Hughes0266ae52014-02-10 17:46:57 -08003262 si->phdr = reinterpret_cast<ElfW(Phdr)*>(reinterpret_cast<char*>(ehdr_vdso) + ehdr_vdso->e_phoff);
3263 si->phnum = ehdr_vdso->e_phnum;
3264 si->base = reinterpret_cast<ElfW(Addr)>(ehdr_vdso);
3265 si->size = phdr_table_get_load_size(si->phdr, si->phnum);
Elliott Hughes0266ae52014-02-10 17:46:57 -08003266 si->load_bias = get_elf_exec_load_bias(ehdr_vdso);
Sergey Melnikovebd506c2013-10-31 18:02:12 +04003267
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003268 si->prelink_image();
Dimitry Ivanovb943f302016-08-03 16:00:10 -07003269 si->link_image(g_empty_list, soinfo_list_t::make_list(si), nullptr);
Sergey Melnikovc45087b2013-01-25 16:40:13 +04003270#endif
3271}
3272
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07003273/* gdb expects the linker to be in the debug shared object list.
3274 * Without this, gdb has trouble locating the linker's ".text"
3275 * and ".plt" sections. Gdb could also potentially use this to
3276 * relocate the offset of our exported 'rtld_db_dlactivity' symbol.
Dimitry Ivanov64001292016-02-17 14:13:06 -08003277 * Note that the linker shouldn't be on the soinfo list.
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07003278 */
3279static void init_linker_info_for_gdb(ElfW(Addr) linker_base) {
Dimitry Ivanov8d22dd52016-02-16 13:43:35 -08003280 static link_map linker_link_map_for_gdb;
3281#if defined(__LP64__)
3282 static char kLinkerPath[] = "/system/bin/linker64";
3283#else
3284 static char kLinkerPath[] = "/system/bin/linker";
3285#endif
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003286
Dimitry Ivanov8d22dd52016-02-16 13:43:35 -08003287 linker_link_map_for_gdb.l_addr = linker_base;
3288 linker_link_map_for_gdb.l_name = kLinkerPath;
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07003289
3290 /*
3291 * Set the dynamic field in the link map otherwise gdb will complain with
3292 * the following:
3293 * warning: .dynamic section for "/system/bin/linker" is not at the
3294 * expected address (wrong library or version mismatch?)
3295 */
3296 ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_base);
3297 ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(linker_base + elf_hdr->e_phoff);
3298 phdr_table_get_dynamic_section(phdr, elf_hdr->e_phnum, linker_base,
Dimitry Ivanov8d22dd52016-02-16 13:43:35 -08003299 &linker_link_map_for_gdb.l_ld, nullptr);
3300
3301 insert_link_map_into_debug_map(&linker_link_map_for_gdb);
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07003302}
3303
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003304static void init_default_namespace() {
3305 g_default_namespace.set_name("(default)");
3306 g_default_namespace.set_isolated(false);
3307
Evgenii Stepanovd640b222015-07-10 17:54:01 -07003308 const char *interp = phdr_table_get_interpreter_name(somain->phdr, somain->phnum,
3309 somain->load_bias);
3310 const char* bname = basename(interp);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003311 if (bname && (strcmp(bname, "linker_asan") == 0 || strcmp(bname, "linker_asan64") == 0)) {
Evgenii Stepanovd640b222015-07-10 17:54:01 -07003312 g_default_ld_paths = kAsanDefaultLdPaths;
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -07003313 g_is_asan = true;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003314 } else {
Evgenii Stepanovd640b222015-07-10 17:54:01 -07003315 g_default_ld_paths = kDefaultLdPaths;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003316 }
3317
3318 std::vector<std::string> ld_default_paths;
3319 for (size_t i = 0; g_default_ld_paths[i] != nullptr; ++i) {
3320 ld_default_paths.push_back(g_default_ld_paths[i]);
3321 }
3322
3323 g_default_namespace.set_default_library_paths(std::move(ld_default_paths));
Evgenii Stepanovd640b222015-07-10 17:54:01 -07003324};
3325
Dmitriy Ivanovb4e50672015-04-28 15:49:26 -07003326extern "C" int __system_properties_init(void);
3327
Dimitry Ivanov2ba1cf32016-05-17 13:29:37 -07003328static const char* get_executable_path() {
3329 static std::string executable_path;
3330 if (executable_path.empty()) {
3331 char path[PATH_MAX];
3332 ssize_t path_len = readlink("/proc/self/exe", path, sizeof(path));
3333 if (path_len == -1 || path_len >= static_cast<ssize_t>(sizeof(path))) {
3334 __libc_fatal("readlink('/proc/self/exe') failed: %s", strerror(errno));
3335 }
3336 executable_path = std::string(path, path_len);
3337 }
3338
3339 return executable_path.c_str();
3340}
3341
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07003342/*
Nick Kralevich468319c2011-11-11 15:53:17 -08003343 * This code is called after the linker has linked itself and
3344 * fixed it's own GOT. It is safe to make references to externs
3345 * and other non-local data at this point.
3346 */
Elliott Hughes0266ae52014-02-10 17:46:57 -08003347static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(Addr) linker_base) {
Evgeniy Stepanov1a78fbb2012-03-22 18:01:53 +04003348#if TIMING
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003349 struct timeval t0, t1;
3350 gettimeofday(&t0, 0);
Evgeniy Stepanov1a78fbb2012-03-22 18:01:53 +04003351#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003352
Elliott Hughes1801db32015-06-08 18:04:00 -07003353 // Sanitize the environment.
3354 __libc_init_AT_SECURE(args);
David 'Digit' Turnerbe575592010-12-16 19:52:02 +01003355
Dmitriy Ivanovb4e50672015-04-28 15:49:26 -07003356 // Initialize system properties
3357 __system_properties_init(); // may use 'environ'
3358
Josh Gao3cc387e2016-06-15 18:33:26 -07003359 // Register the debuggerd signal handler.
3360 debuggerd_callbacks_t callbacks = {
3361 .get_abort_message = []() {
3362 return g_abort_message;
3363 },
3364 .post_dump = &notify_gdb_of_libraries,
3365 };
3366 debuggerd_init(&callbacks);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003367
Dimitry Ivanovb996d602016-07-11 18:11:39 -07003368 g_linker_logger.ResetState();
3369
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003370 // Get a few environment variables.
Elliott Hughes1801db32015-06-08 18:04:00 -07003371 const char* LD_DEBUG = getenv("LD_DEBUG");
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003372 if (LD_DEBUG != nullptr) {
3373 g_ld_debug_verbosity = atoi(LD_DEBUG);
3374 }
3375
Elliott Hughes116b5692016-01-04 17:45:36 -08003376#if defined(__LP64__)
3377 INFO("[ Android dynamic linker (64-bit) ]");
3378#else
3379 INFO("[ Android dynamic linker (32-bit) ]");
3380#endif
3381
Elliott Hughes1801db32015-06-08 18:04:00 -07003382 // These should have been sanitized by __libc_init_AT_SECURE, but the test
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003383 // doesn't cost us anything.
3384 const char* ldpath_env = nullptr;
3385 const char* ldpreload_env = nullptr;
Elliott Hughes1801db32015-06-08 18:04:00 -07003386 if (!getauxval(AT_SECURE)) {
3387 ldpath_env = getenv("LD_LIBRARY_PATH");
Elliott Hughes116b5692016-01-04 17:45:36 -08003388 if (ldpath_env != nullptr) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07003389 INFO("[ LD_LIBRARY_PATH set to \"%s\" ]", ldpath_env);
Elliott Hughes116b5692016-01-04 17:45:36 -08003390 }
Elliott Hughes1801db32015-06-08 18:04:00 -07003391 ldpreload_env = getenv("LD_PRELOAD");
Elliott Hughes116b5692016-01-04 17:45:36 -08003392 if (ldpreload_env != nullptr) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07003393 INFO("[ LD_PRELOAD set to \"%s\" ]", ldpreload_env);
Elliott Hughes116b5692016-01-04 17:45:36 -08003394 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003395 }
3396
Dimitry Ivanov2ba1cf32016-05-17 13:29:37 -07003397 struct stat file_stat;
Dimitry Ivanovf4e3ebe2016-08-25 14:53:35 -07003398 // Stat "/proc/self/exe" instead of executable_path because
3399 // the executable could be unlinked by this point and it should
3400 // not cause a crash (see http://b/31084669)
3401 if (TEMP_FAILURE_RETRY(stat("/proc/self/exe", &file_stat)) != 0) {
3402 __libc_fatal("unable to stat \"/proc/self/exe\": %s", strerror(errno));
Dimitry Ivanov2ba1cf32016-05-17 13:29:37 -07003403 }
3404
Dimitry Ivanovf4e3ebe2016-08-25 14:53:35 -07003405 const char* executable_path = get_executable_path();
Dimitry Ivanov2ba1cf32016-05-17 13:29:37 -07003406 soinfo* si = soinfo_alloc(&g_default_namespace, executable_path, &file_stat, 0, RTLD_GLOBAL);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003407 if (si == nullptr) {
Dimitry Ivanov9f0a6952016-02-18 14:37:44 -08003408 __libc_fatal("Couldn't allocate soinfo: out of memory?");
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003409 }
3410
3411 /* bootstrap the link map, the main exe always needs to be first */
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08003412 si->set_main_executable();
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003413 link_map* map = &(si->link_map_head);
3414
Dimitry Ivanove97d8ed2016-03-01 15:55:56 -08003415 // Register the main executable and the linker upfront to have
3416 // gdb aware of them before loading the rest of the dependency
3417 // tree.
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003418 map->l_addr = 0;
Dimitry Ivanov2ba1cf32016-05-17 13:29:37 -07003419 map->l_name = const_cast<char*>(executable_path);
Dimitry Ivanovf3064e42016-02-17 15:25:25 -08003420 insert_link_map_into_debug_map(map);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003421 init_linker_info_for_gdb(linker_base);
3422
3423 // Extract information passed from the kernel.
3424 si->phdr = reinterpret_cast<ElfW(Phdr)*>(args.getauxval(AT_PHDR));
3425 si->phnum = args.getauxval(AT_PHNUM);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003426
3427 /* Compute the value of si->base. We can't rely on the fact that
3428 * the first entry is the PHDR because this will not be true
3429 * for certain executables (e.g. some in the NDK unit test suite)
3430 */
3431 si->base = 0;
3432 si->size = phdr_table_get_load_size(si->phdr, si->phnum);
3433 si->load_bias = 0;
3434 for (size_t i = 0; i < si->phnum; ++i) {
3435 if (si->phdr[i].p_type == PT_PHDR) {
3436 si->load_bias = reinterpret_cast<ElfW(Addr)>(si->phdr) - si->phdr[i].p_vaddr;
3437 si->base = reinterpret_cast<ElfW(Addr)>(si->phdr) - si->phdr[i].p_offset;
3438 break;
Nick Kralevich8d3e91d2013-04-25 13:15:24 -07003439 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003440 }
3441 si->dynamic = nullptr;
Nick Kralevich8d3e91d2013-04-25 13:15:24 -07003442
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003443 ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(si->base);
3444 if (elf_hdr->e_type != ET_DYN) {
Dimitry Ivanov9f0a6952016-02-18 14:37:44 -08003445 __libc_fatal("\"%s\": error: only position independent executables (PIE) are supported.",
Dimitry Ivanov55437462016-07-20 15:33:07 -07003446 g_argv[0]);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003447 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003448
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003449 // Use LD_LIBRARY_PATH and LD_PRELOAD (but only if we aren't setuid/setgid).
3450 parse_LD_LIBRARY_PATH(ldpath_env);
3451 parse_LD_PRELOAD(ldpreload_env);
David 'Digit' Turnerbe575592010-12-16 19:52:02 +01003452
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003453 somain = si;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003454
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003455 init_default_namespace();
Evgenii Stepanovd640b222015-07-10 17:54:01 -07003456
Dmitriy Ivanov67181252015-01-07 15:48:25 -08003457 if (!si->prelink_image()) {
Dimitry Ivanov55437462016-07-20 15:33:07 -07003458 __libc_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", g_argv[0], linker_get_error_buffer());
Dmitriy Ivanov67181252015-01-07 15:48:25 -08003459 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003460
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07003461 // add somain to global group
3462 si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL);
3463
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003464 // Load ld_preloads and dependencies.
3465 StringLinkedList needed_library_name_list;
3466 size_t needed_libraries_count = 0;
3467 size_t ld_preloads_count = 0;
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07003468
3469 for (const auto& ld_preload_name : g_ld_preload_names) {
3470 needed_library_name_list.push_back(ld_preload_name.c_str());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003471 ++needed_libraries_count;
Dmitriy Ivanovf8093a92015-04-28 18:09:53 -07003472 ++ld_preloads_count;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003473 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003474
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003475 for_each_dt_needed(si, [&](const char* name) {
3476 needed_library_name_list.push_back(name);
3477 ++needed_libraries_count;
3478 });
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003479
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003480 const char* needed_library_names[needed_libraries_count];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003481
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003482 memset(needed_library_names, 0, sizeof(needed_library_names));
3483 needed_library_name_list.copy_to_array(needed_library_names, needed_libraries_count);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003484
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07003485 if (needed_libraries_count > 0 &&
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003486 !find_libraries(&g_default_namespace, si, needed_library_names, needed_libraries_count,
3487 nullptr, &g_ld_preloads, ld_preloads_count, RTLD_GLOBAL, nullptr,
Evgenii Stepanov0cdef7e2015-07-06 17:56:31 -07003488 /* add_as_children */ true)) {
Dimitry Ivanov55437462016-07-20 15:33:07 -07003489 __libc_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", g_argv[0], linker_get_error_buffer());
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08003490 } else if (needed_libraries_count == 0) {
Dimitry Ivanovb943f302016-08-03 16:00:10 -07003491 if (!si->link_image(g_empty_list, soinfo_list_t::make_list(si), nullptr)) {
Dimitry Ivanov55437462016-07-20 15:33:07 -07003492 __libc_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", g_argv[0], linker_get_error_buffer());
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08003493 }
3494 si->increment_ref_count();
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003495 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003496
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003497 add_vdso(args);
Nick Kralevich2aebf542014-05-07 10:32:39 -07003498
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -08003499 {
3500 ProtectedDataGuard guard;
Matt Fischer4fd42c12009-12-31 12:09:10 -06003501
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -08003502 si->call_pre_init_constructors();
3503
3504 /* After the prelink_image, the si->load_bias is initialized.
3505 * For so lib, the map->l_addr will be updated in notify_gdb_of_load.
3506 * We need to update this value for so exe here. So Unwind_Backtrace
3507 * for some arch like x86 could work correctly within so exe.
3508 */
3509 map->l_addr = si->load_bias;
3510 si->call_constructors();
3511 }
Evgeniy Stepanove83c56d2011-12-21 13:03:54 +04003512
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003513#if TIMING
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003514 gettimeofday(&t1, nullptr);
Dimitry Ivanov55437462016-07-20 15:33:07 -07003515 PRINT("LINKER TIME: %s: %d microseconds", g_argv[0], (int) (
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003516 (((long long)t1.tv_sec * 1000000LL) + (long long)t1.tv_usec) -
3517 (((long long)t0.tv_sec * 1000000LL) + (long long)t0.tv_usec)));
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003518#endif
3519#if STATS
Dimitry Ivanov55437462016-07-20 15:33:07 -07003520 PRINT("RELO STATS: %s: %d abs, %d rel, %d copy, %d symbol", g_argv[0],
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003521 linker_stats.count[kRelocAbsolute],
3522 linker_stats.count[kRelocRelative],
3523 linker_stats.count[kRelocCopy],
3524 linker_stats.count[kRelocSymbol]);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003525#endif
3526#if COUNT_PAGES
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003527 {
3528 unsigned n;
3529 unsigned i;
3530 unsigned count = 0;
3531 for (n = 0; n < 4096; n++) {
3532 if (bitmask[n]) {
3533 unsigned x = bitmask[n];
Marcus Oaklande365f9d2013-10-10 15:19:31 +01003534#if defined(__LP64__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003535 for (i = 0; i < 32; i++) {
Marcus Oaklande365f9d2013-10-10 15:19:31 +01003536#else
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003537 for (i = 0; i < 8; i++) {
Marcus Oaklande365f9d2013-10-10 15:19:31 +01003538#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003539 if (x & 1) {
3540 count++;
3541 }
3542 x >>= 1;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003543 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003544 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003545 }
Dimitry Ivanov55437462016-07-20 15:33:07 -07003546 PRINT("PAGES MODIFIED: %s: %d (%dKB)", g_argv[0], count, count * 4);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003547 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003548#endif
3549
3550#if TIMING || STATS || COUNT_PAGES
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003551 fflush(stdout);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003552#endif
3553
Dimitry Ivanove687d062016-02-16 13:25:29 -08003554 ElfW(Addr) entry = args.getauxval(AT_ENTRY);
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07003555 TRACE("[ Ready to execute \"%s\" @ %p ]", si->get_realpath(), reinterpret_cast<void*>(entry));
Dimitry Ivanove687d062016-02-16 13:25:29 -08003556 return entry;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003557}
Nick Kralevich468319c2011-11-11 15:53:17 -08003558
David 'Digit' Turnerbea23e52012-06-18 23:38:46 +02003559/* Compute the load-bias of an existing executable. This shall only
3560 * be used to compute the load bias of an executable or shared library
3561 * that was loaded by the kernel itself.
3562 *
3563 * Input:
3564 * elf -> address of ELF header, assumed to be at the start of the file.
3565 * Return:
3566 * load bias, i.e. add the value of any p_vaddr in the file to get
3567 * the corresponding address in memory.
3568 */
Elliott Hughes0266ae52014-02-10 17:46:57 -08003569static ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf) {
3570 ElfW(Addr) offset = elf->e_phoff;
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003571 const ElfW(Phdr)* phdr_table =
3572 reinterpret_cast<const ElfW(Phdr)*>(reinterpret_cast<uintptr_t>(elf) + offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08003573 const ElfW(Phdr)* phdr_end = phdr_table + elf->e_phnum;
David 'Digit' Turnerbea23e52012-06-18 23:38:46 +02003574
Elliott Hughes0266ae52014-02-10 17:46:57 -08003575 for (const ElfW(Phdr)* phdr = phdr_table; phdr < phdr_end; phdr++) {
Kito Chengfa8c05d2013-03-12 14:58:06 +08003576 if (phdr->p_type == PT_LOAD) {
Elliott Hughes0266ae52014-02-10 17:46:57 -08003577 return reinterpret_cast<ElfW(Addr)>(elf) + phdr->p_offset - phdr->p_vaddr;
David 'Digit' Turnerbea23e52012-06-18 23:38:46 +02003578 }
Kito Chengfa8c05d2013-03-12 14:58:06 +08003579 }
3580 return 0;
David 'Digit' Turnerbea23e52012-06-18 23:38:46 +02003581}
3582
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07003583static void __linker_cannot_link(const char* argv0) {
3584 __libc_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", argv0, linker_get_error_buffer());
Mingwei Shibe910522015-11-12 07:02:14 +00003585}
Dmitriy Ivanovefe13832014-07-28 15:05:51 -07003586
Nick Kralevich468319c2011-11-11 15:53:17 -08003587/*
3588 * This is the entry point for the linker, called from begin.S. This
3589 * method is responsible for fixing the linker's own relocations, and
3590 * then calling __linker_init_post_relocation().
3591 *
3592 * Because this method is called before the linker has fixed it's own
3593 * relocations, any attempt to reference an extern variable, extern
3594 * function, or other GOT reference will generate a segfault.
3595 */
Elliott Hughes0266ae52014-02-10 17:46:57 -08003596extern "C" ElfW(Addr) __linker_init(void* raw_args) {
Elliott Hughes42b2c6a2013-02-07 10:14:39 -08003597 KernelArgumentBlock args(raw_args);
Nick Kralevich468319c2011-11-11 15:53:17 -08003598
Elliott Hughes0266ae52014-02-10 17:46:57 -08003599 ElfW(Addr) linker_addr = args.getauxval(AT_BASE);
Dmitriy Ivanovefe13832014-07-28 15:05:51 -07003600 ElfW(Addr) entry_point = args.getauxval(AT_ENTRY);
Elliott Hughes0266ae52014-02-10 17:46:57 -08003601 ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_addr);
Elliott Hughesfaf05ba2014-02-11 16:59:37 -08003602 ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(linker_addr + elf_hdr->e_phoff);
Nick Kralevich468319c2011-11-11 15:53:17 -08003603
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003604 soinfo linker_so(nullptr, nullptr, nullptr, 0, 0);
Nick Kralevich468319c2011-11-11 15:53:17 -08003605
Dmitriy Ivanovefe13832014-07-28 15:05:51 -07003606 // If the linker is not acting as PT_INTERP entry_point is equal to
3607 // _start. Which means that the linker is running as an executable and
3608 // already linked by PT_INTERP.
3609 //
3610 // This happens when user tries to run 'adb shell /system/bin/linker'
3611 // see also https://code.google.com/p/android/issues/detail?id=63174
3612 if (reinterpret_cast<ElfW(Addr)>(&_start) == entry_point) {
Dimitry Ivanov9f0a6952016-02-18 14:37:44 -08003613 __libc_format_fd(STDOUT_FILENO,
3614 "This is %s, the helper program for shared library executables.\n",
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07003615 args.argv[0]);
Dimitry Ivanov9f0a6952016-02-18 14:37:44 -08003616 exit(0);
Dmitriy Ivanovefe13832014-07-28 15:05:51 -07003617 }
3618
Elliott Hughes42b2c6a2013-02-07 10:14:39 -08003619 linker_so.base = linker_addr;
3620 linker_so.size = phdr_table_get_load_size(phdr, elf_hdr->e_phnum);
3621 linker_so.load_bias = get_elf_exec_load_bias(elf_hdr);
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07003622 linker_so.dynamic = nullptr;
Elliott Hughes42b2c6a2013-02-07 10:14:39 -08003623 linker_so.phdr = phdr;
3624 linker_so.phnum = elf_hdr->e_phnum;
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08003625 linker_so.set_linker_flag();
Elliott Hughes5419b942012-10-16 15:54:46 -07003626
Mingwei Shibe910522015-11-12 07:02:14 +00003627 // Prelink the linker so we can access linker globals.
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07003628 if (!linker_so.prelink_image()) __linker_cannot_link(args.argv[0]);
Mingwei Shibe910522015-11-12 07:02:14 +00003629
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07003630 // This might not be obvious... The reasons why we pass g_empty_list
3631 // in place of local_group here are (1) we do not really need it, because
3632 // linker is built with DT_SYMBOLIC and therefore relocates its symbols against
3633 // itself without having to look into local_group and (2) allocators
3634 // are not yet initialized, and therefore we cannot use linked_list.push_*
3635 // functions at this point.
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07003636 if (!linker_so.link_image(g_empty_list, g_empty_list, nullptr)) __linker_cannot_link(args.argv[0]);
Elliott Hughesd23736e2012-11-01 15:16:56 -07003637
Mingwei Shibe910522015-11-12 07:02:14 +00003638#if defined(__i386__)
3639 // On x86, we can't make system calls before this point.
3640 // We can't move this up because this needs to assign to a global.
3641 // Note that until we call __libc_init_main_thread below we have
3642 // no TLS, so you shouldn't make a system call that can fail, because
3643 // it will SEGV when it tries to set errno.
3644 __libc_init_sysinfo(args);
3645#endif
3646
3647 // Initialize the main thread (including TLS, so system calls really work).
Elliott Hughesd2948632015-07-21 11:57:09 -07003648 __libc_init_main_thread(args);
Dmitriy Ivanov14241402014-08-26 14:16:52 -07003649
Mingwei Shibe910522015-11-12 07:02:14 +00003650 // We didn't protect the linker's RELRO pages in link_image because we
3651 // couldn't make system calls on x86 at that point, but we can now...
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07003652 if (!linker_so.protect_relro()) __linker_cannot_link(args.argv[0]);
Mingwei Shibe910522015-11-12 07:02:14 +00003653
Josh Gao93c0f5e2015-10-06 11:08:13 -07003654 // Initialize the linker's static libc's globals
3655 __libc_init_globals(args);
3656
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07003657 // store argc/argv/envp to use them for calling constructors
3658 g_argc = args.argc;
3659 g_argv = args.argv;
3660 g_envp = args.envp;
3661
Dmitriy Ivanovefe13832014-07-28 15:05:51 -07003662 // Initialize the linker's own global variables
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003663 linker_so.call_constructors();
Dmitriy Ivanov4151ea72014-07-24 15:33:25 -07003664
Dmitriy Ivanov0d150942014-08-22 12:25:04 -07003665 // Initialize static variables. Note that in order to
3666 // get correct libdl_info we need to call constructors
3667 // before get_libdl_info().
3668 solist = get_libdl_info();
3669 sonext = get_libdl_info();
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07003670 g_default_namespace.add_soinfo(get_libdl_info());
Dmitriy Ivanov0d150942014-08-22 12:25:04 -07003671
Elliott Hughes42b2c6a2013-02-07 10:14:39 -08003672 // We have successfully fixed our own relocations. It's safe to run
3673 // the main part of the linker now.
Elliott Hughes1728b232014-05-14 10:02:03 -07003674 args.abort_message_ptr = &g_abort_message;
Elliott Hughes0266ae52014-02-10 17:46:57 -08003675 ElfW(Addr) start_address = __linker_init_post_relocation(args, linker_addr);
Elliott Hughes42b2c6a2013-02-07 10:14:39 -08003676
Elliott Hughes116b5692016-01-04 17:45:36 -08003677 INFO("[ Jumping to _start (%p)... ]", reinterpret_cast<void*>(start_address));
Elliott Hughes611f9562015-01-23 10:43:58 -08003678
Elliott Hughes42b2c6a2013-02-07 10:14:39 -08003679 // Return the address that the calling assembly stub should jump to.
3680 return start_address;
Nick Kralevich468319c2011-11-11 15:53:17 -08003681}