blob: d5839d3840b3ee84e2067c54e93ac85cadd199ec [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.
Elliott Hugheseb847bc2013-10-09 15:50:50 -070047#include "private/KernelArgumentBlock.h"
48#include "private/ScopedPthreadMutexLocker.h"
Dmitriy Ivanov14669a92014-09-05 16:42:53 -070049#include "private/ScopeGuard.h"
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080050
51#include "linker.h"
Dmitriy Ivanovc9ce70d2015-03-10 15:30:26 -070052#include "linker_block_allocator.h"
Dimitry Ivanov6b788ee2016-02-17 16:08:03 -080053#include "linker_gdb_support.h"
Dimitry Ivanov48ec2882016-08-04 11:50:36 -070054#include "linker_globals.h"
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080055#include "linker_debug.h"
Dimitry Ivanov769b33f2016-07-21 11:33:40 -070056#include "linker_dlwarning.h"
Dimitry Ivanov3f660572016-09-09 10:00:39 -070057#include "linker_main.h"
Dimitry Ivanovb943f302016-08-03 16:00:10 -070058#include "linker_namespaces.h"
Dmitriy Ivanov18870d32015-04-22 13:10:04 -070059#include "linker_sleb128.h"
David 'Digit' Turner23363ed2012-06-18 18:13:49 +020060#include "linker_phdr.h"
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -080061#include "linker_relocs.h"
Dmitriy Ivanovfa26eee2015-02-03 16:06:47 -080062#include "linker_reloc_iterators.h"
Dmitriy Ivanova1feb112015-10-01 18:41:57 -070063#include "linker_utils.h"
tony.ys_liub4474402015-07-29 18:00:22 +080064
Elliott Hughes939a7e02015-12-04 15:27:46 -080065#include "android-base/strings.h"
Dimitry Ivanovb996d602016-07-11 18:11:39 -070066#include "android-base/stringprintf.h"
Simon Baldwinaef71952015-01-16 13:22:54 +000067#include "ziparchive/zip_archive.h"
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080068
Josh Gao93c0f5e2015-10-06 11:08:13 -070069extern void __libc_init_globals(KernelArgumentBlock&);
Elliott Hughes1801db32015-06-08 18:04:00 -070070extern void __libc_init_AT_SECURE(KernelArgumentBlock&);
71
Mingwei Shibe910522015-11-12 07:02:14 +000072extern "C" void _start();
73
Elliott Hughes1801db32015-06-08 18:04:00 -070074// Override macros to use C++ style casts.
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -080075#undef ELF_ST_TYPE
76#define ELF_ST_TYPE(x) (static_cast<uint32_t>(x) & 0xf)
77
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -070078static android_namespace_t* g_anonymous_namespace = &g_default_namespace;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -070079
Dmitriy Ivanov600bc3c2015-03-10 15:43:50 -070080static LinkerTypeAllocator<soinfo> g_soinfo_allocator;
81static LinkerTypeAllocator<LinkedListEntry<soinfo>> g_soinfo_links_allocator;
Magnus Malmbornba98d922012-09-12 13:00:55 +020082
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -070083static LinkerTypeAllocator<android_namespace_t> g_namespace_allocator;
Dimitry Ivanovaca299a2016-04-11 12:42:58 -070084static LinkerTypeAllocator<LinkedListEntry<android_namespace_t>> g_namespace_list_allocator;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -070085
Elliott Hughes4eeb1f12013-10-25 17:38:02 -070086#if defined(__LP64__)
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -070087static const char* const kSystemLibDir = "/system/lib64";
88static const char* const kVendorLibDir = "/vendor/lib64";
89static const char* const kAsanSystemLibDir = "/data/lib64";
90static const char* const kAsanVendorLibDir = "/data/vendor/lib64";
Elliott Hughes011bc0b2013-10-08 14:27:10 -070091#else
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -070092static const char* const kSystemLibDir = "/system/lib";
93static const char* const kVendorLibDir = "/vendor/lib";
94static const char* const kAsanSystemLibDir = "/data/lib";
95static const char* const kAsanVendorLibDir = "/data/vendor/lib";
Elliott Hughes011bc0b2013-10-08 14:27:10 -070096#endif
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -070097
98static const char* const kDefaultLdPaths[] = {
99 kSystemLibDir,
100 kVendorLibDir,
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700101 nullptr
Elliott Hughes124fae92012-10-31 14:20:03 -0700102};
David Bartleybc3a5c22009-06-02 18:27:28 -0700103
Evgenii Stepanovd640b222015-07-10 17:54:01 -0700104static const char* const kAsanDefaultLdPaths[] = {
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700105 kAsanSystemLibDir,
106 kSystemLibDir,
107 kAsanVendorLibDir,
108 kVendorLibDir,
Evgenii Stepanovd640b222015-07-10 17:54:01 -0700109 nullptr
110};
111
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700112// Is ASAN enabled?
113static bool g_is_asan = false;
114
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700115static bool is_system_library(const std::string& realpath) {
116 for (const auto& dir : g_default_namespace.get_default_library_paths()) {
117 if (file_is_in_dir(realpath, dir)) {
118 return true;
119 }
120 }
121 return false;
122}
123
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700124// Checks if the file exists and not a directory.
125static bool file_exists(const char* path) {
Dimitry Ivanov4cf70242016-08-11 11:11:52 -0700126 struct stat s;
127
128 if (stat(path, &s) != 0) {
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700129 return false;
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700130 }
Dimitry Ivanov4cf70242016-08-11 11:11:52 -0700131
132 return S_ISREG(s.st_mode);
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700133}
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700134
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700135// TODO(dimitry): The grey-list is a workaround for http://b/26394120 ---
136// gradually remove libraries from this list until it is gone.
137static bool is_greylisted(const char* name, const soinfo* needed_by) {
138 static const char* const kLibraryGreyList[] = {
139 "libandroid_runtime.so",
140 "libbinder.so",
141 "libcrypto.so",
142 "libcutils.so",
143 "libexpat.so",
144 "libgui.so",
145 "libmedia.so",
146 "libnativehelper.so",
147 "libskia.so",
148 "libssl.so",
149 "libstagefright.so",
150 "libsqlite.so",
151 "libui.so",
152 "libutils.so",
153 "libvorbisidec.so",
154 nullptr
155 };
156
Elliott Hughes5bc78c82016-11-16 11:35:43 -0800157 // If you're targeting N, you don't get the greylist.
158 if (get_application_target_sdk_version() >= __ANDROID_API_N__) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700159 return false;
160 }
161
162 // if the library needed by a system library - implicitly assume it
163 // is greylisted
164
165 if (needed_by != nullptr && is_system_library(needed_by->get_realpath())) {
166 return true;
167 }
168
169 // if this is an absolute path - make sure it points to /system/lib(64)
170 if (name[0] == '/' && dirname(name) == kSystemLibDir) {
171 // and reduce the path to basename
172 name = basename(name);
173 }
174
175 for (size_t i = 0; kLibraryGreyList[i] != nullptr; ++i) {
176 if (strcmp(name, kLibraryGreyList[i]) == 0) {
177 return true;
178 }
179 }
180
181 return false;
182}
183// END OF WORKAROUND
184
Evgenii Stepanovd640b222015-07-10 17:54:01 -0700185static const char* const* g_default_ld_paths;
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700186static std::vector<std::string> g_ld_preload_names;
Elliott Hughesa4aafd12014-01-13 16:37:47 -0800187
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700188static bool g_public_namespace_initialized;
Dimitry Ivanovb943f302016-08-03 16:00:10 -0700189static soinfo_list_t g_public_namespace;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700190
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800191#if STATS
Elliott Hughesbedfe382012-08-14 14:07:59 -0700192struct linker_stats_t {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700193 int count[kRelocMax];
Elliott Hughesbedfe382012-08-14 14:07:59 -0700194};
195
196static linker_stats_t linker_stats;
197
Dmitriy Ivanov114ff692015-01-14 11:36:38 -0800198void count_relocation(RelocationKind kind) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700199 ++linker_stats.count[kind];
Elliott Hughesbedfe382012-08-14 14:07:59 -0700200}
201#else
Dmitriy Ivanov114ff692015-01-14 11:36:38 -0800202void count_relocation(RelocationKind) {
Elliott Hughesbedfe382012-08-14 14:07:59 -0700203}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800204#endif
205
206#if COUNT_PAGES
Dmitriy Ivanov114ff692015-01-14 11:36:38 -0800207uint32_t bitmask[4096];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800208#endif
209
Elliott Hughesbedfe382012-08-14 14:07:59 -0700210static void notify_gdb_of_load(soinfo* info) {
Dimitry Ivanove97d8ed2016-03-01 15:55:56 -0800211 if (info->is_linker() || info->is_main_executable()) {
212 // gdb already knows about the linker and the main executable.
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700213 return;
214 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800215
Dimitry Ivanov6b788ee2016-02-17 16:08:03 -0800216 link_map* map = &(info->link_map_head);
Nicolas Geoffray0fa54102016-02-18 09:31:24 +0000217
Dimitry Ivanov6b788ee2016-02-17 16:08:03 -0800218 map->l_addr = info->load_bias;
219 // link_map l_name field is not const.
220 map->l_name = const_cast<char*>(info->get_realpath());
221 map->l_ld = info->dynamic;
Nicolas Geoffray0fa54102016-02-18 09:31:24 +0000222
Dimitry Ivanove97d8ed2016-03-01 15:55:56 -0800223 CHECK(map->l_name != nullptr);
224 CHECK(map->l_name[0] != '\0');
225
Dimitry Ivanov6b788ee2016-02-17 16:08:03 -0800226 notify_gdb_of_load(map);
Iliyan Malchev5e12d7e2009-03-24 19:02:00 -0700227}
228
Elliott Hughesbedfe382012-08-14 14:07:59 -0700229static void notify_gdb_of_unload(soinfo* info) {
Dimitry Ivanov6b788ee2016-02-17 16:08:03 -0800230 notify_gdb_of_unload(&(info->link_map_head));
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800231}
232
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -0700233LinkedListEntry<soinfo>* SoinfoListAllocator::alloc() {
234 return g_soinfo_links_allocator.alloc();
235}
236
237void SoinfoListAllocator::free(LinkedListEntry<soinfo>* entry) {
238 g_soinfo_links_allocator.free(entry);
239}
240
Dimitry Ivanovaca299a2016-04-11 12:42:58 -0700241LinkedListEntry<android_namespace_t>* NamespaceListAllocator::alloc() {
242 return g_namespace_list_allocator.alloc();
243}
244
245void NamespaceListAllocator::free(LinkedListEntry<android_namespace_t>* entry) {
246 g_namespace_list_allocator.free(entry);
247}
248
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700249soinfo* soinfo_alloc(android_namespace_t* ns, const char* name,
250 struct stat* file_stat, off64_t file_offset,
251 uint32_t rtld_flags) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700252 if (strlen(name) >= PATH_MAX) {
Magnus Malmbornba98d922012-09-12 13:00:55 +0200253 DL_ERR("library name \"%s\" too long", name);
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700254 return nullptr;
Magnus Malmbornba98d922012-09-12 13:00:55 +0200255 }
256
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700257 TRACE("name %s: allocating soinfo for ns=%p", name, ns);
258
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700259 soinfo* si = new (g_soinfo_allocator.alloc()) soinfo(ns, name, file_stat,
260 file_offset, rtld_flags);
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -0700261
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700262 solist_add_soinfo(si);
Magnus Malmbornba98d922012-09-12 13:00:55 +0200263
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -0700264 si->generate_handle();
265 ns->add_soinfo(si);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700266
Elliott Hughesca0c11b2013-03-12 10:40:45 -0700267 TRACE("name %s: allocated soinfo @ %p", name, si);
Magnus Malmbornba98d922012-09-12 13:00:55 +0200268 return si;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800269}
270
Elliott Hughesfaf05ba2014-02-11 16:59:37 -0800271static void soinfo_free(soinfo* si) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700272 if (si == nullptr) {
273 return;
274 }
275
276 if (si->base != 0 && si->size != 0) {
Dimitry Ivanovf45b0e92016-01-15 11:13:35 -0800277 if (!si->is_mapped_by_caller()) {
278 munmap(reinterpret_cast<void*>(si->base), si->size);
279 } else {
280 // remap the region as PROT_NONE, MAP_ANONYMOUS | MAP_NORESERVE
281 mmap(reinterpret_cast<void*>(si->base), si->size, PROT_NONE,
282 MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
283 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700284 }
285
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700286 TRACE("name %s: freeing soinfo @ %p", si->get_realpath(), si);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700287
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700288 if (!solist_remove_soinfo(si)) {
289 // TODO (dimitry): revisit this - for now preserving the logic
290 // but it does not look right, abort if soinfo is not in the list instead?
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700291 return;
292 }
Elliott Hughes46882792012-08-03 16:49:39 -0700293
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700294 // clear links to/from si
295 si->remove_all_links();
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -0700296
Dmitriy Ivanov609f11b2015-07-08 15:26:46 -0700297 si->~soinfo();
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700298 g_soinfo_allocator.free(si);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800299}
300
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700301static void parse_path(const char* path, const char* delimiters,
302 std::vector<std::string>* resolved_paths) {
303 std::vector<std::string> paths;
304 split_path(path, delimiters, &paths);
305 resolve_paths(paths, resolved_paths);
306}
307
Elliott Hughescade4c32012-12-20 14:42:14 -0800308static void parse_LD_LIBRARY_PATH(const char* path) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700309 std::vector<std::string> ld_libary_paths;
310 parse_path(path, ":", &ld_libary_paths);
311 g_default_namespace.set_ld_library_paths(std::move(ld_libary_paths));
Elliott Hughescade4c32012-12-20 14:42:14 -0800312}
313
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700314static bool realpath_fd(int fd, std::string* realpath) {
315 std::vector<char> buf(PATH_MAX), proc_self_fd(PATH_MAX);
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700316 __libc_format_buffer(&proc_self_fd[0], proc_self_fd.size(), "/proc/self/fd/%d", fd);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700317 if (readlink(&proc_self_fd[0], &buf[0], buf.size()) == -1) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700318 PRINT("readlink(\"%s\") failed: %s [fd=%d]", &proc_self_fd[0], strerror(errno), fd);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700319 return false;
320 }
321
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700322 *realpath = &buf[0];
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700323 return true;
324}
325
Elliott Hughes4eeb1f12013-10-25 17:38:02 -0700326#if defined(__arm__)
Elliott Hughes46882792012-08-03 16:49:39 -0700327
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700328// For a given PC, find the .so that it belongs to.
329// Returns the base address of the .ARM.exidx section
330// for that .so, and the number of 8-byte entries
331// in that section (via *pcount).
332//
333// Intended to be called by libc's __gnu_Unwind_Find_exidx().
334//
335// This function is exposed via dlfcn.cpp and libdl.so.
Elliott Hughesfaf05ba2014-02-11 16:59:37 -0800336_Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr pc, int* pcount) {
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -0800337 uintptr_t addr = reinterpret_cast<uintptr_t>(pc);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800338
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700339 for (soinfo* si = solist_get_head(); si != 0; si = si->next) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700340 if ((addr >= si->base) && (addr < (si->base + si->size))) {
341 *pcount = si->ARM_exidx_count;
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -0800342 return reinterpret_cast<_Unwind_Ptr>(si->ARM_exidx);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800343 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700344 }
345 *pcount = 0;
346 return nullptr;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800347}
Elliott Hughes46882792012-08-03 16:49:39 -0700348
Christopher Ferris24053a42013-08-19 17:45:09 -0700349#endif
Elliott Hughes46882792012-08-03 16:49:39 -0700350
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700351// Here, we only have to provide a callback to iterate across all the
352// loaded libraries. gcc_eh does the rest.
Dmitriy Ivanov7271caf2015-06-29 14:48:25 -0700353int do_dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void* data) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700354 int rv = 0;
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700355 for (soinfo* si = solist_get_head(); si != nullptr; si = si->next) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700356 dl_phdr_info dl_info;
357 dl_info.dlpi_addr = si->link_map_head.l_addr;
358 dl_info.dlpi_name = si->link_map_head.l_name;
359 dl_info.dlpi_phdr = si->phdr;
360 dl_info.dlpi_phnum = si->phnum;
361 rv = cb(&dl_info, sizeof(dl_phdr_info), data);
362 if (rv != 0) {
363 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800364 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700365 }
366 return rv;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800367}
Elliott Hughes46882792012-08-03 16:49:39 -0700368
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800369
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700370bool soinfo_do_lookup(soinfo* si_from, const char* name, const version_info* vi,
Dimitry Ivanovb943f302016-08-03 16:00:10 -0700371 soinfo** si_found_in, const soinfo_list_t& global_group,
372 const soinfo_list_t& local_group, const ElfW(Sym)** symbol) {
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800373 SymbolName symbol_name(name);
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700374 const ElfW(Sym)* s = nullptr;
Iliyan Malchev6ed80c82009-09-28 19:38:04 -0700375
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -0700376 /* "This element's presence in a shared object library alters the dynamic linker's
377 * symbol resolution algorithm for references within the library. Instead of starting
378 * a symbol search with the executable file, the dynamic linker starts from the shared
379 * object itself. If the shared object fails to supply the referenced symbol, the
380 * dynamic linker then searches the executable file and other shared objects as usual."
381 *
382 * http://www.sco.com/developers/gabi/2012-12-31/ch5.dynamic.html
383 *
384 * Note that this is unlikely since static linker avoids generating
385 * relocations for -Bsymbolic linked dynamic executables.
386 */
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700387 if (si_from->has_DT_SYMBOLIC) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700388 DEBUG("%s: looking up %s in local scope (DT_SYMBOLIC)", si_from->get_realpath(), name);
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700389 if (!si_from->find_symbol_by_name(symbol_name, vi, &s)) {
390 return false;
391 }
392
Dmitriy Ivanov8f61d992014-09-16 14:31:06 -0700393 if (s != nullptr) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700394 *si_found_in = si_from;
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -0700395 }
396 }
397
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700398 // 1. Look for it in global_group
399 if (s == nullptr) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700400 bool error = false;
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700401 global_group.visit([&](soinfo* global_si) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700402 DEBUG("%s: looking up %s in %s (from global group)",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700403 si_from->get_realpath(), name, global_si->get_realpath());
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700404 if (!global_si->find_symbol_by_name(symbol_name, vi, &s)) {
405 error = true;
406 return false;
407 }
408
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -0700409 if (s != nullptr) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700410 *si_found_in = global_si;
411 return false;
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -0700412 }
Dmitriy Ivanovc2048942014-08-29 10:15:25 -0700413
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700414 return true;
415 });
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700416
417 if (error) {
418 return false;
419 }
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -0700420 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700421
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700422 // 2. Look for it in the local group
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700423 if (s == nullptr) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700424 bool error = false;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700425 local_group.visit([&](soinfo* local_si) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700426 if (local_si == si_from && si_from->has_DT_SYMBOLIC) {
Dmitriy Ivanove47b3f82014-10-23 14:19:07 -0700427 // we already did this - skip
428 return true;
429 }
430
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700431 DEBUG("%s: looking up %s in %s (from local group)",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700432 si_from->get_realpath(), name, local_si->get_realpath());
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700433 if (!local_si->find_symbol_by_name(symbol_name, vi, &s)) {
434 error = true;
435 return false;
436 }
437
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700438 if (s != nullptr) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700439 *si_found_in = local_si;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700440 return false;
441 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700442
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700443 return true;
444 });
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700445
446 if (error) {
447 return false;
448 }
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700449 }
450
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700451 if (s != nullptr) {
452 TRACE_TYPE(LOOKUP, "si %s sym %s s->st_value = %p, "
453 "found in %s, base = %p, load bias = %p",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700454 si_from->get_realpath(), name, reinterpret_cast<void*>(s->st_value),
455 (*si_found_in)->get_realpath(), reinterpret_cast<void*>((*si_found_in)->base),
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700456 reinterpret_cast<void*>((*si_found_in)->load_bias));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700457 }
Iliyan Malchev6ed80c82009-09-28 19:38:04 -0700458
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700459 *symbol = s;
460 return true;
Iliyan Malchev6ed80c82009-09-28 19:38:04 -0700461}
462
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700463ProtectedDataGuard::ProtectedDataGuard() {
464 if (ref_count_++ == 0) {
465 protect_data(PROT_READ | PROT_WRITE);
466 }
467}
468
469ProtectedDataGuard::~ProtectedDataGuard() {
470 if (ref_count_ == 0) { // overflow
471 __libc_fatal("Too many nested calls to dlopen()");
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -0800472 }
473
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700474 if (--ref_count_ == 0) {
475 protect_data(PROT_READ);
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -0800476 }
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700477}
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -0800478
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700479void ProtectedDataGuard::protect_data(int protection) {
480 g_soinfo_allocator.protect_all(protection);
481 g_soinfo_links_allocator.protect_all(protection);
482 g_namespace_allocator.protect_all(protection);
483 g_namespace_list_allocator.protect_all(protection);
484}
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -0800485
486size_t ProtectedDataGuard::ref_count_ = 0;
487
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700488// Each size has it's own allocator.
489template<size_t size>
490class SizeBasedAllocator {
491 public:
492 static void* alloc() {
493 return allocator_.alloc();
494 }
Dmitriy Ivanov4bea4982014-08-29 14:01:48 -0700495
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700496 static void free(void* ptr) {
497 allocator_.free(ptr);
498 }
Dmitriy Ivanov4bea4982014-08-29 14:01:48 -0700499
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700500 private:
501 static LinkerBlockAllocator allocator_;
502};
503
504template<size_t size>
505LinkerBlockAllocator SizeBasedAllocator<size>::allocator_(size);
506
507template<typename T>
508class TypeBasedAllocator {
509 public:
510 static T* alloc() {
511 return reinterpret_cast<T*>(SizeBasedAllocator<sizeof(T)>::alloc());
512 }
513
514 static void free(T* ptr) {
515 SizeBasedAllocator<sizeof(T)>::free(ptr);
516 }
517};
518
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700519class LoadTask {
520 public:
521 struct deleter_t {
522 void operator()(LoadTask* t) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700523 t->~LoadTask();
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700524 TypeBasedAllocator<LoadTask>::free(t);
525 }
526 };
527
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700528 static deleter_t deleter;
529
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700530 static LoadTask* create(const char* name, soinfo* needed_by,
531 std::unordered_map<const soinfo*, ElfReader>* readers_map) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700532 LoadTask* ptr = TypeBasedAllocator<LoadTask>::alloc();
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700533 return new (ptr) LoadTask(name, needed_by, readers_map);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700534 }
535
536 const char* get_name() const {
537 return name_;
538 }
539
540 soinfo* get_needed_by() const {
541 return needed_by_;
542 }
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700543
544 soinfo* get_soinfo() const {
545 return si_;
546 }
547
548 void set_soinfo(soinfo* si) {
549 si_ = si;
550 }
551
552 off64_t get_file_offset() const {
553 return file_offset_;
554 }
555
556 void set_file_offset(off64_t offset) {
557 file_offset_ = offset;
558 }
559
560 int get_fd() const {
561 return fd_;
562 }
563
564 void set_fd(int fd, bool assume_ownership) {
565 fd_ = fd;
566 close_fd_ = assume_ownership;
567 }
568
569 const android_dlextinfo* get_extinfo() const {
570 return extinfo_;
571 }
572
573 void set_extinfo(const android_dlextinfo* extinfo) {
574 extinfo_ = extinfo;
575 }
576
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700577 bool is_dt_needed() const {
578 return is_dt_needed_;
579 }
580
581 void set_dt_needed(bool is_dt_needed) {
582 is_dt_needed_ = is_dt_needed;
583 }
584
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700585 const ElfReader& get_elf_reader() const {
586 CHECK(si_ != nullptr);
587 return (*elf_readers_map_)[si_];
588 }
589
590 ElfReader& get_elf_reader() {
591 CHECK(si_ != nullptr);
592 return (*elf_readers_map_)[si_];
593 }
594
595 std::unordered_map<const soinfo*, ElfReader>* get_readers_map() {
596 return elf_readers_map_;
597 }
598
599 bool read(const char* realpath, off64_t file_size) {
600 ElfReader& elf_reader = get_elf_reader();
601 return elf_reader.Read(realpath, fd_, file_offset_, file_size);
602 }
603
604 bool load() {
605 ElfReader& elf_reader = get_elf_reader();
606 if (!elf_reader.Load(extinfo_)) {
607 return false;
608 }
609
610 si_->base = elf_reader.load_start();
611 si_->size = elf_reader.load_size();
Dimitry Ivanovf45b0e92016-01-15 11:13:35 -0800612 si_->set_mapped_by_caller(elf_reader.is_mapped_by_caller());
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700613 si_->load_bias = elf_reader.load_bias();
614 si_->phnum = elf_reader.phdr_count();
615 si_->phdr = elf_reader.loaded_phdr();
616
617 return true;
618 }
619
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700620 private:
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700621 LoadTask(const char* name, soinfo* needed_by,
622 std::unordered_map<const soinfo*, ElfReader>* readers_map)
623 : name_(name), needed_by_(needed_by), si_(nullptr),
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700624 fd_(-1), close_fd_(false), file_offset_(0), elf_readers_map_(readers_map),
625 is_dt_needed_(false) {}
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700626
627 ~LoadTask() {
628 if (fd_ != -1 && close_fd_) {
629 close(fd_);
630 }
631 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700632
633 const char* name_;
634 soinfo* needed_by_;
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700635 soinfo* si_;
636 const android_dlextinfo* extinfo_;
637 int fd_;
638 bool close_fd_;
639 off64_t file_offset_;
640 std::unordered_map<const soinfo*, ElfReader>* elf_readers_map_;
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700641 // TODO(dimitry): needed by workaround for http://b/26394120 (the grey-list)
642 bool is_dt_needed_;
643 // END OF WORKAROUND
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700644
645 DISALLOW_IMPLICIT_CONSTRUCTORS(LoadTask);
646};
647
Ningsheng Jiane93be992014-09-16 15:22:10 +0800648LoadTask::deleter_t LoadTask::deleter;
649
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700650template <typename T>
651using linked_list_t = LinkedList<T, TypeBasedAllocator<LinkedListEntry<T>>>;
652
653typedef linked_list_t<soinfo> SoinfoLinkedList;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700654typedef linked_list_t<const char> StringLinkedList;
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700655typedef std::vector<LoadTask*> LoadTaskList;
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700656
Dmitriy Ivanovaa0f2bd2014-07-28 17:32:20 -0700657
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700658// This function walks down the tree of soinfo dependencies
659// in breadth-first order and
660// * calls action(soinfo* si) for each node, and
661// * terminates walk if action returns false.
662//
663// walk_dependencies_tree returns false if walk was terminated
664// by the action and true otherwise.
665template<typename F>
666static bool walk_dependencies_tree(soinfo* root_soinfos[], size_t root_soinfos_size, F action) {
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700667 SoinfoLinkedList visit_list;
668 SoinfoLinkedList visited;
669
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700670 for (size_t i = 0; i < root_soinfos_size; ++i) {
671 visit_list.push_back(root_soinfos[i]);
672 }
673
674 soinfo* si;
675 while ((si = visit_list.pop_front()) != nullptr) {
676 if (visited.contains(si)) {
Dmitriy Ivanov042426b2014-08-12 21:02:13 -0700677 continue;
678 }
679
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700680 if (!action(si)) {
681 return false;
Dmitriy Ivanovaa0f2bd2014-07-28 17:32:20 -0700682 }
683
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700684 visited.push_back(si);
685
686 si->get_children().for_each([&](soinfo* child) {
Dmitriy Ivanovaa0f2bd2014-07-28 17:32:20 -0700687 visit_list.push_back(child);
688 });
689 }
690
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700691 return true;
692}
693
694
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700695static const ElfW(Sym)* dlsym_handle_lookup(soinfo* root, soinfo* skip_until,
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800696 soinfo** found, SymbolName& symbol_name,
697 const version_info* vi) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700698 const ElfW(Sym)* result = nullptr;
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700699 bool skip_lookup = skip_until != nullptr;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700700
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700701 walk_dependencies_tree(&root, 1, [&](soinfo* current_soinfo) {
702 if (skip_lookup) {
703 skip_lookup = current_soinfo != skip_until;
704 return true;
705 }
706
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800707 if (!current_soinfo->find_symbol_by_name(symbol_name, vi, &result)) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700708 result = nullptr;
709 return false;
710 }
711
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700712 if (result != nullptr) {
713 *found = current_soinfo;
714 return false;
715 }
716
717 return true;
718 });
719
720 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800721}
722
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800723static const ElfW(Sym)* dlsym_linear_lookup(android_namespace_t* ns,
724 const char* name,
725 const version_info* vi,
726 soinfo** found,
727 soinfo* caller,
728 void* handle);
729
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700730// This is used by dlsym(3). It performs symbol lookup only within the
731// specified soinfo object and its dependencies in breadth first order.
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800732static const ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found,
733 const char* name, const version_info* vi) {
Dmitriy Ivanovf439b5a2015-05-30 13:04:39 -0700734 // According to man dlopen(3) and posix docs in the case when si is handle
735 // of the main executable we need to search not only in the executable and its
736 // dependencies but also in all libraries loaded with RTLD_GLOBAL.
737 //
738 // Since RTLD_GLOBAL is always set for the main executable and all dt_needed shared
739 // libraries and they are loaded in breath-first (correct) order we can just execute
740 // dlsym(RTLD_DEFAULT, ...); instead of doing two stage lookup.
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700741 if (si == solist_get_somain()) {
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800742 return dlsym_linear_lookup(&g_default_namespace, name, vi, found, nullptr, RTLD_DEFAULT);
Dmitriy Ivanovf439b5a2015-05-30 13:04:39 -0700743 }
744
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700745 SymbolName symbol_name(name);
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800746 return dlsym_handle_lookup(si, nullptr, found, symbol_name, vi);
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700747}
748
Brian Carlstromd4ee82d2013-02-28 15:58:45 -0800749/* This is used by dlsym(3) to performs a global symbol lookup. If the
750 start value is null (for RTLD_DEFAULT), the search starts at the
751 beginning of the global solist. Otherwise the search starts at the
752 specified soinfo (for RTLD_NEXT).
Iliyan Malchev6ed80c82009-09-28 19:38:04 -0700753 */
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800754static const ElfW(Sym)* dlsym_linear_lookup(android_namespace_t* ns,
755 const char* name,
756 const version_info* vi,
757 soinfo** found,
758 soinfo* caller,
759 void* handle) {
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800760 SymbolName symbol_name(name);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800761
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -0700762 auto& soinfo_list = ns->soinfo_list();
763 auto start = soinfo_list.begin();
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -0700764
765 if (handle == RTLD_NEXT) {
Dmitriy Ivanovb96ac412015-05-22 12:34:42 -0700766 if (caller == nullptr) {
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -0700767 return nullptr;
768 } else {
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -0700769 auto it = soinfo_list.find(caller);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700770 CHECK (it != soinfo_list.end());
771 start = ++it;
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -0700772 }
Elliott Hughescade4c32012-12-20 14:42:14 -0800773 }
774
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700775 const ElfW(Sym)* s = nullptr;
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -0700776 for (auto it = start, end = soinfo_list.end(); it != end; ++it) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700777 soinfo* si = *it;
Dmitriy Ivanov19133522015-06-02 17:36:54 -0700778 // Do not skip RTLD_LOCAL libraries in dlsym(RTLD_DEFAULT, ...)
Elliott Hughes5bc78c82016-11-16 11:35:43 -0800779 // if the library is opened by application with target api level < M.
Dmitriy Ivanov19133522015-06-02 17:36:54 -0700780 // See http://b/21565766
Elliott Hughes5bc78c82016-11-16 11:35:43 -0800781 if ((si->get_rtld_flags() & RTLD_GLOBAL) == 0 &&
782 si->get_target_sdk_version() >= __ANDROID_API_M__) {
Dmitriy Ivanove8ba50f2014-09-15 17:00:10 -0700783 continue;
784 }
785
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800786 if (!si->find_symbol_by_name(symbol_name, vi, &s)) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700787 return nullptr;
788 }
789
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700790 if (s != nullptr) {
Elliott Hughescade4c32012-12-20 14:42:14 -0800791 *found = si;
792 break;
Matt Fischer1698d9e2009-12-31 12:17:56 -0600793 }
Elliott Hughescade4c32012-12-20 14:42:14 -0800794 }
Matt Fischer1698d9e2009-12-31 12:17:56 -0600795
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700796 // If not found - use dlsym_handle_lookup for caller's
797 // local_group unless it is part of the global group in which
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -0700798 // case we already did it.
799 if (s == nullptr && caller != nullptr &&
800 (caller->get_rtld_flags() & RTLD_GLOBAL) == 0) {
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700801 return dlsym_handle_lookup(caller->get_local_group_root(),
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800802 (handle == RTLD_NEXT) ? caller : nullptr, found, symbol_name, vi);
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -0700803 }
804
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700805 if (s != nullptr) {
Elliott Hughesc00f2cb2013-10-04 17:01:33 -0700806 TRACE_TYPE(LOOKUP, "%s s->st_value = %p, found->base = %p",
807 name, reinterpret_cast<void*>(s->st_value), reinterpret_cast<void*>((*found)->base));
Elliott Hughescade4c32012-12-20 14:42:14 -0800808 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800809
Elliott Hughescade4c32012-12-20 14:42:14 -0800810 return s;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800811}
812
Kito Chengfa8c05d2013-03-12 14:58:06 +0800813soinfo* find_containing_library(const void* p) {
Elliott Hughes0266ae52014-02-10 17:46:57 -0800814 ElfW(Addr) address = reinterpret_cast<ElfW(Addr)>(p);
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700815 for (soinfo* si = solist_get_head(); si != nullptr; si = si->next) {
Kito Chengfa8c05d2013-03-12 14:58:06 +0800816 if (address >= si->base && address - si->base < si->size) {
817 return si;
Matt Fischere2a8b1f2009-12-31 12:17:40 -0600818 }
Kito Chengfa8c05d2013-03-12 14:58:06 +0800819 }
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700820 return nullptr;
Matt Fischere2a8b1f2009-12-31 12:17:40 -0600821}
822
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700823class ZipArchiveCache {
824 public:
825 ZipArchiveCache() {}
826 ~ZipArchiveCache();
827
828 bool get_or_open(const char* zip_path, ZipArchiveHandle* handle);
829 private:
830 DISALLOW_COPY_AND_ASSIGN(ZipArchiveCache);
831
832 std::unordered_map<std::string, ZipArchiveHandle> cache_;
833};
834
835bool ZipArchiveCache::get_or_open(const char* zip_path, ZipArchiveHandle* handle) {
836 std::string key(zip_path);
837
838 auto it = cache_.find(key);
839 if (it != cache_.end()) {
840 *handle = it->second;
841 return true;
842 }
843
844 int fd = TEMP_FAILURE_RETRY(open(zip_path, O_RDONLY | O_CLOEXEC));
845 if (fd == -1) {
846 return false;
847 }
848
849 if (OpenArchiveFd(fd, "", handle) != 0) {
850 // invalid zip-file (?)
Yabin Cui722072d2016-03-21 17:10:12 -0700851 CloseArchive(handle);
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700852 close(fd);
853 return false;
854 }
855
856 cache_[key] = *handle;
857 return true;
858}
859
860ZipArchiveCache::~ZipArchiveCache() {
Dmitriy Ivanov5dce8942015-10-13 12:14:16 -0700861 for (const auto& it : cache_) {
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700862 CloseArchive(it.second);
863 }
864}
865
866static int open_library_in_zipfile(ZipArchiveCache* zip_archive_cache,
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700867 const char* const input_path,
868 off64_t* file_offset, std::string* realpath) {
869 std::string normalized_path;
870 if (!normalize_path(input_path, &normalized_path)) {
871 return -1;
872 }
873
874 const char* const path = normalized_path.c_str();
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700875 TRACE("Trying zip file open from path \"%s\" -> normalized \"%s\"", input_path, path);
Simon Baldwinaef71952015-01-16 13:22:54 +0000876
Dmitriy Ivanov402a7502015-06-09 13:46:51 -0700877 // Treat an '!/' separator inside a path as the separator between the name
Simon Baldwinaef71952015-01-16 13:22:54 +0000878 // of the zip file on disk and the subdirectory to search within it.
Dmitriy Ivanov402a7502015-06-09 13:46:51 -0700879 // For example, if path is "foo.zip!/bar/bas/x.so", then we search for
Simon Baldwinaef71952015-01-16 13:22:54 +0000880 // "bar/bas/x.so" within "foo.zip".
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700881 const char* const separator = strstr(path, kZipFileSeparator);
Simon Baldwinaef71952015-01-16 13:22:54 +0000882 if (separator == nullptr) {
883 return -1;
Elliott Hughes124fae92012-10-31 14:20:03 -0700884 }
Simon Baldwinaef71952015-01-16 13:22:54 +0000885
886 char buf[512];
887 if (strlcpy(buf, path, sizeof(buf)) >= sizeof(buf)) {
888 PRINT("Warning: ignoring very long library path: %s", path);
889 return -1;
890 }
891
892 buf[separator - path] = '\0';
893
894 const char* zip_path = buf;
Dmitriy Ivanov402a7502015-06-09 13:46:51 -0700895 const char* file_path = &buf[separator - path + 2];
Simon Baldwinaef71952015-01-16 13:22:54 +0000896 int fd = TEMP_FAILURE_RETRY(open(zip_path, O_RDONLY | O_CLOEXEC));
897 if (fd == -1) {
898 return -1;
899 }
900
901 ZipArchiveHandle handle;
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700902 if (!zip_archive_cache->get_or_open(zip_path, &handle)) {
Simon Baldwinaef71952015-01-16 13:22:54 +0000903 // invalid zip-file (?)
904 close(fd);
905 return -1;
906 }
907
Simon Baldwinaef71952015-01-16 13:22:54 +0000908 ZipEntry entry;
909
Yusuke Sato56f40fb2015-06-25 14:56:07 -0700910 if (FindEntry(handle, ZipString(file_path), &entry) != 0) {
Simon Baldwinaef71952015-01-16 13:22:54 +0000911 // Entry was not found.
912 close(fd);
913 return -1;
914 }
915
916 // Check if it is properly stored
917 if (entry.method != kCompressStored || (entry.offset % PAGE_SIZE) != 0) {
918 close(fd);
919 return -1;
920 }
921
922 *file_offset = entry.offset;
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700923
924 if (realpath_fd(fd, realpath)) {
925 *realpath += separator;
926 } else {
927 PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.",
928 normalized_path.c_str());
929 *realpath = normalized_path;
930 }
931
Simon Baldwinaef71952015-01-16 13:22:54 +0000932 return fd;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800933}
934
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700935static bool format_path(char* buf, size_t buf_size, const char* path, const char* name) {
936 int n = __libc_format_buffer(buf, buf_size, "%s/%s", path, name);
937 if (n < 0 || n >= static_cast<int>(buf_size)) {
938 PRINT("Warning: ignoring very long library path: %s/%s", path, name);
939 return false;
940 }
Simon Baldwinaef71952015-01-16 13:22:54 +0000941
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700942 return true;
943}
944
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700945static int open_library_on_paths(ZipArchiveCache* zip_archive_cache,
946 const char* name, off64_t* file_offset,
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700947 const std::vector<std::string>& paths,
948 std::string* realpath) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700949 for (const auto& path : paths) {
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700950 char buf[512];
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700951 if (!format_path(buf, sizeof(buf), path.c_str(), name)) {
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700952 continue;
953 }
954
955 int fd = -1;
Dmitriy Ivanov730ed9d2015-07-16 04:52:06 -0700956 if (strstr(buf, kZipFileSeparator) != nullptr) {
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700957 fd = open_library_in_zipfile(zip_archive_cache, buf, file_offset, realpath);
Simon Baldwinaef71952015-01-16 13:22:54 +0000958 }
959
960 if (fd == -1) {
961 fd = TEMP_FAILURE_RETRY(open(buf, O_RDONLY | O_CLOEXEC));
962 if (fd != -1) {
963 *file_offset = 0;
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700964 if (!realpath_fd(fd, realpath)) {
965 PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.", buf);
966 *realpath = buf;
967 }
Simon Baldwinaef71952015-01-16 13:22:54 +0000968 }
969 }
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700970
971 if (fd != -1) {
972 return fd;
973 }
Simon Baldwinaef71952015-01-16 13:22:54 +0000974 }
975
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700976 return -1;
Simon Baldwinaef71952015-01-16 13:22:54 +0000977}
978
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700979static int open_library(android_namespace_t* ns,
980 ZipArchiveCache* zip_archive_cache,
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700981 const char* name, soinfo *needed_by,
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700982 off64_t* file_offset, std::string* realpath) {
Elliott Hughesca0c11b2013-03-12 10:40:45 -0700983 TRACE("[ opening %s ]", name);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800984
Elliott Hughes124fae92012-10-31 14:20:03 -0700985 // 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 -0700986 if (strchr(name, '/') != nullptr) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700987 int fd = -1;
988
Dmitriy Ivanov730ed9d2015-07-16 04:52:06 -0700989 if (strstr(name, kZipFileSeparator) != nullptr) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700990 fd = open_library_in_zipfile(zip_archive_cache, name, file_offset, realpath);
991 }
992
993 if (fd == -1) {
994 fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_CLOEXEC));
Simon Baldwinaef71952015-01-16 13:22:54 +0000995 if (fd != -1) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700996 *file_offset = 0;
997 if (!realpath_fd(fd, realpath)) {
998 PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.", name);
999 *realpath = name;
1000 }
Simon Baldwinaef71952015-01-16 13:22:54 +00001001 }
1002 }
1003
Dmitriy Ivanove44fffd2015-03-17 17:12:18 -07001004 return fd;
Elliott Hughes124fae92012-10-31 14:20:03 -07001005 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001006
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001007 // Otherwise we try LD_LIBRARY_PATH first, and fall back to the default library path
1008 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 -07001009 if (fd == -1 && needed_by != nullptr) {
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001010 fd = open_library_on_paths(zip_archive_cache, name, file_offset, needed_by->get_dt_runpath(), realpath);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001011 // Check if the library is accessible
1012 if (fd != -1 && !ns->is_accessible(*realpath)) {
1013 fd = -1;
1014 }
Evgenii Stepanov68650822015-06-10 13:38:39 -07001015 }
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001016
Elliott Hughes124fae92012-10-31 14:20:03 -07001017 if (fd == -1) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001018 fd = open_library_on_paths(zip_archive_cache, name, file_offset, ns->get_default_library_paths(), realpath);
Elliott Hughes124fae92012-10-31 14:20:03 -07001019 }
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001020
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001021 // TODO(dimitry): workaround for http://b/26394120 (the grey-list)
1022 if (fd == -1 && ns != &g_default_namespace && is_greylisted(name, needed_by)) {
1023 // try searching for it on default_namespace default_library_path
1024 fd = open_library_on_paths(zip_archive_cache, name, file_offset,
1025 g_default_namespace.get_default_library_paths(), realpath);
1026 }
1027 // END OF WORKAROUND
1028
Elliott Hughes124fae92012-10-31 14:20:03 -07001029 return fd;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001030}
1031
Dimitry Ivanov3f660572016-09-09 10:00:39 -07001032const char* fix_dt_needed(const char* dt_needed, const char* sopath __unused) {
Dmitriy Ivanovd974e882015-05-27 18:29:41 -07001033#if !defined(__LP64__)
1034 // Work around incorrect DT_NEEDED entries for old apps: http://b/21364029
Elliott Hughes5bc78c82016-11-16 11:35:43 -08001035 if (get_application_target_sdk_version() < __ANDROID_API_M__) {
Dmitriy Ivanovd974e882015-05-27 18:29:41 -07001036 const char* bname = basename(dt_needed);
1037 if (bname != dt_needed) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001038 DL_WARN("library \"%s\" has invalid DT_NEEDED entry \"%s\"", sopath, dt_needed);
1039 add_dlwarning(sopath, "invalid DT_NEEDED entry", dt_needed);
Dmitriy Ivanovd974e882015-05-27 18:29:41 -07001040 }
1041
1042 return bname;
1043 }
1044#endif
1045 return dt_needed;
1046}
1047
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001048template<typename F>
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001049static void for_each_dt_needed(const ElfReader& elf_reader, F action) {
1050 for (const ElfW(Dyn)* d = elf_reader.dynamic(); d->d_tag != DT_NULL; ++d) {
1051 if (d->d_tag == DT_NEEDED) {
1052 action(fix_dt_needed(elf_reader.get_string(d->d_un.d_val), elf_reader.name()));
1053 }
1054 }
1055}
1056
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001057static bool load_library(android_namespace_t* ns,
1058 LoadTask* task,
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001059 LoadTaskList* load_tasks,
1060 int rtld_flags,
1061 const std::string& realpath) {
1062 off64_t file_offset = task->get_file_offset();
1063 const char* name = task->get_name();
1064 const android_dlextinfo* extinfo = task->get_extinfo();
1065
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001066 if ((file_offset % PAGE_SIZE) != 0) {
Dmitriy Ivanova6c12792014-10-21 12:09:18 -07001067 DL_ERR("file offset for the library \"%s\" is not page-aligned: %" PRId64, name, file_offset);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001068 return false;
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001069 }
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001070 if (file_offset < 0) {
1071 DL_ERR("file offset for the library \"%s\" is negative: %" PRId64, name, file_offset);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001072 return false;
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001073 }
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001074
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001075 struct stat file_stat;
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001076 if (TEMP_FAILURE_RETRY(fstat(task->get_fd(), &file_stat)) != 0) {
Dmitriy Ivanova6c12792014-10-21 12:09:18 -07001077 DL_ERR("unable to stat file for the library \"%s\": %s", name, strerror(errno));
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001078 return false;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001079 }
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001080 if (file_offset >= file_stat.st_size) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07001081 DL_ERR("file offset for the library \"%s\" >= file size: %" PRId64 " >= %" PRId64,
1082 name, file_offset, file_stat.st_size);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001083 return false;
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001084 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001085
1086 // Check for symlink and other situations where
Dmitriy Ivanov9b821362015-04-02 16:03:56 -07001087 // file can have different names, unless ANDROID_DLEXT_FORCE_LOAD is set
1088 if (extinfo == nullptr || (extinfo->flags & ANDROID_DLEXT_FORCE_LOAD) == 0) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001089 auto predicate = [&](soinfo* si) {
1090 return si->get_st_dev() != 0 &&
1091 si->get_st_ino() != 0 &&
1092 si->get_st_dev() == file_stat.st_dev &&
1093 si->get_st_ino() == file_stat.st_ino &&
1094 si->get_file_offset() == file_offset;
1095 };
1096
1097 soinfo* si = ns->soinfo_list().find_if(predicate);
1098
1099 // check public namespace
1100 if (si == nullptr) {
1101 si = g_public_namespace.find_if(predicate);
1102 if (si != nullptr) {
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001103 ns->add_soinfo(si);
Dmitriy Ivanov9b821362015-04-02 16:03:56 -07001104 }
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07001105 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001106
1107 if (si != nullptr) {
1108 TRACE("library \"%s\" is already loaded under different name/path \"%s\" - "
1109 "will return existing soinfo", name, si->get_realpath());
1110 task->set_soinfo(si);
1111 return true;
1112 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001113 }
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07001114
Dmitriy Ivanove8ba50f2014-09-15 17:00:10 -07001115 if ((rtld_flags & RTLD_NOLOAD) != 0) {
Dmitriy Ivanova6ac54a2014-09-09 10:21:42 -07001116 DL_ERR("library \"%s\" wasn't loaded and RTLD_NOLOAD prevented it", name);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001117 return false;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001118 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001119
Dimitry Ivanov22840aa2015-12-04 18:28:49 -08001120 if (!ns->is_accessible(realpath)) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001121 // TODO(dimitry): workaround for http://b/26394120 - the grey-list
1122 const soinfo* needed_by = task->is_dt_needed() ? task->get_needed_by() : nullptr;
1123 if (is_greylisted(name, needed_by)) {
1124 // print warning only if needed by non-system library
1125 if (needed_by == nullptr || !is_system_library(needed_by->get_realpath())) {
1126 const soinfo* needed_or_dlopened_by = task->get_needed_by();
1127 const char* sopath = needed_or_dlopened_by == nullptr ? "(unknown)" :
1128 needed_or_dlopened_by->get_realpath();
1129 DL_WARN("library \"%s\" (\"%s\") needed or dlopened by \"%s\" is not accessible for the namespace \"%s\""
1130 " - the access is temporarily granted as a workaround for http://b/26394120, note that the access"
1131 " will be removed in future releases of Android.",
1132 name, realpath.c_str(), sopath, ns->get_name());
1133 add_dlwarning(sopath, "unauthorized access to", name);
1134 }
1135 } else {
1136 // do not load libraries if they are not accessible for the specified namespace.
1137 const char* needed_or_dlopened_by = task->get_needed_by() == nullptr ?
1138 "(unknown)" :
1139 task->get_needed_by()->get_realpath();
Dimitry Ivanovd17a3772016-03-01 13:11:28 -08001140
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001141 DL_ERR("library \"%s\" needed or dlopened by \"%s\" is not accessible for the namespace \"%s\"",
1142 name, needed_or_dlopened_by, ns->get_name());
Dimitry Ivanovd17a3772016-03-01 13:11:28 -08001143
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001144 PRINT("library \"%s\" (\"%s\") needed or dlopened by \"%s\" is not accessible for the"
1145 " namespace: [name=\"%s\", ld_library_paths=\"%s\", default_library_paths=\"%s\","
1146 " permitted_paths=\"%s\"]",
1147 name, realpath.c_str(),
1148 needed_or_dlopened_by,
1149 ns->get_name(),
1150 android::base::Join(ns->get_ld_library_paths(), ':').c_str(),
1151 android::base::Join(ns->get_default_library_paths(), ':').c_str(),
1152 android::base::Join(ns->get_permitted_paths(), ':').c_str());
1153 return false;
1154 }
Dimitry Ivanov22840aa2015-12-04 18:28:49 -08001155 }
1156
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001157 soinfo* si = soinfo_alloc(ns, realpath.c_str(), &file_stat, file_offset, rtld_flags);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001158 if (si == nullptr) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001159 return false;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001160 }
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07001161
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001162 task->set_soinfo(si);
1163
1164 // Read the ELF header and some of the segments.
1165 if (!task->read(realpath.c_str(), file_stat.st_size)) {
Dmitriy Ivanovfd7a91e2015-11-06 10:44:37 -08001166 soinfo_free(si);
1167 task->set_soinfo(nullptr);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001168 return false;
1169 }
1170
1171 // find and set DT_RUNPATH and dt_soname
1172 // Note that these field values are temporary and are
1173 // going to be overwritten on soinfo::prelink_image
1174 // with values from PT_LOAD segments.
1175 const ElfReader& elf_reader = task->get_elf_reader();
1176 for (const ElfW(Dyn)* d = elf_reader.dynamic(); d->d_tag != DT_NULL; ++d) {
1177 if (d->d_tag == DT_RUNPATH) {
1178 si->set_dt_runpath(elf_reader.get_string(d->d_un.d_val));
1179 }
1180 if (d->d_tag == DT_SONAME) {
1181 si->set_soname(elf_reader.get_string(d->d_un.d_val));
1182 }
1183 }
1184
1185 for_each_dt_needed(task->get_elf_reader(), [&](const char* name) {
1186 load_tasks->push_back(LoadTask::create(name, si, task->get_readers_map()));
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001187 });
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07001188
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001189 return true;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001190}
1191
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001192static bool load_library(android_namespace_t* ns,
1193 LoadTask* task,
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001194 ZipArchiveCache* zip_archive_cache,
1195 LoadTaskList* load_tasks,
1196 int rtld_flags) {
1197 const char* name = task->get_name();
1198 soinfo* needed_by = task->get_needed_by();
1199 const android_dlextinfo* extinfo = task->get_extinfo();
1200
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001201 off64_t file_offset;
1202 std::string realpath;
Spencer Low0346ad72015-04-22 18:06:51 -07001203 if (extinfo != nullptr && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) {
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001204 file_offset = 0;
Spencer Low0346ad72015-04-22 18:06:51 -07001205 if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
1206 file_offset = extinfo->library_fd_offset;
1207 }
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001208
1209 if (!realpath_fd(extinfo->library_fd, &realpath)) {
1210 PRINT("warning: unable to get realpath for the library \"%s\" by extinfo->library_fd. "
1211 "Will use given name.", name);
1212 realpath = name;
1213 }
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001214
1215 task->set_fd(extinfo->library_fd, false);
1216 task->set_file_offset(file_offset);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001217 return load_library(ns, task, load_tasks, rtld_flags, realpath);
Spencer Low0346ad72015-04-22 18:06:51 -07001218 }
1219
1220 // Open the file.
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001221 int fd = open_library(ns, zip_archive_cache, name, needed_by, &file_offset, &realpath);
Spencer Low0346ad72015-04-22 18:06:51 -07001222 if (fd == -1) {
1223 DL_ERR("library \"%s\" not found", name);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001224 return false;
Spencer Low0346ad72015-04-22 18:06:51 -07001225 }
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001226
1227 task->set_fd(fd, true);
1228 task->set_file_offset(file_offset);
1229
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001230 return load_library(ns, task, load_tasks, rtld_flags, realpath);
Spencer Low0346ad72015-04-22 18:06:51 -07001231}
1232
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001233// Returns true if library was found and false in 2 cases
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001234// 1. (for default namespace only) The library was found but loaded under different
1235// target_sdk_version (*candidate != nullptr)
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001236// 2. The library was not found by soname (*candidate is nullptr)
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001237static bool find_loaded_library_by_soname(android_namespace_t* ns,
1238 const char* name, soinfo** candidate) {
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001239 *candidate = nullptr;
1240
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07001241 // Ignore filename with path.
1242 if (strchr(name, '/') != nullptr) {
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001243 return false;
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07001244 }
1245
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001246 uint32_t target_sdk_version = get_application_target_sdk_version();
1247
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001248 return !ns->soinfo_list().visit([&](soinfo* si) {
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07001249 const char* soname = si->get_soname();
1250 if (soname != nullptr && (strcmp(name, soname) == 0)) {
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001251 // If the library was opened under different target sdk version
1252 // skip this step and try to reopen it. The exceptions are
1253 // "libdl.so" and global group. There is no point in skipping
1254 // them because relocation process is going to use them
1255 // in any case.
Dimitry Ivanov3f660572016-09-09 10:00:39 -07001256
1257 // TODO (dimitry): remove this once linker stops imposing as libdl.so
1258 bool is_libdl = (si == solist_get_head());
1259
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001260 if (is_libdl || (si->get_dt_flags_1() & DF_1_GLOBAL) != 0 ||
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001261 !si->is_linked() || si->get_target_sdk_version() == target_sdk_version ||
1262 ns != &g_default_namespace) {
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001263 *candidate = si;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001264 return false;
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001265 } else if (*candidate == nullptr) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001266 // for the different sdk version in the default namespace
1267 // remember the first library.
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001268 *candidate = si;
1269 }
Ard Biesheuvel12c78bb2012-08-14 12:30:09 +02001270 }
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001271
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001272 return true;
1273 });
Ard Biesheuvel12c78bb2012-08-14 12:30:09 +02001274}
1275
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001276static bool find_library_internal(android_namespace_t* ns,
1277 LoadTask* task,
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001278 ZipArchiveCache* zip_archive_cache,
1279 LoadTaskList* load_tasks,
1280 int rtld_flags) {
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001281 soinfo* candidate;
1282
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001283 if (find_loaded_library_by_soname(ns, task->get_name(), &candidate)) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001284 task->set_soinfo(candidate);
1285 return true;
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001286 }
Dmitriy Ivanovb648a8a2014-05-19 15:06:58 -07001287
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001288 if (ns != &g_default_namespace) {
1289 // check public namespace
1290 candidate = g_public_namespace.find_if([&](soinfo* si) {
1291 return strcmp(task->get_name(), si->get_soname()) == 0;
1292 });
1293
1294 if (candidate != nullptr) {
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001295 ns->add_soinfo(candidate);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001296 task->set_soinfo(candidate);
1297 return true;
1298 }
1299 }
1300
Dmitriy Ivanovb648a8a2014-05-19 15:06:58 -07001301 // Library might still be loaded, the accurate detection
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001302 // of this fact is done by load_library.
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001303 TRACE("[ \"%s\" find_loaded_library_by_soname failed (*candidate=%s@%p). Trying harder...]",
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001304 task->get_name(), candidate == nullptr ? "n/a" : candidate->get_realpath(), candidate);
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001305
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001306 if (load_library(ns, task, zip_archive_cache, load_tasks, rtld_flags)) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001307 return true;
1308 } else {
1309 // In case we were unable to load the library but there
1310 // is a candidate loaded under the same soname but different
1311 // sdk level - return it anyways.
1312 if (candidate != nullptr) {
1313 task->set_soinfo(candidate);
1314 return true;
1315 }
Elliott Hughesd23736e2012-11-01 15:16:56 -07001316 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001317
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001318 return false;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001319}
1320
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001321static void soinfo_unload(soinfo* si);
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001322static void soinfo_unload(soinfo* soinfos[], size_t count);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001323
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001324// TODO: this is slightly unusual way to construct
1325// the global group for relocation. Not every RTLD_GLOBAL
1326// library is included in this group for backwards-compatibility
1327// reasons.
1328//
1329// This group consists of the main executable, LD_PRELOADs
1330// and libraries with the DF_1_GLOBAL flag set.
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001331static soinfo_list_t make_global_group(android_namespace_t* ns) {
1332 soinfo_list_t global_group;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001333 ns->soinfo_list().for_each([&](soinfo* si) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001334 if ((si->get_dt_flags_1() & DF_1_GLOBAL) != 0) {
1335 global_group.push_back(si);
1336 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001337 });
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001338
1339 return global_group;
1340}
1341
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07001342// This function provides a list of libraries to be shared
1343// by the namespace. For the default namespace this is the global
1344// group (see make_global_group). For all others this is a group
1345// of RTLD_GLOBAL libraries (which includes the global group from
1346// the default namespace).
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001347static soinfo_list_t get_shared_group(android_namespace_t* ns) {
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07001348 if (ns == &g_default_namespace) {
1349 return make_global_group(ns);
1350 }
1351
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001352 soinfo_list_t shared_group;
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07001353 ns->soinfo_list().for_each([&](soinfo* si) {
1354 if ((si->get_rtld_flags() & RTLD_GLOBAL) != 0) {
1355 shared_group.push_back(si);
1356 }
1357 });
1358
1359 return shared_group;
1360}
1361
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001362static void shuffle(std::vector<LoadTask*>* v) {
1363 for (size_t i = 0, size = v->size(); i < size; ++i) {
1364 size_t n = size - i;
1365 size_t r = arc4random_uniform(n);
1366 std::swap((*v)[n-1], (*v)[r]);
1367 }
1368}
1369
Evgenii Stepanov0cdef7e2015-07-06 17:56:31 -07001370// add_as_children - add first-level loaded libraries (i.e. library_names[], but
1371// not their transitive dependencies) as children of the start_with library.
1372// This is false when find_libraries is called for dlopen(), when newly loaded
1373// libraries must form a disjoint tree.
Dimitry Ivanov3f660572016-09-09 10:00:39 -07001374bool find_libraries(android_namespace_t* ns,
1375 soinfo* start_with,
1376 const char* const library_names[],
1377 size_t library_names_count,
1378 soinfo* soinfos[],
1379 std::vector<soinfo*>* ld_preloads,
1380 size_t ld_preloads_count,
1381 int rtld_flags,
1382 const android_dlextinfo* extinfo,
1383 bool add_as_children) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001384 // Step 0: prepare.
1385 LoadTaskList load_tasks;
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001386 std::unordered_map<const soinfo*, ElfReader> readers_map;
1387
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001388 for (size_t i = 0; i < library_names_count; ++i) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001389 const char* name = library_names[i];
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001390 load_tasks.push_back(LoadTask::create(name, start_with, &readers_map));
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001391 }
1392
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001393 // Construct global_group.
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001394 soinfo_list_t global_group = make_global_group(ns);
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001395
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001396 // If soinfos array is null allocate one on stack.
1397 // The array is needed in case of failure; for example
1398 // when library_names[] = {libone.so, libtwo.so} and libone.so
1399 // is loaded correctly but libtwo.so failed for some reason.
1400 // In this case libone.so should be unloaded on return.
1401 // See also implementation of failure_guard below.
1402
1403 if (soinfos == nullptr) {
1404 size_t soinfos_size = sizeof(soinfo*)*library_names_count;
1405 soinfos = reinterpret_cast<soinfo**>(alloca(soinfos_size));
1406 memset(soinfos, 0, soinfos_size);
1407 }
1408
1409 // list of libraries to link - see step 2.
1410 size_t soinfos_count = 0;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001411
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001412 auto scope_guard = make_scope_guard([&]() {
1413 for (LoadTask* t : load_tasks) {
1414 LoadTask::deleter(t);
1415 }
1416 });
1417
Dmitriy Ivanovd9ff7222014-09-08 16:22:22 -07001418 auto failure_guard = make_scope_guard([&]() {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001419 // Housekeeping
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001420 soinfo_unload(soinfos, soinfos_count);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001421 });
1422
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001423 ZipArchiveCache zip_archive_cache;
1424
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001425 // Step 1: expand the list of load_tasks to include
1426 // all DT_NEEDED libraries (do not load them just yet)
1427 for (size_t i = 0; i<load_tasks.size(); ++i) {
1428 LoadTask* task = load_tasks[i];
Evgenii Stepanov68650822015-06-10 13:38:39 -07001429 soinfo* needed_by = task->get_needed_by();
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001430
Dmitriy Ivanovedfc9f62015-09-02 16:32:02 -07001431 bool is_dt_needed = needed_by != nullptr && (needed_by != start_with || add_as_children);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001432 task->set_extinfo(is_dt_needed ? nullptr : extinfo);
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001433 task->set_dt_needed(is_dt_needed);
Dmitriy Ivanovedfc9f62015-09-02 16:32:02 -07001434
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001435 if(!find_library_internal(ns, task, &zip_archive_cache, &load_tasks, rtld_flags)) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001436 return false;
1437 }
1438
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001439 soinfo* si = task->get_soinfo();
1440
Dmitriy Ivanovedfc9f62015-09-02 16:32:02 -07001441 if (is_dt_needed) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001442 needed_by->add_child(si);
1443 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001444
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001445 if (si->is_linked()) {
1446 si->increment_ref_count();
1447 }
1448
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001449 // When ld_preloads is not null, the first
1450 // ld_preloads_count libs are in fact ld_preloads.
1451 if (ld_preloads != nullptr && soinfos_count < ld_preloads_count) {
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07001452 ld_preloads->push_back(si);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001453 }
1454
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001455 if (soinfos_count < library_names_count) {
1456 soinfos[soinfos_count++] = si;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001457 }
1458 }
1459
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001460 // Step 2: Load libraries in random order (see b/24047022)
1461 LoadTaskList load_list;
1462 for (auto&& task : load_tasks) {
1463 soinfo* si = task->get_soinfo();
1464 auto pred = [&](const LoadTask* t) {
1465 return t->get_soinfo() == si;
1466 };
1467
1468 if (!si->is_linked() &&
1469 std::find_if(load_list.begin(), load_list.end(), pred) == load_list.end() ) {
1470 load_list.push_back(task);
1471 }
1472 }
1473 shuffle(&load_list);
1474
1475 for (auto&& task : load_list) {
1476 if (!task->load()) {
1477 return false;
1478 }
1479 }
1480
1481 // Step 3: pre-link all DT_NEEDED libraries in breadth first order.
1482 for (auto&& task : load_tasks) {
1483 soinfo* si = task->get_soinfo();
1484 if (!si->is_linked() && !si->prelink_image()) {
1485 return false;
1486 }
1487 }
1488
1489 // Step 4: Add LD_PRELOADed libraries to the global group for
1490 // future runs. There is no need to explicitly add them to
1491 // the global group for this run because they are going to
1492 // appear in the local group in the correct order.
1493 if (ld_preloads != nullptr) {
1494 for (auto&& si : *ld_preloads) {
1495 si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL);
1496 }
1497 }
1498
1499
1500 // Step 5: link libraries.
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001501 soinfo_list_t local_group;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001502 walk_dependencies_tree(
Evgenii Stepanov0cdef7e2015-07-06 17:56:31 -07001503 (start_with != nullptr && add_as_children) ? &start_with : soinfos,
1504 (start_with != nullptr && add_as_children) ? 1 : soinfos_count,
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001505 [&] (soinfo* si) {
1506 local_group.push_back(si);
1507 return true;
1508 });
1509
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001510 // We need to increment ref_count in case
1511 // the root of the local group was not linked.
1512 bool was_local_group_root_linked = local_group.front()->is_linked();
1513
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001514 bool linked = local_group.visit([&](soinfo* si) {
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001515 if (!si->is_linked()) {
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08001516 if (!si->link_image(global_group, local_group, extinfo)) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001517 return false;
1518 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001519 }
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001520
1521 return true;
1522 });
1523
1524 if (linked) {
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001525 local_group.for_each([](soinfo* si) {
1526 if (!si->is_linked()) {
1527 si->set_linked();
1528 }
1529 });
1530
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001531 failure_guard.disable();
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001532 }
1533
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001534 if (!was_local_group_root_linked) {
1535 local_group.front()->increment_ref_count();
1536 }
1537
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001538 return linked;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001539}
1540
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001541static soinfo* find_library(android_namespace_t* ns,
1542 const char* name, int rtld_flags,
Evgenii Stepanov0cdef7e2015-07-06 17:56:31 -07001543 const android_dlextinfo* extinfo,
1544 soinfo* needed_by) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001545 soinfo* si;
1546
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001547 if (name == nullptr) {
Dimitry Ivanov3f660572016-09-09 10:00:39 -07001548 si = solist_get_somain();
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001549 } else if (!find_libraries(ns, needed_by, &name, 1, &si, nullptr, 0, rtld_flags,
Evgenii Stepanov0cdef7e2015-07-06 17:56:31 -07001550 extinfo, /* add_as_children */ false)) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001551 return nullptr;
1552 }
1553
Elliott Hughesd23736e2012-11-01 15:16:56 -07001554 return si;
1555}
Elliott Hughesbedfe382012-08-14 14:07:59 -07001556
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001557static void soinfo_unload(soinfo* root) {
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001558 if (root->is_linked()) {
1559 root = root->get_local_group_root();
1560 }
1561
1562 if (!root->can_unload()) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001563 TRACE("not unloading \"%s\" - the binary is flagged with NODELETE", root->get_realpath());
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -07001564 return;
1565 }
1566
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001567 soinfo_unload(&root, 1);
1568}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001569
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001570static void soinfo_unload(soinfo* soinfos[], size_t count) {
1571 // Note that the library can be loaded but not linked;
1572 // in which case there is no root but we still need
1573 // to walk the tree and unload soinfos involved.
1574 //
1575 // This happens on unsuccessful dlopen, when one of
1576 // the DT_NEEDED libraries could not be linked/found.
1577 if (count == 0) {
1578 return;
1579 }
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001580
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001581 soinfo_list_t unload_list;
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001582 for (size_t i = 0; i < count; ++i) {
1583 soinfo* si = soinfos[i];
Dmitriy Ivanov5ae82cb2014-12-02 17:08:42 -08001584
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001585 if (si->can_unload()) {
1586 size_t ref_count = si->is_linked() ? si->decrement_ref_count() : 0;
1587 if (ref_count == 0) {
1588 unload_list.push_back(si);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001589 } else {
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001590 TRACE("not unloading '%s' group, decrementing ref_count to %zd",
1591 si->get_realpath(), ref_count);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001592 }
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001593 } else {
1594 TRACE("not unloading '%s' - the binary is flagged with NODELETE", si->get_realpath());
1595 return;
1596 }
1597 }
1598
1599 // This is used to identify soinfos outside of the load-group
1600 // note that we cannot have > 1 in the array and have any of them
1601 // linked. This is why we can safely use the first one.
1602 soinfo* root = soinfos[0];
1603
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001604 soinfo_list_t local_unload_list;
1605 soinfo_list_t external_unload_list;
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001606 soinfo* si = nullptr;
1607
1608 while ((si = unload_list.pop_front()) != nullptr) {
1609 if (local_unload_list.contains(si)) {
1610 continue;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001611 }
Elliott Hughesd23736e2012-11-01 15:16:56 -07001612
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001613 local_unload_list.push_back(si);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001614
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001615 if (si->has_min_version(0)) {
1616 soinfo* child = nullptr;
1617 while ((child = si->get_children().pop_front()) != nullptr) {
1618 TRACE("%s@%p needs to unload %s@%p", si->get_realpath(), si,
1619 child->get_realpath(), child);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001620
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001621 if (local_unload_list.contains(child)) {
1622 continue;
1623 } else if (child->is_linked() && child->get_local_group_root() != root) {
1624 external_unload_list.push_back(child);
1625 } else {
1626 unload_list.push_front(child);
1627 }
1628 }
1629 } else {
1630#if !defined(__work_around_b_24465209__)
1631 __libc_fatal("soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
1632#else
1633 PRINT("warning: soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
1634 for_each_dt_needed(si, [&] (const char* library_name) {
1635 TRACE("deprecated (old format of soinfo): %s needs to unload %s",
1636 si->get_realpath(), library_name);
1637
1638 soinfo* needed = find_library(si->get_primary_namespace(),
1639 library_name, RTLD_NOLOAD, nullptr, nullptr);
1640
1641 if (needed != nullptr) {
1642 // Not found: for example if symlink was deleted between dlopen and dlclose
1643 // Since we cannot really handle errors at this point - print and continue.
1644 PRINT("warning: couldn't find %s needed by %s on unload.",
1645 library_name, si->get_realpath());
1646 return;
1647 } else if (local_unload_list.contains(needed)) {
1648 // already visited
1649 return;
1650 } else if (needed->is_linked() && needed->get_local_group_root() != root) {
1651 // external group
1652 external_unload_list.push_back(needed);
1653 } else {
1654 // local group
1655 unload_list.push_front(needed);
1656 }
1657 });
1658#endif
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001659 }
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001660 }
1661
1662 local_unload_list.for_each([](soinfo* si) {
1663 si->call_destructors();
1664 });
1665
1666 while ((si = local_unload_list.pop_front()) != nullptr) {
1667 notify_gdb_of_unload(si);
1668 soinfo_free(si);
1669 }
1670
1671 while ((si = external_unload_list.pop_front()) != nullptr) {
1672 soinfo_unload(si);
Dmitriy Ivanova2547052014-11-18 12:03:09 -08001673 }
1674}
1675
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001676static std::string symbol_display_name(const char* sym_name, const char* sym_ver) {
1677 if (sym_ver == nullptr) {
1678 return sym_name;
1679 }
1680
Dimitry Ivanov9cf99cb2015-12-11 14:22:24 -08001681 return std::string(sym_name) + ", version " + sym_ver;
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001682}
1683
Dimitry Ivanovaca299a2016-04-11 12:42:58 -07001684static android_namespace_t* get_caller_namespace(soinfo* caller) {
1685 return caller != nullptr ? caller->get_primary_namespace() : g_anonymous_namespace;
1686}
1687
Elliott Hughesa4aafd12014-01-13 16:37:47 -08001688void do_android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size) {
Christopher Ferris052fa3a2014-08-26 20:48:11 -07001689 // Use basic string manipulation calls to avoid snprintf.
1690 // snprintf indirectly calls pthread_getspecific to get the size of a buffer.
1691 // When debug malloc is enabled, this call returns 0. This in turn causes
1692 // snprintf to do nothing, which causes libraries to fail to load.
1693 // See b/17302493 for further details.
1694 // Once the above bug is fixed, this code can be modified to use
1695 // snprintf again.
Evgenii Stepanovd640b222015-07-10 17:54:01 -07001696 size_t required_len = 0;
1697 for (size_t i = 0; g_default_ld_paths[i] != nullptr; ++i) {
1698 required_len += strlen(g_default_ld_paths[i]) + 1;
1699 }
Christopher Ferris052fa3a2014-08-26 20:48:11 -07001700 if (buffer_size < required_len) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07001701 __libc_fatal("android_get_LD_LIBRARY_PATH failed, buffer too small: "
1702 "buffer len %zu, required len %zu", buffer_size, required_len);
Christopher Ferris052fa3a2014-08-26 20:48:11 -07001703 }
Evgenii Stepanovd640b222015-07-10 17:54:01 -07001704 char* end = buffer;
1705 for (size_t i = 0; g_default_ld_paths[i] != nullptr; ++i) {
1706 if (i > 0) *end++ = ':';
1707 end = stpcpy(end, g_default_ld_paths[i]);
1708 }
Elliott Hughesa4aafd12014-01-13 16:37:47 -08001709}
1710
Elliott Hughescade4c32012-12-20 14:42:14 -08001711void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path) {
Nick Kralevich6bb01b62015-03-07 13:37:05 -08001712 parse_LD_LIBRARY_PATH(ld_library_path);
Elliott Hughescade4c32012-12-20 14:42:14 -08001713}
1714
Dimitry Ivanovb996d602016-07-11 18:11:39 -07001715static std::string android_dlextinfo_to_string(const android_dlextinfo* info) {
1716 if (info == nullptr) {
1717 return "(null)";
1718 }
1719
1720 return android::base::StringPrintf("[flags=0x%" PRIx64 ","
1721 " reserved_addr=%p,"
1722 " reserved_size=0x%zx,"
1723 " relro_fd=%d,"
1724 " library_fd=%d,"
1725 " library_fd_offset=0x%" PRIx64 ","
1726 " library_namespace=%s@%p]",
1727 info->flags,
1728 info->reserved_addr,
1729 info->reserved_size,
1730 info->relro_fd,
1731 info->library_fd,
1732 info->library_fd_offset,
1733 (info->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0 ?
1734 (info->library_namespace != nullptr ?
1735 info->library_namespace->get_name() : "(null)") : "(n/a)",
1736 (info->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0 ?
1737 info->library_namespace : nullptr);
1738}
1739
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001740void* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo,
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001741 void* caller_addr) {
1742 soinfo* const caller = find_containing_library(caller_addr);
Dimitry Ivanovb996d602016-07-11 18:11:39 -07001743 android_namespace_t* ns = get_caller_namespace(caller);
1744
1745 LD_LOG(kLogDlopen,
1746 "dlopen(name=\"%s\", flags=0x%x, extinfo=%s, caller=\"%s\", caller_ns=%s@%p) ...",
1747 name,
1748 flags,
1749 android_dlextinfo_to_string(extinfo).c_str(),
1750 caller == nullptr ? "(null)" : caller->get_realpath(),
1751 ns == nullptr ? "(null)" : ns->get_name(),
1752 ns);
1753
1754 auto failure_guard = make_scope_guard([&]() {
1755 LD_LOG(kLogDlopen, "... dlopen failed: %s", linker_get_error_buffer());
1756 });
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001757
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -07001758 if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL|RTLD_NODELETE|RTLD_NOLOAD)) != 0) {
Elliott Hughese66190d2012-12-18 15:57:55 -08001759 DL_ERR("invalid flags to dlopen: %x", flags);
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07001760 return nullptr;
Elliott Hughese66190d2012-12-18 15:57:55 -08001761 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001762
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001763 if (extinfo != nullptr) {
1764 if ((extinfo->flags & ~(ANDROID_DLEXT_VALID_FLAG_BITS)) != 0) {
1765 DL_ERR("invalid extended flags to android_dlopen_ext: 0x%" PRIx64, extinfo->flags);
1766 return nullptr;
1767 }
Dmitriy Ivanov126af752015-10-07 16:34:20 -07001768
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001769 if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) == 0 &&
Dmitriy Ivanova6c12792014-10-21 12:09:18 -07001770 (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07001771 DL_ERR("invalid extended flag combination (ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET without "
1772 "ANDROID_DLEXT_USE_LIBRARY_FD): 0x%" PRIx64, extinfo->flags);
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001773 return nullptr;
1774 }
Dmitriy Ivanov126af752015-10-07 16:34:20 -07001775
1776 if ((extinfo->flags & ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS) != 0 &&
1777 (extinfo->flags & (ANDROID_DLEXT_RESERVED_ADDRESS | ANDROID_DLEXT_RESERVED_ADDRESS_HINT)) != 0) {
1778 DL_ERR("invalid extended flag combination: ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS is not "
1779 "compatible with ANDROID_DLEXT_RESERVED_ADDRESS/ANDROID_DLEXT_RESERVED_ADDRESS_HINT");
1780 return nullptr;
1781 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001782
1783 if ((extinfo->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0) {
1784 if (extinfo->library_namespace == nullptr) {
1785 DL_ERR("ANDROID_DLEXT_USE_NAMESPACE is set but extinfo->library_namespace is null");
1786 return nullptr;
1787 }
1788 ns = extinfo->library_namespace;
1789 }
Torne (Richard Coles)012cb452014-02-06 14:34:21 +00001790 }
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -08001791
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -07001792 std::string asan_name_holder;
1793
1794 const char* translated_name = name;
1795 if (g_is_asan) {
1796 if (file_is_in_dir(name, kSystemLibDir)) {
1797 asan_name_holder = std::string(kAsanSystemLibDir) + "/" + basename(name);
1798 if (file_exists(asan_name_holder.c_str())) {
1799 translated_name = asan_name_holder.c_str();
1800 PRINT("linker_asan dlopen translating \"%s\" -> \"%s\"", name, translated_name);
1801 }
1802 } else if (file_is_in_dir(name, kVendorLibDir)) {
1803 asan_name_holder = std::string(kAsanVendorLibDir) + "/" + basename(name);
1804 if (file_exists(asan_name_holder.c_str())) {
1805 translated_name = asan_name_holder.c_str();
1806 PRINT("linker_asan dlopen translating \"%s\" -> \"%s\"", name, translated_name);
1807 }
1808 }
1809 }
1810
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -08001811 ProtectedDataGuard guard;
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -07001812 soinfo* si = find_library(ns, translated_name, flags, extinfo, caller);
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07001813 if (si != nullptr) {
Dimitry Ivanovb996d602016-07-11 18:11:39 -07001814 failure_guard.disable();
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08001815 si->call_constructors();
Dimitry Ivanovb996d602016-07-11 18:11:39 -07001816 void* handle = si->to_handle();
1817 LD_LOG(kLogDlopen,
1818 "... dlopen successful: realpath=\"%s\", soname=\"%s\", handle=%p",
1819 si->get_realpath(), si->get_soname(), handle);
1820 return handle;
Elliott Hughesd23736e2012-11-01 15:16:56 -07001821 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001822
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001823 return nullptr;
Elliott Hughesd23736e2012-11-01 15:16:56 -07001824}
1825
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001826int do_dladdr(const void* addr, Dl_info* info) {
1827 // Determine if this address can be found in any library currently mapped.
1828 soinfo* si = find_containing_library(addr);
1829 if (si == nullptr) {
1830 return 0;
1831 }
1832
1833 memset(info, 0, sizeof(Dl_info));
1834
1835 info->dli_fname = si->get_realpath();
1836 // Address at which the shared object is loaded.
1837 info->dli_fbase = reinterpret_cast<void*>(si->base);
1838
1839 // Determine if any symbol in the library contains the specified address.
1840 ElfW(Sym)* sym = si->find_symbol_by_address(addr);
1841 if (sym != nullptr) {
1842 info->dli_sname = si->get_string(sym->st_name);
1843 info->dli_saddr = reinterpret_cast<void*>(si->resolve_symbol_address(sym));
1844 }
1845
1846 return 1;
1847}
1848
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001849static soinfo* soinfo_from_handle(void* handle) {
1850 if ((reinterpret_cast<uintptr_t>(handle) & 1) != 0) {
1851 auto it = g_soinfo_handles_map.find(reinterpret_cast<uintptr_t>(handle));
1852 if (it == g_soinfo_handles_map.end()) {
1853 return nullptr;
1854 } else {
1855 return it->second;
1856 }
1857 }
1858
1859 return static_cast<soinfo*>(handle);
1860}
1861
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001862bool do_dlsym(void* handle, const char* sym_name, const char* sym_ver,
1863 void* caller_addr, void** symbol) {
1864#if !defined(__LP64__)
1865 if (handle == nullptr) {
1866 DL_ERR("dlsym failed: library handle is null");
1867 return false;
1868 }
1869#endif
1870
1871 if (sym_name == nullptr) {
1872 DL_ERR("dlsym failed: symbol name is null");
1873 return false;
1874 }
1875
1876 soinfo* found = nullptr;
1877 const ElfW(Sym)* sym = nullptr;
1878 soinfo* caller = find_containing_library(caller_addr);
Dimitry Ivanovaca299a2016-04-11 12:42:58 -07001879 android_namespace_t* ns = get_caller_namespace(caller);
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001880
1881 version_info vi_instance;
1882 version_info* vi = nullptr;
1883
1884 if (sym_ver != nullptr) {
Dimitry Ivanov9cf99cb2015-12-11 14:22:24 -08001885 vi_instance.name = sym_ver;
1886 vi_instance.elf_hash = calculate_elf_hash(sym_ver);
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001887 vi = &vi_instance;
1888 }
1889
1890 if (handle == RTLD_DEFAULT || handle == RTLD_NEXT) {
1891 sym = dlsym_linear_lookup(ns, sym_name, vi, &found, caller, handle);
1892 } else {
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001893 soinfo* si = soinfo_from_handle(handle);
1894 if (si == nullptr) {
1895 DL_ERR("dlsym failed: invalid handle: %p", handle);
1896 return false;
1897 }
1898 sym = dlsym_handle_lookup(si, &found, sym_name, vi);
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001899 }
1900
1901 if (sym != nullptr) {
1902 uint32_t bind = ELF_ST_BIND(sym->st_info);
1903
1904 if ((bind == STB_GLOBAL || bind == STB_WEAK) && sym->st_shndx != 0) {
1905 *symbol = reinterpret_cast<void*>(found->resolve_symbol_address(sym));
1906 return true;
1907 }
1908
1909 DL_ERR("symbol \"%s\" found but not global", symbol_display_name(sym_name, sym_ver).c_str());
1910 return false;
1911 }
1912
1913 DL_ERR("undefined symbol: %s", symbol_display_name(sym_name, sym_ver).c_str());
1914 return false;
1915}
1916
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001917int do_dlclose(void* handle) {
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -08001918 ProtectedDataGuard guard;
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001919 soinfo* si = soinfo_from_handle(handle);
1920 if (si == nullptr) {
1921 DL_ERR("invalid handle: %p", handle);
1922 return -1;
1923 }
1924
Dmitriy Ivanovb648a8a2014-05-19 15:06:58 -07001925 soinfo_unload(si);
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001926 return 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001927}
1928
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08001929bool init_namespaces(const char* public_ns_sonames, const char* anon_ns_library_path) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001930 if (g_public_namespace_initialized) {
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08001931 DL_ERR("public namespace has already been initialized.");
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001932 return false;
1933 }
1934
Dimitry Ivanov54807612016-04-21 14:57:38 -07001935 if (public_ns_sonames == nullptr || public_ns_sonames[0] == '\0') {
1936 DL_ERR("error initializing public namespace: the list of public libraries is empty.");
1937 return false;
1938 }
1939
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08001940 std::vector<std::string> sonames = android::base::Split(public_ns_sonames, ":");
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001941
1942 ProtectedDataGuard guard;
1943
1944 auto failure_guard = make_scope_guard([&]() {
1945 g_public_namespace.clear();
1946 });
1947
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001948 for (const auto& soname : sonames) {
Dmitriy Ivanov3cc35e22015-11-17 18:36:50 -08001949 soinfo* candidate = nullptr;
1950
1951 find_loaded_library_by_soname(&g_default_namespace, soname.c_str(), &candidate);
1952
1953 if (candidate == nullptr) {
Christopher Ferris523e2a92016-06-17 13:46:36 -07001954 DL_ERR("error initializing public namespace: a library with soname \"%s\""
1955 " was not found in the default namespace", soname.c_str());
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001956 return false;
1957 }
1958
1959 candidate->set_nodelete();
1960 g_public_namespace.push_back(candidate);
1961 }
1962
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001963 g_public_namespace_initialized = true;
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08001964
1965 // create anonymous namespace
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08001966 // When the caller is nullptr - create_namespace will take global group
1967 // from the anonymous namespace, which is fine because anonymous namespace
1968 // is still pointing to the default one.
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08001969 android_namespace_t* anon_ns =
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08001970 create_namespace(nullptr, "(anonymous)", nullptr, anon_ns_library_path,
Dimitry Ivanov52408632016-05-23 10:31:11 -07001971 ANDROID_NAMESPACE_TYPE_REGULAR, nullptr, &g_default_namespace);
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08001972
1973 if (anon_ns == nullptr) {
1974 g_public_namespace_initialized = false;
1975 return false;
1976 }
1977 g_anonymous_namespace = anon_ns;
1978 failure_guard.disable();
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001979 return true;
1980}
1981
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001982static void add_soinfos_to_namespace(const soinfo_list_t& soinfos, android_namespace_t* ns) {
1983 ns->add_soinfos(soinfos);
1984 for (auto si : soinfos) {
1985 si->add_secondary_namespace(ns);
1986 }
1987}
1988
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08001989android_namespace_t* create_namespace(const void* caller_addr,
1990 const char* name,
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001991 const char* ld_library_path,
1992 const char* default_library_path,
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08001993 uint64_t type,
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07001994 const char* permitted_when_isolated_path,
1995 android_namespace_t* parent_namespace) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001996 if (!g_public_namespace_initialized) {
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08001997 DL_ERR("cannot create namespace: public namespace is not initialized.");
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001998 return nullptr;
1999 }
2000
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002001 if (parent_namespace == nullptr) {
Dimitry Ivanov52408632016-05-23 10:31:11 -07002002 // if parent_namespace is nullptr -> set it to the caller namespace
2003 soinfo* caller_soinfo = find_containing_library(caller_addr);
2004
2005 parent_namespace = caller_soinfo != nullptr ?
2006 caller_soinfo->get_primary_namespace() :
2007 g_anonymous_namespace;
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002008 }
2009
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002010 ProtectedDataGuard guard;
2011 std::vector<std::string> ld_library_paths;
2012 std::vector<std::string> default_library_paths;
Dimitry Ivanov284ae352015-12-08 10:47:13 -08002013 std::vector<std::string> permitted_paths;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002014
2015 parse_path(ld_library_path, ":", &ld_library_paths);
2016 parse_path(default_library_path, ":", &default_library_paths);
Dimitry Ivanov284ae352015-12-08 10:47:13 -08002017 parse_path(permitted_when_isolated_path, ":", &permitted_paths);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002018
2019 android_namespace_t* ns = new (g_namespace_allocator.alloc()) android_namespace_t();
2020 ns->set_name(name);
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002021 ns->set_isolated((type & ANDROID_NAMESPACE_TYPE_ISOLATED) != 0);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002022 ns->set_ld_library_paths(std::move(ld_library_paths));
2023 ns->set_default_library_paths(std::move(default_library_paths));
Dimitry Ivanov284ae352015-12-08 10:47:13 -08002024 ns->set_permitted_paths(std::move(permitted_paths));
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002025
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002026 if ((type & ANDROID_NAMESPACE_TYPE_SHARED) != 0) {
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002027 // If shared - clone the parent namespace
Dimitry Ivanovb943f302016-08-03 16:00:10 -07002028 add_soinfos_to_namespace(parent_namespace->soinfo_list(), ns);
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002029 } else {
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002030 // If not shared - copy only the shared group
Dimitry Ivanovb943f302016-08-03 16:00:10 -07002031 add_soinfos_to_namespace(get_shared_group(parent_namespace), ns);
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002032 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002033
2034 return ns;
2035}
2036
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002037ElfW(Addr) call_ifunc_resolver(ElfW(Addr) resolver_addr) {
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07002038 typedef ElfW(Addr) (*ifunc_resolver_t)(void);
2039 ifunc_resolver_t ifunc_resolver = reinterpret_cast<ifunc_resolver_t>(resolver_addr);
2040 ElfW(Addr) ifunc_addr = ifunc_resolver();
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002041 TRACE_TYPE(RELO, "Called ifunc_resolver@%p. The result is %p",
2042 ifunc_resolver, reinterpret_cast<void*>(ifunc_addr));
Brigid Smithc5a13ef2014-07-23 11:22:25 -07002043
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07002044 return ifunc_addr;
Brigid Smithc5a13ef2014-07-23 11:22:25 -07002045}
Brigid Smithc5a13ef2014-07-23 11:22:25 -07002046
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002047const version_info* VersionTracker::get_version_info(ElfW(Versym) source_symver) const {
2048 if (source_symver < 2 ||
2049 source_symver >= version_infos.size() ||
2050 version_infos[source_symver].name == nullptr) {
2051 return nullptr;
2052 }
2053
2054 return &version_infos[source_symver];
2055}
2056
2057void VersionTracker::add_version_info(size_t source_index,
2058 ElfW(Word) elf_hash,
2059 const char* ver_name,
2060 const soinfo* target_si) {
2061 if (source_index >= version_infos.size()) {
2062 version_infos.resize(source_index+1);
2063 }
2064
2065 version_infos[source_index].elf_hash = elf_hash;
2066 version_infos[source_index].name = ver_name;
2067 version_infos[source_index].target_si = target_si;
2068}
2069
2070bool VersionTracker::init_verneed(const soinfo* si_from) {
2071 uintptr_t verneed_ptr = si_from->get_verneed_ptr();
2072
2073 if (verneed_ptr == 0) {
2074 return true;
2075 }
2076
2077 size_t verneed_cnt = si_from->get_verneed_cnt();
2078
2079 for (size_t i = 0, offset = 0; i<verneed_cnt; ++i) {
2080 const ElfW(Verneed)* verneed = reinterpret_cast<ElfW(Verneed)*>(verneed_ptr + offset);
2081 size_t vernaux_offset = offset + verneed->vn_aux;
2082 offset += verneed->vn_next;
2083
2084 if (verneed->vn_version != 1) {
2085 DL_ERR("unsupported verneed[%zd] vn_version: %d (expected 1)", i, verneed->vn_version);
2086 return false;
2087 }
2088
2089 const char* target_soname = si_from->get_string(verneed->vn_file);
2090 // find it in dependencies
2091 soinfo* target_si = si_from->get_children().find_if([&](const soinfo* si) {
Dmitriy Ivanov406d9962015-05-06 11:05:27 -07002092 return si->get_soname() != nullptr && strcmp(si->get_soname(), target_soname) == 0;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002093 });
2094
2095 if (target_si == nullptr) {
2096 DL_ERR("cannot find \"%s\" from verneed[%zd] in DT_NEEDED list for \"%s\"",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002097 target_soname, i, si_from->get_realpath());
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002098 return false;
2099 }
2100
2101 for (size_t j = 0; j<verneed->vn_cnt; ++j) {
2102 const ElfW(Vernaux)* vernaux = reinterpret_cast<ElfW(Vernaux)*>(verneed_ptr + vernaux_offset);
2103 vernaux_offset += vernaux->vna_next;
2104
2105 const ElfW(Word) elf_hash = vernaux->vna_hash;
2106 const char* ver_name = si_from->get_string(vernaux->vna_name);
2107 ElfW(Half) source_index = vernaux->vna_other;
2108
2109 add_version_info(source_index, elf_hash, ver_name, target_si);
2110 }
2111 }
2112
2113 return true;
2114}
2115
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002116template <typename F>
2117static bool for_each_verdef(const soinfo* si, F functor) {
2118 if (!si->has_min_version(2)) {
2119 return true;
2120 }
2121
2122 uintptr_t verdef_ptr = si->get_verdef_ptr();
2123 if (verdef_ptr == 0) {
2124 return true;
2125 }
2126
2127 size_t offset = 0;
2128
2129 size_t verdef_cnt = si->get_verdef_cnt();
2130 for (size_t i = 0; i<verdef_cnt; ++i) {
2131 const ElfW(Verdef)* verdef = reinterpret_cast<ElfW(Verdef)*>(verdef_ptr + offset);
2132 size_t verdaux_offset = offset + verdef->vd_aux;
2133 offset += verdef->vd_next;
2134
2135 if (verdef->vd_version != 1) {
2136 DL_ERR("unsupported verdef[%zd] vd_version: %d (expected 1) library: %s",
2137 i, verdef->vd_version, si->get_realpath());
2138 return false;
2139 }
2140
2141 if ((verdef->vd_flags & VER_FLG_BASE) != 0) {
2142 // "this is the version of the file itself. It must not be used for
2143 // matching a symbol. It can be used to match references."
2144 //
2145 // http://www.akkadia.org/drepper/symbol-versioning
2146 continue;
2147 }
2148
2149 if (verdef->vd_cnt == 0) {
2150 DL_ERR("invalid verdef[%zd] vd_cnt == 0 (version without a name)", i);
2151 return false;
2152 }
2153
2154 const ElfW(Verdaux)* verdaux = reinterpret_cast<ElfW(Verdaux)*>(verdef_ptr + verdaux_offset);
2155
2156 if (functor(i, verdef, verdaux) == true) {
2157 break;
2158 }
2159 }
2160
2161 return true;
2162}
2163
2164bool find_verdef_version_index(const soinfo* si, const version_info* vi, ElfW(Versym)* versym) {
2165 if (vi == nullptr) {
2166 *versym = kVersymNotNeeded;
2167 return true;
2168 }
2169
2170 *versym = kVersymGlobal;
2171
2172 return for_each_verdef(si,
2173 [&](size_t, const ElfW(Verdef)* verdef, const ElfW(Verdaux)* verdaux) {
2174 if (verdef->vd_hash == vi->elf_hash &&
2175 strcmp(vi->name, si->get_string(verdaux->vda_name)) == 0) {
2176 *versym = verdef->vd_ndx;
2177 return true;
2178 }
2179
2180 return false;
2181 }
2182 );
2183}
2184
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002185bool VersionTracker::init_verdef(const soinfo* si_from) {
2186 return for_each_verdef(si_from,
2187 [&](size_t, const ElfW(Verdef)* verdef, const ElfW(Verdaux)* verdaux) {
2188 add_version_info(verdef->vd_ndx, verdef->vd_hash,
2189 si_from->get_string(verdaux->vda_name), si_from);
2190 return false;
2191 }
2192 );
2193}
2194
2195bool VersionTracker::init(const soinfo* si_from) {
2196 if (!si_from->has_min_version(2)) {
2197 return true;
2198 }
2199
2200 return init_verneed(si_from) && init_verdef(si_from);
2201}
2202
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002203// TODO (dimitry): Methods below need to be moved out of soinfo
2204// and in more isolated file in order minimize dependencies on
2205// unnecessary object in the linker binary. Consider making them
2206// independent from soinfo (?).
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002207bool soinfo::lookup_version_info(const VersionTracker& version_tracker, ElfW(Word) sym,
2208 const char* sym_name, const version_info** vi) {
2209 const ElfW(Versym)* sym_ver_ptr = get_versym(sym);
2210 ElfW(Versym) sym_ver = sym_ver_ptr == nullptr ? 0 : *sym_ver_ptr;
2211
2212 if (sym_ver != VER_NDX_LOCAL && sym_ver != VER_NDX_GLOBAL) {
2213 *vi = version_tracker.get_version_info(sym_ver);
2214
2215 if (*vi == nullptr) {
2216 DL_ERR("cannot find verneed/verdef for version index=%d "
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002217 "referenced by symbol \"%s\" at \"%s\"", sym_ver, sym_name, get_realpath());
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002218 return false;
2219 }
2220 } else {
2221 // there is no version info
2222 *vi = nullptr;
2223 }
2224
2225 return true;
2226}
2227
Dimitry Ivanov576a3752016-08-09 06:58:55 -07002228#if !defined(__mips__)
2229#if defined(USE_RELA)
2230static ElfW(Addr) get_addend(ElfW(Rela)* rela, ElfW(Addr) reloc_addr __unused) {
2231 return rela->r_addend;
2232}
2233#else
2234static ElfW(Addr) get_addend(ElfW(Rel)* rel, ElfW(Addr) reloc_addr) {
2235 if (ELFW(R_TYPE)(rel->r_info) == R_GENERIC_RELATIVE ||
2236 ELFW(R_TYPE)(rel->r_info) == R_GENERIC_IRELATIVE) {
2237 return *reinterpret_cast<ElfW(Addr)*>(reloc_addr);
2238 }
2239 return 0;
2240}
2241#endif
2242
Dmitriy Ivanovfa26eee2015-02-03 16:06:47 -08002243template<typename ElfRelIteratorT>
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07002244bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& rel_iterator,
2245 const soinfo_list_t& global_group, const soinfo_list_t& local_group) {
Dmitriy Ivanovfa26eee2015-02-03 16:06:47 -08002246 for (size_t idx = 0; rel_iterator.has_next(); ++idx) {
2247 const auto rel = rel_iterator.next();
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002248 if (rel == nullptr) {
2249 return false;
2250 }
2251
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002252 ElfW(Word) type = ELFW(R_TYPE)(rel->r_info);
2253 ElfW(Word) sym = ELFW(R_SYM)(rel->r_info);
2254
2255 ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rel->r_offset + load_bias);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002256 ElfW(Addr) sym_addr = 0;
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07002257 const char* sym_name = nullptr;
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002258 ElfW(Addr) addend = get_addend(rel, reloc);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002259
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07002260 DEBUG("Processing \"%s\" relocation at index %zd", get_realpath(), idx);
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002261 if (type == R_GENERIC_NONE) {
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002262 continue;
2263 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002264
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002265 const ElfW(Sym)* s = nullptr;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002266 soinfo* lsi = nullptr;
2267
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002268 if (sym != 0) {
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002269 sym_name = get_string(symtab_[sym].st_name);
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002270 const version_info* vi = nullptr;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002271
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002272 if (!lookup_version_info(version_tracker, sym, sym_name, &vi)) {
2273 return false;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002274 }
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002275
2276 if (!soinfo_do_lookup(this, sym_name, vi, &lsi, global_group, local_group, &s)) {
2277 return false;
2278 }
2279
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07002280 if (s == nullptr) {
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002281 // We only allow an undefined symbol if this is a weak reference...
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002282 s = &symtab_[sym];
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002283 if (ELF_ST_BIND(s->st_info) != STB_WEAK) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002284 DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, get_realpath());
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002285 return false;
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002286 }
2287
2288 /* IHI0044C AAELF 4.5.1.1:
2289
2290 Libraries are not searched to resolve weak references.
2291 It is not an error for a weak reference to remain unsatisfied.
2292
2293 During linking, the value of an undefined weak reference is:
2294 - Zero if the relocation type is absolute
2295 - The address of the place if the relocation is pc-relative
2296 - The address of nominal base address if the relocation
2297 type is base-relative.
2298 */
2299
2300 switch (type) {
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002301 case R_GENERIC_JUMP_SLOT:
2302 case R_GENERIC_GLOB_DAT:
2303 case R_GENERIC_RELATIVE:
2304 case R_GENERIC_IRELATIVE:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002305#if defined(__aarch64__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002306 case R_AARCH64_ABS64:
2307 case R_AARCH64_ABS32:
2308 case R_AARCH64_ABS16:
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002309#elif defined(__x86_64__)
2310 case R_X86_64_32:
2311 case R_X86_64_64:
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002312#elif defined(__arm__)
2313 case R_ARM_ABS32:
2314#elif defined(__i386__)
2315 case R_386_32:
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002316#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002317 /*
2318 * The sym_addr was initialized to be zero above, or the relocation
2319 * code below does not care about value of sym_addr.
2320 * No need to do anything.
2321 */
2322 break;
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002323#if defined(__x86_64__)
Dimitry Ivanovd338aac2015-01-13 22:31:54 +00002324 case R_X86_64_PC32:
2325 sym_addr = reloc;
2326 break;
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002327#elif defined(__i386__)
2328 case R_386_PC32:
2329 sym_addr = reloc;
2330 break;
2331#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002332 default:
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002333 DL_ERR("unknown weak reloc type %d @ %p (%zu)", type, rel, idx);
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002334 return false;
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002335 }
Dmitriy Ivanovec83a612015-07-26 07:37:09 -07002336 } else { // We got a definition.
2337#if !defined(__LP64__)
2338 // When relocating dso with text_relocation .text segment is
2339 // not executable. We need to restore elf flags before resolving
2340 // STT_GNU_IFUNC symbol.
2341 bool protect_segments = has_text_relocations &&
2342 lsi == this &&
2343 ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC;
2344 if (protect_segments) {
2345 if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
2346 DL_ERR("can't protect segments for \"%s\": %s",
2347 get_realpath(), strerror(errno));
2348 return false;
2349 }
2350 }
2351#endif
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07002352 sym_addr = lsi->resolve_symbol_address(s);
Dmitriy Ivanovec83a612015-07-26 07:37:09 -07002353#if !defined(__LP64__)
2354 if (protect_segments) {
2355 if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
2356 DL_ERR("can't unprotect loadable segments for \"%s\": %s",
2357 get_realpath(), strerror(errno));
2358 return false;
2359 }
2360 }
2361#endif
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002362 }
2363 count_relocation(kRelocSymbol);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002364 }
2365
2366 switch (type) {
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002367 case R_GENERIC_JUMP_SLOT:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002368 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002369 MARK(rel->r_offset);
2370 TRACE_TYPE(RELO, "RELO JMP_SLOT %16p <- %16p %s\n",
2371 reinterpret_cast<void*>(reloc),
2372 reinterpret_cast<void*>(sym_addr + addend), sym_name);
2373
2374 *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002375 break;
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002376 case R_GENERIC_GLOB_DAT:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002377 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002378 MARK(rel->r_offset);
2379 TRACE_TYPE(RELO, "RELO GLOB_DAT %16p <- %16p %s\n",
2380 reinterpret_cast<void*>(reloc),
2381 reinterpret_cast<void*>(sym_addr + addend), sym_name);
2382 *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002383 break;
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002384 case R_GENERIC_RELATIVE:
2385 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002386 MARK(rel->r_offset);
2387 TRACE_TYPE(RELO, "RELO RELATIVE %16p <- %16p\n",
2388 reinterpret_cast<void*>(reloc),
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002389 reinterpret_cast<void*>(load_bias + addend));
2390 *reinterpret_cast<ElfW(Addr)*>(reloc) = (load_bias + addend);
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002391 break;
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002392 case R_GENERIC_IRELATIVE:
2393 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002394 MARK(rel->r_offset);
2395 TRACE_TYPE(RELO, "RELO IRELATIVE %16p <- %16p\n",
2396 reinterpret_cast<void*>(reloc),
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002397 reinterpret_cast<void*>(load_bias + addend));
Dmitriy Ivanovec83a612015-07-26 07:37:09 -07002398 {
2399#if !defined(__LP64__)
2400 // When relocating dso with text_relocation .text segment is
2401 // not executable. We need to restore elf flags for this
2402 // particular call.
2403 if (has_text_relocations) {
2404 if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
2405 DL_ERR("can't protect segments for \"%s\": %s",
2406 get_realpath(), strerror(errno));
2407 return false;
2408 }
2409 }
2410#endif
2411 ElfW(Addr) ifunc_addr = call_ifunc_resolver(load_bias + addend);
2412#if !defined(__LP64__)
2413 // Unprotect it afterwards...
2414 if (has_text_relocations) {
2415 if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
2416 DL_ERR("can't unprotect loadable segments for \"%s\": %s",
2417 get_realpath(), strerror(errno));
2418 return false;
2419 }
2420 }
2421#endif
2422 *reinterpret_cast<ElfW(Addr)*>(reloc) = ifunc_addr;
2423 }
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002424 break;
2425
2426#if defined(__aarch64__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002427 case R_AARCH64_ABS64:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002428 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002429 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002430 TRACE_TYPE(RELO, "RELO ABS64 %16llx <- %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002431 reloc, sym_addr + addend, sym_name);
2432 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend;
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002433 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002434 case R_AARCH64_ABS32:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002435 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002436 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002437 TRACE_TYPE(RELO, "RELO ABS32 %16llx <- %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002438 reloc, sym_addr + addend, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002439 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002440 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT32_MIN);
2441 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT32_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002442 if ((min_value <= (sym_addr + addend)) &&
2443 ((sym_addr + addend) <= max_value)) {
2444 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend;
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002445 } else {
2446 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002447 sym_addr + addend, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002448 return false;
2449 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002450 }
2451 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002452 case R_AARCH64_ABS16:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002453 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002454 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002455 TRACE_TYPE(RELO, "RELO ABS16 %16llx <- %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002456 reloc, sym_addr + addend, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002457 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002458 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN);
2459 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT16_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002460 if ((min_value <= (sym_addr + addend)) &&
2461 ((sym_addr + addend) <= max_value)) {
2462 *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002463 } else {
2464 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002465 sym_addr + addend, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002466 return false;
2467 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002468 }
2469 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002470 case R_AARCH64_PREL64:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002471 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002472 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002473 TRACE_TYPE(RELO, "RELO REL64 %16llx <- %16llx - %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002474 reloc, sym_addr + addend, rel->r_offset, sym_name);
2475 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset;
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002476 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002477 case R_AARCH64_PREL32:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002478 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002479 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002480 TRACE_TYPE(RELO, "RELO REL32 %16llx <- %16llx - %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002481 reloc, sym_addr + addend, rel->r_offset, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002482 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002483 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT32_MIN);
2484 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT32_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002485 if ((min_value <= (sym_addr + addend - rel->r_offset)) &&
2486 ((sym_addr + addend - rel->r_offset) <= max_value)) {
2487 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset;
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002488 } else {
2489 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002490 sym_addr + addend - rel->r_offset, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002491 return false;
2492 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002493 }
2494 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002495 case R_AARCH64_PREL16:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002496 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002497 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002498 TRACE_TYPE(RELO, "RELO REL16 %16llx <- %16llx - %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002499 reloc, sym_addr + addend, rel->r_offset, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002500 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002501 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN);
2502 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT16_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002503 if ((min_value <= (sym_addr + addend - rel->r_offset)) &&
2504 ((sym_addr + addend - rel->r_offset) <= max_value)) {
2505 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset;
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002506 } else {
2507 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002508 sym_addr + addend - rel->r_offset, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002509 return false;
2510 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002511 }
2512 break;
2513
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002514 case R_AARCH64_COPY:
Nick Kralevich76e289c2014-07-03 12:04:31 -07002515 /*
2516 * ET_EXEC is not supported so this should not happen.
2517 *
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002518 * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0056b/IHI0056B_aaelf64.pdf
Nick Kralevich76e289c2014-07-03 12:04:31 -07002519 *
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002520 * Section 4.6.11 "Dynamic relocations"
Nick Kralevich76e289c2014-07-03 12:04:31 -07002521 * R_AARCH64_COPY may only appear in executable objects where e_type is
2522 * set to ET_EXEC.
2523 */
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002524 DL_ERR("%s R_AARCH64_COPY relocations are not supported", get_realpath());
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002525 return false;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002526 case R_AARCH64_TLS_TPREL64:
Elliott Hughes0266ae52014-02-10 17:46:57 -08002527 TRACE_TYPE(RELO, "RELO TLS_TPREL64 *** %16llx <- %16llx - %16llx\n",
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002528 reloc, (sym_addr + addend), rel->r_offset);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002529 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002530 case R_AARCH64_TLS_DTPREL32:
Elliott Hughes0266ae52014-02-10 17:46:57 -08002531 TRACE_TYPE(RELO, "RELO TLS_DTPREL32 *** %16llx <- %16llx - %16llx\n",
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002532 reloc, (sym_addr + addend), rel->r_offset);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002533 break;
2534#elif defined(__x86_64__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002535 case R_X86_64_32:
2536 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002537 MARK(rel->r_offset);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002538 TRACE_TYPE(RELO, "RELO R_X86_64_32 %08zx <- +%08zx %s", static_cast<size_t>(reloc),
2539 static_cast<size_t>(sym_addr), sym_name);
Junichi Uekawaff35b1e2015-11-18 10:18:59 +09002540 *reinterpret_cast<Elf32_Addr*>(reloc) = sym_addr + addend;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002541 break;
2542 case R_X86_64_64:
2543 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002544 MARK(rel->r_offset);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002545 TRACE_TYPE(RELO, "RELO R_X86_64_64 %08zx <- +%08zx %s", static_cast<size_t>(reloc),
2546 static_cast<size_t>(sym_addr), sym_name);
Junichi Uekawaff35b1e2015-11-18 10:18:59 +09002547 *reinterpret_cast<Elf64_Addr*>(reloc) = sym_addr + addend;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002548 break;
2549 case R_X86_64_PC32:
2550 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002551 MARK(rel->r_offset);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002552 TRACE_TYPE(RELO, "RELO R_X86_64_PC32 %08zx <- +%08zx (%08zx - %08zx) %s",
2553 static_cast<size_t>(reloc), static_cast<size_t>(sym_addr - reloc),
2554 static_cast<size_t>(sym_addr), static_cast<size_t>(reloc), sym_name);
Junichi Uekawaff35b1e2015-11-18 10:18:59 +09002555 *reinterpret_cast<Elf32_Addr*>(reloc) = sym_addr + addend - reloc;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002556 break;
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002557#elif defined(__arm__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002558 case R_ARM_ABS32:
2559 count_relocation(kRelocAbsolute);
2560 MARK(rel->r_offset);
2561 TRACE_TYPE(RELO, "RELO ABS %08x <- %08x %s", reloc, sym_addr, sym_name);
2562 *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
2563 break;
2564 case R_ARM_REL32:
2565 count_relocation(kRelocRelative);
2566 MARK(rel->r_offset);
2567 TRACE_TYPE(RELO, "RELO REL32 %08x <- %08x - %08x %s",
2568 reloc, sym_addr, rel->r_offset, sym_name);
2569 *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr - rel->r_offset;
2570 break;
2571 case R_ARM_COPY:
2572 /*
2573 * ET_EXEC is not supported so this should not happen.
2574 *
2575 * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044d/IHI0044D_aaelf.pdf
2576 *
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002577 * Section 4.6.1.10 "Dynamic relocations"
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002578 * R_ARM_COPY may only appear in executable objects where e_type is
2579 * set to ET_EXEC.
2580 */
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002581 DL_ERR("%s R_ARM_COPY relocations are not supported", get_realpath());
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002582 return false;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002583#elif defined(__i386__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002584 case R_386_32:
2585 count_relocation(kRelocRelative);
2586 MARK(rel->r_offset);
2587 TRACE_TYPE(RELO, "RELO R_386_32 %08x <- +%08x %s", reloc, sym_addr, sym_name);
2588 *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
2589 break;
2590 case R_386_PC32:
2591 count_relocation(kRelocRelative);
2592 MARK(rel->r_offset);
2593 TRACE_TYPE(RELO, "RELO R_386_PC32 %08x <- +%08x (%08x - %08x) %s",
2594 reloc, (sym_addr - reloc), sym_addr, reloc, sym_name);
2595 *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr - reloc);
2596 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002597#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002598 default:
2599 DL_ERR("unknown reloc type %d @ %p (%zu)", type, rel, idx);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002600 return false;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002601 }
2602 }
2603 return true;
Raghu Gandhamd7daacb2012-07-31 12:07:22 -07002604}
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002605#endif // !defined(__mips__)
Raghu Gandhamd7daacb2012-07-31 12:07:22 -07002606
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002607// An empty list of soinfos
Dimitry Ivanovb943f302016-08-03 16:00:10 -07002608static soinfo_list_t g_empty_list;
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07002609
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002610bool soinfo::prelink_image() {
Ningsheng Jiane93be992014-09-16 15:22:10 +08002611 /* Extract dynamic section */
2612 ElfW(Word) dynamic_flags = 0;
2613 phdr_table_get_dynamic_section(phdr, phnum, load_bias, &dynamic, &dynamic_flags);
Dmitriy Ivanov498eb182014-09-05 14:57:59 -07002614
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002615 /* We can't log anything until the linker is relocated */
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002616 bool relocating_linker = (flags_ & FLAG_LINKER) != 0;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002617 if (!relocating_linker) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07002618 INFO("[ Linking \"%s\" ]", get_realpath());
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002619 DEBUG("si->base = %p si->flags = 0x%08x", reinterpret_cast<void*>(base), flags_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002620 }
2621
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002622 if (dynamic == nullptr) {
David 'Digit' Turnerb52e4382012-06-19 01:24:17 +02002623 if (!relocating_linker) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002624 DL_ERR("missing PT_DYNAMIC in \"%s\"", get_realpath());
David 'Digit' Turnerb52e4382012-06-19 01:24:17 +02002625 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002626 return false;
2627 } else {
2628 if (!relocating_linker) {
2629 DEBUG("dynamic = %p", dynamic);
David 'Digit' Turner63f99f42012-06-19 00:08:39 +02002630 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002631 }
David 'Digit' Turner63f99f42012-06-19 00:08:39 +02002632
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07002633#if defined(__arm__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002634 (void) phdr_table_get_arm_exidx(phdr, phnum, load_bias,
2635 &ARM_exidx, &ARM_exidx_count);
David 'Digit' Turner63f99f42012-06-19 00:08:39 +02002636#endif
2637
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002638 // Extract useful information from dynamic section.
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07002639 // Note that: "Except for the DT_NULL element at the end of the array,
2640 // and the relative order of DT_NEEDED elements, entries may appear in any order."
2641 //
2642 // source: http://www.sco.com/developers/gabi/1998-04-29/ch5.dynamic.html
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002643 uint32_t needed_count = 0;
2644 for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
2645 DEBUG("d = %p, d[0](tag) = %p d[1](val) = %p",
2646 d, reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
2647 switch (d->d_tag) {
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002648 case DT_SONAME:
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07002649 // this is parsed after we have strtab initialized (see below).
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002650 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002651
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002652 case DT_HASH:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002653 nbucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0];
2654 nchain_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
2655 bucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8);
2656 chain_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8 + nbucket_ * 4);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002657 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002658
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002659 case DT_GNU_HASH:
Dmitriy Ivanov3597b802015-03-09 12:02:02 -07002660 gnu_nbucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0];
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002661 // skip symndx
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002662 gnu_maskwords_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[2];
2663 gnu_shift2_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[3];
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002664
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002665 gnu_bloom_filter_ = reinterpret_cast<ElfW(Addr)*>(load_bias + d->d_un.d_ptr + 16);
Dmitriy Ivanov3597b802015-03-09 12:02:02 -07002666 gnu_bucket_ = reinterpret_cast<uint32_t*>(gnu_bloom_filter_ + gnu_maskwords_);
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002667 // amend chain for symndx = header[1]
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002668 gnu_chain_ = gnu_bucket_ + gnu_nbucket_ -
2669 reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002670
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002671 if (!powerof2(gnu_maskwords_)) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002672 DL_ERR("invalid maskwords for gnu_hash = 0x%x, in \"%s\" expecting power to two",
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002673 gnu_maskwords_, get_realpath());
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002674 return false;
2675 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002676 --gnu_maskwords_;
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002677
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002678 flags_ |= FLAG_GNU_HASH;
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002679 break;
2680
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002681 case DT_STRTAB:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002682 strtab_ = reinterpret_cast<const char*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002683 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002684
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07002685 case DT_STRSZ:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002686 strtab_size_ = d->d_un.d_val;
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07002687 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002688
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002689 case DT_SYMTAB:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002690 symtab_ = reinterpret_cast<ElfW(Sym)*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002691 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002692
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002693 case DT_SYMENT:
2694 if (d->d_un.d_val != sizeof(ElfW(Sym))) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002695 DL_ERR("invalid DT_SYMENT: %zd in \"%s\"",
2696 static_cast<size_t>(d->d_un.d_val), get_realpath());
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002697 return false;
2698 }
2699 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002700
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002701 case DT_PLTREL:
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002702#if defined(USE_RELA)
2703 if (d->d_un.d_val != DT_RELA) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002704 DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_RELA", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002705 return false;
2706 }
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002707#else
2708 if (d->d_un.d_val != DT_REL) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002709 DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_REL", get_realpath());
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002710 return false;
2711 }
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002712#endif
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002713 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002714
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002715 case DT_JMPREL:
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07002716#if defined(USE_RELA)
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002717 plt_rela_ = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002718#else
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002719 plt_rel_ = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002720#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002721 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002722
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002723 case DT_PLTRELSZ:
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07002724#if defined(USE_RELA)
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002725 plt_rela_count_ = d->d_un.d_val / sizeof(ElfW(Rela));
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002726#else
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002727 plt_rel_count_ = d->d_un.d_val / sizeof(ElfW(Rel));
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002728#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002729 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002730
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002731 case DT_PLTGOT:
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002732#if defined(__mips__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002733 // Used by mips and mips64.
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002734 plt_got_ = reinterpret_cast<ElfW(Addr)**>(load_bias + d->d_un.d_ptr);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002735#endif
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002736 // Ignore for other platforms... (because RTLD_LAZY is not supported)
2737 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002738
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002739 case DT_DEBUG:
2740 // Set the DT_DEBUG entry to the address of _r_debug for GDB
2741 // if the dynamic table is writable
Chris Dearman99186652014-02-06 20:36:51 -08002742// FIXME: not working currently for N64
2743// The flags for the LOAD and DYNAMIC program headers do not agree.
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002744// The LOAD section containing the dynamic table has been mapped as
Chris Dearman99186652014-02-06 20:36:51 -08002745// read-only, but the DYNAMIC header claims it is writable.
2746#if !(defined(__mips__) && defined(__LP64__))
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002747 if ((dynamic_flags & PF_W) != 0) {
2748 d->d_un.d_val = reinterpret_cast<uintptr_t>(&_r_debug);
2749 }
Chris Dearman99186652014-02-06 20:36:51 -08002750#endif
Dmitriy Ivanovc6292ea2015-02-13 16:29:50 -08002751 break;
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07002752#if defined(USE_RELA)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002753 case DT_RELA:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002754 rela_ = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002755 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002756
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002757 case DT_RELASZ:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002758 rela_count_ = d->d_un.d_val / sizeof(ElfW(Rela));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002759 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002760
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002761 case DT_ANDROID_RELA:
2762 android_relocs_ = reinterpret_cast<uint8_t*>(load_bias + d->d_un.d_ptr);
2763 break;
2764
2765 case DT_ANDROID_RELASZ:
2766 android_relocs_size_ = d->d_un.d_val;
2767 break;
2768
2769 case DT_ANDROID_REL:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002770 DL_ERR("unsupported DT_ANDROID_REL in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002771 return false;
2772
2773 case DT_ANDROID_RELSZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002774 DL_ERR("unsupported DT_ANDROID_RELSZ in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002775 return false;
2776
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002777 case DT_RELAENT:
2778 if (d->d_un.d_val != sizeof(ElfW(Rela))) {
Dmitriy Ivanovf240aa82014-09-16 23:34:20 -07002779 DL_ERR("invalid DT_RELAENT: %zd", static_cast<size_t>(d->d_un.d_val));
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002780 return false;
2781 }
2782 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002783
2784 // ignored (see DT_RELCOUNT comments for details)
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002785 case DT_RELACOUNT:
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002786 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002787
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002788 case DT_REL:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002789 DL_ERR("unsupported DT_REL in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002790 return false;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002791
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002792 case DT_RELSZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002793 DL_ERR("unsupported DT_RELSZ in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002794 return false;
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002795
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002796#else
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002797 case DT_REL:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002798 rel_ = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002799 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002800
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002801 case DT_RELSZ:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002802 rel_count_ = d->d_un.d_val / sizeof(ElfW(Rel));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002803 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002804
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002805 case DT_RELENT:
2806 if (d->d_un.d_val != sizeof(ElfW(Rel))) {
Dmitriy Ivanovf240aa82014-09-16 23:34:20 -07002807 DL_ERR("invalid DT_RELENT: %zd", static_cast<size_t>(d->d_un.d_val));
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002808 return false;
2809 }
2810 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002811
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002812 case DT_ANDROID_REL:
2813 android_relocs_ = reinterpret_cast<uint8_t*>(load_bias + d->d_un.d_ptr);
2814 break;
2815
2816 case DT_ANDROID_RELSZ:
2817 android_relocs_size_ = d->d_un.d_val;
2818 break;
2819
2820 case DT_ANDROID_RELA:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002821 DL_ERR("unsupported DT_ANDROID_RELA in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002822 return false;
2823
2824 case DT_ANDROID_RELASZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002825 DL_ERR("unsupported DT_ANDROID_RELASZ in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002826 return false;
2827
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002828 // "Indicates that all RELATIVE relocations have been concatenated together,
2829 // and specifies the RELATIVE relocation count."
2830 //
2831 // TODO: Spec also mentions that this can be used to optimize relocation process;
2832 // Not currently used by bionic linker - ignored.
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002833 case DT_RELCOUNT:
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002834 break;
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002835
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002836 case DT_RELA:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002837 DL_ERR("unsupported DT_RELA in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002838 return false;
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002839
2840 case DT_RELASZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002841 DL_ERR("unsupported DT_RELASZ in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002842 return false;
2843
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002844#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002845 case DT_INIT:
Dimitry Ivanov55437462016-07-20 15:33:07 -07002846 init_func_ = reinterpret_cast<linker_ctor_function_t>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002847 DEBUG("%s constructors (DT_INIT) found at %p", get_realpath(), init_func_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002848 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002849
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002850 case DT_FINI:
Dimitry Ivanov55437462016-07-20 15:33:07 -07002851 fini_func_ = reinterpret_cast<linker_dtor_function_t>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002852 DEBUG("%s destructors (DT_FINI) found at %p", get_realpath(), fini_func_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002853 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002854
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002855 case DT_INIT_ARRAY:
Dimitry Ivanov55437462016-07-20 15:33:07 -07002856 init_array_ = reinterpret_cast<linker_ctor_function_t*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002857 DEBUG("%s constructors (DT_INIT_ARRAY) found at %p", get_realpath(), init_array_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002858 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002859
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002860 case DT_INIT_ARRAYSZ:
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -08002861 init_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002862 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002863
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002864 case DT_FINI_ARRAY:
Dimitry Ivanov55437462016-07-20 15:33:07 -07002865 fini_array_ = reinterpret_cast<linker_dtor_function_t*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002866 DEBUG("%s destructors (DT_FINI_ARRAY) found at %p", get_realpath(), fini_array_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002867 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002868
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002869 case DT_FINI_ARRAYSZ:
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -08002870 fini_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002871 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002872
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002873 case DT_PREINIT_ARRAY:
Dimitry Ivanov55437462016-07-20 15:33:07 -07002874 preinit_array_ = reinterpret_cast<linker_ctor_function_t*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002875 DEBUG("%s constructors (DT_PREINIT_ARRAY) found at %p", get_realpath(), preinit_array_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002876 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002877
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002878 case DT_PREINIT_ARRAYSZ:
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -08002879 preinit_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002880 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002881
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002882 case DT_TEXTREL:
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00002883#if defined(__LP64__)
Dimitry Ivanov816676e2016-10-19 11:00:28 -07002884 DL_ERR("\"%s\" has text relocations", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002885 return false;
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00002886#else
2887 has_text_relocations = true;
2888 break;
2889#endif
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002890
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002891 case DT_SYMBOLIC:
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -07002892 has_DT_SYMBOLIC = true;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002893 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002894
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002895 case DT_NEEDED:
2896 ++needed_count;
2897 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002898
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002899 case DT_FLAGS:
2900 if (d->d_un.d_val & DF_TEXTREL) {
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00002901#if defined(__LP64__)
Dimitry Ivanov816676e2016-10-19 11:00:28 -07002902 DL_ERR("\"%s\" has text relocations", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002903 return false;
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00002904#else
2905 has_text_relocations = true;
2906#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002907 }
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -07002908 if (d->d_un.d_val & DF_SYMBOLIC) {
2909 has_DT_SYMBOLIC = true;
2910 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002911 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002912
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07002913 case DT_FLAGS_1:
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07002914 set_dt_flags_1(d->d_un.d_val);
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -07002915
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07002916 if ((d->d_un.d_val & ~SUPPORTED_DT_FLAGS_1) != 0) {
Dimitry Ivanov816676e2016-10-19 11:00:28 -07002917 DL_WARN("\"%s\" has unsupported flags DT_FLAGS_1=%p", get_realpath(), reinterpret_cast<void*>(d->d_un.d_val));
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07002918 }
2919 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002920#if defined(__mips__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002921 case DT_MIPS_RLD_MAP:
2922 // Set the DT_MIPS_RLD_MAP entry to the address of _r_debug for GDB.
2923 {
2924 r_debug** dp = reinterpret_cast<r_debug**>(load_bias + d->d_un.d_ptr);
2925 *dp = &_r_debug;
2926 }
2927 break;
Lazar Trsic83b44a92016-04-06 13:39:17 +02002928 case DT_MIPS_RLD_MAP_REL:
2929 // Set the DT_MIPS_RLD_MAP_REL entry to the address of _r_debug for GDB.
Raghu Gandham68815722014-12-18 19:12:19 -08002930 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002931 r_debug** dp = reinterpret_cast<r_debug**>(
2932 reinterpret_cast<ElfW(Addr)>(d) + d->d_un.d_val);
Raghu Gandham68815722014-12-18 19:12:19 -08002933 *dp = &_r_debug;
2934 }
2935 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002936
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002937 case DT_MIPS_RLD_VERSION:
2938 case DT_MIPS_FLAGS:
2939 case DT_MIPS_BASE_ADDRESS:
2940 case DT_MIPS_UNREFEXTNO:
2941 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002942
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002943 case DT_MIPS_SYMTABNO:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002944 mips_symtabno_ = d->d_un.d_val;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002945 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002946
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002947 case DT_MIPS_LOCAL_GOTNO:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002948 mips_local_gotno_ = d->d_un.d_val;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002949 break;
2950
2951 case DT_MIPS_GOTSYM:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002952 mips_gotsym_ = d->d_un.d_val;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002953 break;
2954#endif
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002955 // Ignored: "Its use has been superseded by the DF_BIND_NOW flag"
2956 case DT_BIND_NOW:
2957 break;
2958
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002959 case DT_VERSYM:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002960 versym_ = reinterpret_cast<ElfW(Versym)*>(load_bias + d->d_un.d_ptr);
2961 break;
2962
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002963 case DT_VERDEF:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002964 verdef_ptr_ = load_bias + d->d_un.d_ptr;
2965 break;
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002966 case DT_VERDEFNUM:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002967 verdef_cnt_ = d->d_un.d_val;
2968 break;
2969
Alexander Ivchenkoe8314332014-12-02 15:32:25 +03002970 case DT_VERNEED:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002971 verneed_ptr_ = load_bias + d->d_un.d_ptr;
2972 break;
2973
Alexander Ivchenkoe8314332014-12-02 15:32:25 +03002974 case DT_VERNEEDNUM:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002975 verneed_cnt_ = d->d_un.d_val;
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002976 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002977
Evgenii Stepanov68650822015-06-10 13:38:39 -07002978 case DT_RUNPATH:
2979 // this is parsed after we have strtab initialized (see below).
2980 break;
2981
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002982 default:
Dmitriy Ivanov8f61d992014-09-16 14:31:06 -07002983 if (!relocating_linker) {
Dimitry Ivanov816676e2016-10-19 11:00:28 -07002984 DL_WARN("\"%s\" unused DT entry: type %p arg %p", get_realpath(),
Dmitriy Ivanov8f61d992014-09-16 14:31:06 -07002985 reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
2986 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002987 break;
Brian Carlstromd4ee82d2013-02-28 15:58:45 -08002988 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002989 }
2990
Duane Sandbc425c72015-06-01 16:29:14 -07002991#if defined(__mips__) && !defined(__LP64__)
2992 if (!mips_check_and_adjust_fp_modes()) {
2993 return false;
2994 }
2995#endif
2996
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002997 DEBUG("si->base = %p, si->strtab = %p, si->symtab = %p",
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002998 reinterpret_cast<void*>(base), strtab_, symtab_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002999
3000 // Sanity checks.
3001 if (relocating_linker && needed_count != 0) {
3002 DL_ERR("linker cannot have DT_NEEDED dependencies on other libraries");
3003 return false;
3004 }
Dmitriy Ivanov3597b802015-03-09 12:02:02 -07003005 if (nbucket_ == 0 && gnu_nbucket_ == 0) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003006 DL_ERR("empty/missing DT_HASH/DT_GNU_HASH in \"%s\" "
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003007 "(new hash type from the future?)", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003008 return false;
3009 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003010 if (strtab_ == 0) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003011 DL_ERR("empty/missing DT_STRTAB in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003012 return false;
3013 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003014 if (symtab_ == 0) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003015 DL_ERR("empty/missing DT_SYMTAB in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003016 return false;
3017 }
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003018
Dmitriy Ivanov624b8f12015-06-08 10:41:33 -07003019 // second pass - parse entries relying on strtab
3020 for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
Evgenii Stepanov68650822015-06-10 13:38:39 -07003021 switch (d->d_tag) {
3022 case DT_SONAME:
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07003023 set_soname(get_string(d->d_un.d_val));
Evgenii Stepanov68650822015-06-10 13:38:39 -07003024 break;
3025 case DT_RUNPATH:
Evgenii Stepanov68650822015-06-10 13:38:39 -07003026 set_dt_runpath(get_string(d->d_un.d_val));
3027 break;
Dmitriy Ivanov624b8f12015-06-08 10:41:33 -07003028 }
3029 }
3030
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003031 // Before M release linker was using basename in place of soname.
Dmitriy Ivanov19133522015-06-02 17:36:54 -07003032 // In the case when dt_soname is absent some apps stop working
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003033 // because they can't find dt_needed library by soname.
3034 // This workaround should keep them working. (applies only
Elliott Hughes5bc78c82016-11-16 11:35:43 -08003035 // for apps targeting sdk version < M). Make an exception for
Dmitriy Ivanov19133522015-06-02 17:36:54 -07003036 // the main executable and linker; they do not need to have dt_soname
Dimitry Ivanov3f660572016-09-09 10:00:39 -07003037 if (soname_ == nullptr &&
3038 this != solist_get_somain() &&
3039 (flags_ & FLAG_LINKER) == 0 &&
Elliott Hughes5bc78c82016-11-16 11:35:43 -08003040 get_application_target_sdk_version() < __ANDROID_API_M__) {
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003041 soname_ = basename(realpath_.c_str());
3042 DL_WARN("%s: is missing DT_SONAME will use basename as a replacement: \"%s\"",
3043 get_realpath(), soname_);
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07003044 // 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 -07003045 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003046 return true;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07003047}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003048
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003049bool soinfo::link_image(const soinfo_list_t& global_group, const soinfo_list_t& local_group,
3050 const android_dlextinfo* extinfo) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003051
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08003052 local_group_root_ = local_group.front();
3053 if (local_group_root_ == nullptr) {
3054 local_group_root_ = this;
3055 }
3056
Dmitriy Ivanov19133522015-06-02 17:36:54 -07003057 if ((flags_ & FLAG_LINKER) == 0 && local_group_root_ == this) {
3058 target_sdk_version_ = get_application_target_sdk_version();
3059 }
3060
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003061 VersionTracker version_tracker;
3062
3063 if (!version_tracker.init(this)) {
3064 return false;
3065 }
3066
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003067#if !defined(__LP64__)
3068 if (has_text_relocations) {
Elliott Hughes5bc78c82016-11-16 11:35:43 -08003069 // Fail if app is targeting M or above.
3070 if (get_application_target_sdk_version() >= __ANDROID_API_M__) {
Dimitry Ivanov816676e2016-10-19 11:00:28 -07003071 DL_ERR_AND_LOG("\"%s\" has text relocations", get_realpath());
Dmitriy Ivanove4ad91f2015-06-12 15:00:31 -07003072 return false;
3073 }
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003074 // Make segments writable to allow text relocations to work properly. We will later call
Dmitriy Ivanov7e039932015-10-01 14:02:19 -07003075 // phdr_table_protect_segments() after all of them are applied.
Dimitry Ivanov816676e2016-10-19 11:00:28 -07003076 DL_WARN("\"%s\" has text relocations. This is wasting memory and prevents "
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003077 "security hardening. Please fix.", get_realpath());
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07003078 add_dlwarning(get_realpath(), "text relocations");
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003079 if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
3080 DL_ERR("can't unprotect loadable segments for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003081 get_realpath(), strerror(errno));
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003082 return false;
3083 }
3084 }
3085#endif
3086
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003087 if (android_relocs_ != nullptr) {
3088 // check signature
3089 if (android_relocs_size_ > 3 &&
3090 android_relocs_[0] == 'A' &&
3091 android_relocs_[1] == 'P' &&
Dmitriy Ivanov18870d32015-04-22 13:10:04 -07003092 android_relocs_[2] == 'S' &&
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003093 android_relocs_[3] == '2') {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003094 DEBUG("[ android relocating %s ]", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003095
3096 bool relocated = false;
3097 const uint8_t* packed_relocs = android_relocs_ + 4;
3098 const size_t packed_relocs_size = android_relocs_size_ - 4;
3099
Dmitriy Ivanov18870d32015-04-22 13:10:04 -07003100 relocated = relocate(
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003101 version_tracker,
Dmitriy Ivanov18870d32015-04-22 13:10:04 -07003102 packed_reloc_iterator<sleb128_decoder>(
3103 sleb128_decoder(packed_relocs, packed_relocs_size)),
3104 global_group, local_group);
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003105
3106 if (!relocated) {
3107 return false;
3108 }
3109 } else {
3110 DL_ERR("bad android relocation header.");
3111 return false;
3112 }
3113 }
3114
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07003115#if defined(USE_RELA)
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003116 if (rela_ != nullptr) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003117 DEBUG("[ relocating %s ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003118 if (!relocate(version_tracker,
3119 plain_reloc_iterator(rela_, rela_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003120 return false;
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07003121 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003122 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003123 if (plt_rela_ != nullptr) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003124 DEBUG("[ relocating %s plt ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003125 if (!relocate(version_tracker,
3126 plain_reloc_iterator(plt_rela_, plt_rela_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003127 return false;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003128 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003129 }
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07003130#else
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003131 if (rel_ != nullptr) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003132 DEBUG("[ relocating %s ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003133 if (!relocate(version_tracker,
3134 plain_reloc_iterator(rel_, rel_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003135 return false;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003136 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003137 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003138 if (plt_rel_ != nullptr) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003139 DEBUG("[ relocating %s plt ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003140 if (!relocate(version_tracker,
3141 plain_reloc_iterator(plt_rel_, plt_rel_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003142 return false;
Brigid Smithc5a13ef2014-07-23 11:22:25 -07003143 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003144 }
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07003145#endif
Brigid Smithc5a13ef2014-07-23 11:22:25 -07003146
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07003147#if defined(__mips__)
Dmitriy Ivanovf39cb632015-04-30 20:17:03 -07003148 if (!mips_relocate_got(version_tracker, global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003149 return false;
3150 }
Raghu Gandhamd7daacb2012-07-31 12:07:22 -07003151#endif
3152
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003153 DEBUG("[ finished linking %s ]", get_realpath());
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003154
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003155#if !defined(__LP64__)
3156 if (has_text_relocations) {
3157 // All relocations are done, we can protect our segments back to read-only.
3158 if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
3159 DL_ERR("can't protect segments for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003160 get_realpath(), strerror(errno));
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003161 return false;
3162 }
3163 }
3164#endif
3165
Mingwei Shibe910522015-11-12 07:02:14 +00003166 // We can also turn on GNU RELRO protection if we're not linking the dynamic linker
3167 // itself --- it can't make system calls yet, and will have to call protect_relro later.
3168 if (!is_linker() && !protect_relro()) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003169 return false;
3170 }
Nick Kralevich9ec0f032012-02-28 10:40:00 -08003171
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003172 /* Handle serializing/sharing the RELRO segment */
3173 if (extinfo && (extinfo->flags & ANDROID_DLEXT_WRITE_RELRO)) {
3174 if (phdr_table_serialize_gnu_relro(phdr, phnum, load_bias,
3175 extinfo->relro_fd) < 0) {
3176 DL_ERR("failed serializing GNU RELRO section for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003177 get_realpath(), strerror(errno));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003178 return false;
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +00003179 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003180 } else if (extinfo && (extinfo->flags & ANDROID_DLEXT_USE_RELRO)) {
3181 if (phdr_table_map_gnu_relro(phdr, phnum, load_bias,
3182 extinfo->relro_fd) < 0) {
3183 DL_ERR("failed mapping GNU RELRO section for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003184 get_realpath(), strerror(errno));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003185 return false;
3186 }
3187 }
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +00003188
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003189 notify_gdb_of_load(this);
3190 return true;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003191}
3192
Mingwei Shibe910522015-11-12 07:02:14 +00003193bool soinfo::protect_relro() {
3194 if (phdr_table_protect_gnu_relro(phdr, phnum, load_bias) < 0) {
3195 DL_ERR("can't enable GNU RELRO protection for \"%s\": %s",
3196 get_realpath(), strerror(errno));
3197 return false;
3198 }
3199 return true;
3200}
3201
Dimitry Ivanov3f660572016-09-09 10:00:39 -07003202void init_default_namespace() {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003203 g_default_namespace.set_name("(default)");
3204 g_default_namespace.set_isolated(false);
3205
Dimitry Ivanov3f660572016-09-09 10:00:39 -07003206 soinfo* somain = solist_get_somain();
3207
Evgenii Stepanovd640b222015-07-10 17:54:01 -07003208 const char *interp = phdr_table_get_interpreter_name(somain->phdr, somain->phnum,
3209 somain->load_bias);
3210 const char* bname = basename(interp);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003211 if (bname && (strcmp(bname, "linker_asan") == 0 || strcmp(bname, "linker_asan64") == 0)) {
Evgenii Stepanovd640b222015-07-10 17:54:01 -07003212 g_default_ld_paths = kAsanDefaultLdPaths;
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -07003213 g_is_asan = true;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003214 } else {
Evgenii Stepanovd640b222015-07-10 17:54:01 -07003215 g_default_ld_paths = kDefaultLdPaths;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003216 }
3217
neo.chae2589f9d2016-10-04 11:00:27 +09003218 char real_path[PATH_MAX];
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003219 std::vector<std::string> ld_default_paths;
3220 for (size_t i = 0; g_default_ld_paths[i] != nullptr; ++i) {
neo.chae2589f9d2016-10-04 11:00:27 +09003221 if (realpath(g_default_ld_paths[i], real_path) != nullptr) {
3222 ld_default_paths.push_back(real_path);
3223 } else {
3224 ld_default_paths.push_back(g_default_ld_paths[i]);
3225 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003226 }
3227
3228 g_default_namespace.set_default_library_paths(std::move(ld_default_paths));
Evgenii Stepanovd640b222015-07-10 17:54:01 -07003229};