blob: fab64bc1c86e45d418c182c8a50a2d6d5a5dc5f0 [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
157 // limit greylisting to apps targeting sdk version 23 and below
158 if (get_application_target_sdk_version() > 23) {
159 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, ...)
779 // if the library is opened by application with target api level <= 22
780 // See http://b/21565766
781 if ((si->get_rtld_flags() & RTLD_GLOBAL) == 0 && si->get_target_sdk_version() > 22) {
Dmitriy Ivanove8ba50f2014-09-15 17:00:10 -0700782 continue;
783 }
784
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800785 if (!si->find_symbol_by_name(symbol_name, vi, &s)) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700786 return nullptr;
787 }
788
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700789 if (s != nullptr) {
Elliott Hughescade4c32012-12-20 14:42:14 -0800790 *found = si;
791 break;
Matt Fischer1698d9e2009-12-31 12:17:56 -0600792 }
Elliott Hughescade4c32012-12-20 14:42:14 -0800793 }
Matt Fischer1698d9e2009-12-31 12:17:56 -0600794
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700795 // If not found - use dlsym_handle_lookup for caller's
796 // local_group unless it is part of the global group in which
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -0700797 // case we already did it.
798 if (s == nullptr && caller != nullptr &&
799 (caller->get_rtld_flags() & RTLD_GLOBAL) == 0) {
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700800 return dlsym_handle_lookup(caller->get_local_group_root(),
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800801 (handle == RTLD_NEXT) ? caller : nullptr, found, symbol_name, vi);
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -0700802 }
803
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700804 if (s != nullptr) {
Elliott Hughesc00f2cb2013-10-04 17:01:33 -0700805 TRACE_TYPE(LOOKUP, "%s s->st_value = %p, found->base = %p",
806 name, reinterpret_cast<void*>(s->st_value), reinterpret_cast<void*>((*found)->base));
Elliott Hughescade4c32012-12-20 14:42:14 -0800807 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800808
Elliott Hughescade4c32012-12-20 14:42:14 -0800809 return s;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800810}
811
Kito Chengfa8c05d2013-03-12 14:58:06 +0800812soinfo* find_containing_library(const void* p) {
Elliott Hughes0266ae52014-02-10 17:46:57 -0800813 ElfW(Addr) address = reinterpret_cast<ElfW(Addr)>(p);
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700814 for (soinfo* si = solist_get_head(); si != nullptr; si = si->next) {
Kito Chengfa8c05d2013-03-12 14:58:06 +0800815 if (address >= si->base && address - si->base < si->size) {
816 return si;
Matt Fischere2a8b1f2009-12-31 12:17:40 -0600817 }
Kito Chengfa8c05d2013-03-12 14:58:06 +0800818 }
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700819 return nullptr;
Matt Fischere2a8b1f2009-12-31 12:17:40 -0600820}
821
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700822class ZipArchiveCache {
823 public:
824 ZipArchiveCache() {}
825 ~ZipArchiveCache();
826
827 bool get_or_open(const char* zip_path, ZipArchiveHandle* handle);
828 private:
829 DISALLOW_COPY_AND_ASSIGN(ZipArchiveCache);
830
831 std::unordered_map<std::string, ZipArchiveHandle> cache_;
832};
833
834bool ZipArchiveCache::get_or_open(const char* zip_path, ZipArchiveHandle* handle) {
835 std::string key(zip_path);
836
837 auto it = cache_.find(key);
838 if (it != cache_.end()) {
839 *handle = it->second;
840 return true;
841 }
842
843 int fd = TEMP_FAILURE_RETRY(open(zip_path, O_RDONLY | O_CLOEXEC));
844 if (fd == -1) {
845 return false;
846 }
847
848 if (OpenArchiveFd(fd, "", handle) != 0) {
849 // invalid zip-file (?)
Yabin Cui722072d2016-03-21 17:10:12 -0700850 CloseArchive(handle);
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700851 close(fd);
852 return false;
853 }
854
855 cache_[key] = *handle;
856 return true;
857}
858
859ZipArchiveCache::~ZipArchiveCache() {
Dmitriy Ivanov5dce8942015-10-13 12:14:16 -0700860 for (const auto& it : cache_) {
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700861 CloseArchive(it.second);
862 }
863}
864
865static int open_library_in_zipfile(ZipArchiveCache* zip_archive_cache,
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700866 const char* const input_path,
867 off64_t* file_offset, std::string* realpath) {
868 std::string normalized_path;
869 if (!normalize_path(input_path, &normalized_path)) {
870 return -1;
871 }
872
873 const char* const path = normalized_path.c_str();
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700874 TRACE("Trying zip file open from path \"%s\" -> normalized \"%s\"", input_path, path);
Simon Baldwinaef71952015-01-16 13:22:54 +0000875
Dmitriy Ivanov402a7502015-06-09 13:46:51 -0700876 // Treat an '!/' separator inside a path as the separator between the name
Simon Baldwinaef71952015-01-16 13:22:54 +0000877 // of the zip file on disk and the subdirectory to search within it.
Dmitriy Ivanov402a7502015-06-09 13:46:51 -0700878 // For example, if path is "foo.zip!/bar/bas/x.so", then we search for
Simon Baldwinaef71952015-01-16 13:22:54 +0000879 // "bar/bas/x.so" within "foo.zip".
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700880 const char* const separator = strstr(path, kZipFileSeparator);
Simon Baldwinaef71952015-01-16 13:22:54 +0000881 if (separator == nullptr) {
882 return -1;
Elliott Hughes124fae92012-10-31 14:20:03 -0700883 }
Simon Baldwinaef71952015-01-16 13:22:54 +0000884
885 char buf[512];
886 if (strlcpy(buf, path, sizeof(buf)) >= sizeof(buf)) {
887 PRINT("Warning: ignoring very long library path: %s", path);
888 return -1;
889 }
890
891 buf[separator - path] = '\0';
892
893 const char* zip_path = buf;
Dmitriy Ivanov402a7502015-06-09 13:46:51 -0700894 const char* file_path = &buf[separator - path + 2];
Simon Baldwinaef71952015-01-16 13:22:54 +0000895 int fd = TEMP_FAILURE_RETRY(open(zip_path, O_RDONLY | O_CLOEXEC));
896 if (fd == -1) {
897 return -1;
898 }
899
900 ZipArchiveHandle handle;
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700901 if (!zip_archive_cache->get_or_open(zip_path, &handle)) {
Simon Baldwinaef71952015-01-16 13:22:54 +0000902 // invalid zip-file (?)
903 close(fd);
904 return -1;
905 }
906
Simon Baldwinaef71952015-01-16 13:22:54 +0000907 ZipEntry entry;
908
Yusuke Sato56f40fb2015-06-25 14:56:07 -0700909 if (FindEntry(handle, ZipString(file_path), &entry) != 0) {
Simon Baldwinaef71952015-01-16 13:22:54 +0000910 // Entry was not found.
911 close(fd);
912 return -1;
913 }
914
915 // Check if it is properly stored
916 if (entry.method != kCompressStored || (entry.offset % PAGE_SIZE) != 0) {
917 close(fd);
918 return -1;
919 }
920
921 *file_offset = entry.offset;
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700922
923 if (realpath_fd(fd, realpath)) {
924 *realpath += separator;
925 } else {
926 PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.",
927 normalized_path.c_str());
928 *realpath = normalized_path;
929 }
930
Simon Baldwinaef71952015-01-16 13:22:54 +0000931 return fd;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800932}
933
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700934static bool format_path(char* buf, size_t buf_size, const char* path, const char* name) {
935 int n = __libc_format_buffer(buf, buf_size, "%s/%s", path, name);
936 if (n < 0 || n >= static_cast<int>(buf_size)) {
937 PRINT("Warning: ignoring very long library path: %s/%s", path, name);
938 return false;
939 }
Simon Baldwinaef71952015-01-16 13:22:54 +0000940
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700941 return true;
942}
943
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700944static int open_library_on_paths(ZipArchiveCache* zip_archive_cache,
945 const char* name, off64_t* file_offset,
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700946 const std::vector<std::string>& paths,
947 std::string* realpath) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700948 for (const auto& path : paths) {
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700949 char buf[512];
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700950 if (!format_path(buf, sizeof(buf), path.c_str(), name)) {
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700951 continue;
952 }
953
954 int fd = -1;
Dmitriy Ivanov730ed9d2015-07-16 04:52:06 -0700955 if (strstr(buf, kZipFileSeparator) != nullptr) {
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700956 fd = open_library_in_zipfile(zip_archive_cache, buf, file_offset, realpath);
Simon Baldwinaef71952015-01-16 13:22:54 +0000957 }
958
959 if (fd == -1) {
960 fd = TEMP_FAILURE_RETRY(open(buf, O_RDONLY | O_CLOEXEC));
961 if (fd != -1) {
962 *file_offset = 0;
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700963 if (!realpath_fd(fd, realpath)) {
964 PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.", buf);
965 *realpath = buf;
966 }
Simon Baldwinaef71952015-01-16 13:22:54 +0000967 }
968 }
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700969
970 if (fd != -1) {
971 return fd;
972 }
Simon Baldwinaef71952015-01-16 13:22:54 +0000973 }
974
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700975 return -1;
Simon Baldwinaef71952015-01-16 13:22:54 +0000976}
977
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700978static int open_library(android_namespace_t* ns,
979 ZipArchiveCache* zip_archive_cache,
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700980 const char* name, soinfo *needed_by,
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700981 off64_t* file_offset, std::string* realpath) {
Elliott Hughesca0c11b2013-03-12 10:40:45 -0700982 TRACE("[ opening %s ]", name);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800983
Elliott Hughes124fae92012-10-31 14:20:03 -0700984 // 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 -0700985 if (strchr(name, '/') != nullptr) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700986 int fd = -1;
987
Dmitriy Ivanov730ed9d2015-07-16 04:52:06 -0700988 if (strstr(name, kZipFileSeparator) != nullptr) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700989 fd = open_library_in_zipfile(zip_archive_cache, name, file_offset, realpath);
990 }
991
992 if (fd == -1) {
993 fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_CLOEXEC));
Simon Baldwinaef71952015-01-16 13:22:54 +0000994 if (fd != -1) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700995 *file_offset = 0;
996 if (!realpath_fd(fd, realpath)) {
997 PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.", name);
998 *realpath = name;
999 }
Simon Baldwinaef71952015-01-16 13:22:54 +00001000 }
1001 }
1002
Dmitriy Ivanove44fffd2015-03-17 17:12:18 -07001003 return fd;
Elliott Hughes124fae92012-10-31 14:20:03 -07001004 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001005
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001006 // Otherwise we try LD_LIBRARY_PATH first, and fall back to the default library path
1007 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 -07001008 if (fd == -1 && needed_by != nullptr) {
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001009 fd = open_library_on_paths(zip_archive_cache, name, file_offset, needed_by->get_dt_runpath(), realpath);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001010 // Check if the library is accessible
1011 if (fd != -1 && !ns->is_accessible(*realpath)) {
1012 fd = -1;
1013 }
Evgenii Stepanov68650822015-06-10 13:38:39 -07001014 }
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001015
Elliott Hughes124fae92012-10-31 14:20:03 -07001016 if (fd == -1) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001017 fd = open_library_on_paths(zip_archive_cache, name, file_offset, ns->get_default_library_paths(), realpath);
Elliott Hughes124fae92012-10-31 14:20:03 -07001018 }
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001019
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001020 // TODO(dimitry): workaround for http://b/26394120 (the grey-list)
1021 if (fd == -1 && ns != &g_default_namespace && is_greylisted(name, needed_by)) {
1022 // try searching for it on default_namespace default_library_path
1023 fd = open_library_on_paths(zip_archive_cache, name, file_offset,
1024 g_default_namespace.get_default_library_paths(), realpath);
1025 }
1026 // END OF WORKAROUND
1027
Elliott Hughes124fae92012-10-31 14:20:03 -07001028 return fd;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001029}
1030
Dimitry Ivanov3f660572016-09-09 10:00:39 -07001031const char* fix_dt_needed(const char* dt_needed, const char* sopath __unused) {
Dmitriy Ivanovd974e882015-05-27 18:29:41 -07001032#if !defined(__LP64__)
1033 // Work around incorrect DT_NEEDED entries for old apps: http://b/21364029
Dmitriy Ivanov19133522015-06-02 17:36:54 -07001034 if (get_application_target_sdk_version() <= 22) {
Dmitriy Ivanovd974e882015-05-27 18:29:41 -07001035 const char* bname = basename(dt_needed);
1036 if (bname != dt_needed) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001037 DL_WARN("library \"%s\" has invalid DT_NEEDED entry \"%s\"", sopath, dt_needed);
1038 add_dlwarning(sopath, "invalid DT_NEEDED entry", dt_needed);
Dmitriy Ivanovd974e882015-05-27 18:29:41 -07001039 }
1040
1041 return bname;
1042 }
1043#endif
1044 return dt_needed;
1045}
1046
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001047template<typename F>
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001048static void for_each_dt_needed(const ElfReader& elf_reader, F action) {
1049 for (const ElfW(Dyn)* d = elf_reader.dynamic(); d->d_tag != DT_NULL; ++d) {
1050 if (d->d_tag == DT_NEEDED) {
1051 action(fix_dt_needed(elf_reader.get_string(d->d_un.d_val), elf_reader.name()));
1052 }
1053 }
1054}
1055
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001056static bool load_library(android_namespace_t* ns,
1057 LoadTask* task,
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001058 LoadTaskList* load_tasks,
1059 int rtld_flags,
1060 const std::string& realpath) {
1061 off64_t file_offset = task->get_file_offset();
1062 const char* name = task->get_name();
1063 const android_dlextinfo* extinfo = task->get_extinfo();
1064
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001065 if ((file_offset % PAGE_SIZE) != 0) {
Dmitriy Ivanova6c12792014-10-21 12:09:18 -07001066 DL_ERR("file offset for the library \"%s\" is not page-aligned: %" PRId64, name, file_offset);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001067 return false;
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001068 }
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001069 if (file_offset < 0) {
1070 DL_ERR("file offset for the library \"%s\" is negative: %" PRId64, name, file_offset);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001071 return false;
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001072 }
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001073
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001074 struct stat file_stat;
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001075 if (TEMP_FAILURE_RETRY(fstat(task->get_fd(), &file_stat)) != 0) {
Dmitriy Ivanova6c12792014-10-21 12:09:18 -07001076 DL_ERR("unable to stat file for the library \"%s\": %s", name, strerror(errno));
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001077 return false;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001078 }
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001079 if (file_offset >= file_stat.st_size) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07001080 DL_ERR("file offset for the library \"%s\" >= file size: %" PRId64 " >= %" PRId64,
1081 name, file_offset, file_stat.st_size);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001082 return false;
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001083 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001084
1085 // Check for symlink and other situations where
Dmitriy Ivanov9b821362015-04-02 16:03:56 -07001086 // file can have different names, unless ANDROID_DLEXT_FORCE_LOAD is set
1087 if (extinfo == nullptr || (extinfo->flags & ANDROID_DLEXT_FORCE_LOAD) == 0) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001088 auto predicate = [&](soinfo* si) {
1089 return si->get_st_dev() != 0 &&
1090 si->get_st_ino() != 0 &&
1091 si->get_st_dev() == file_stat.st_dev &&
1092 si->get_st_ino() == file_stat.st_ino &&
1093 si->get_file_offset() == file_offset;
1094 };
1095
1096 soinfo* si = ns->soinfo_list().find_if(predicate);
1097
1098 // check public namespace
1099 if (si == nullptr) {
1100 si = g_public_namespace.find_if(predicate);
1101 if (si != nullptr) {
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001102 ns->add_soinfo(si);
Dmitriy Ivanov9b821362015-04-02 16:03:56 -07001103 }
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07001104 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001105
1106 if (si != nullptr) {
1107 TRACE("library \"%s\" is already loaded under different name/path \"%s\" - "
1108 "will return existing soinfo", name, si->get_realpath());
1109 task->set_soinfo(si);
1110 return true;
1111 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001112 }
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07001113
Dmitriy Ivanove8ba50f2014-09-15 17:00:10 -07001114 if ((rtld_flags & RTLD_NOLOAD) != 0) {
Dmitriy Ivanova6ac54a2014-09-09 10:21:42 -07001115 DL_ERR("library \"%s\" wasn't loaded and RTLD_NOLOAD prevented it", name);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001116 return false;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001117 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001118
Dimitry Ivanov22840aa2015-12-04 18:28:49 -08001119 if (!ns->is_accessible(realpath)) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001120 // TODO(dimitry): workaround for http://b/26394120 - the grey-list
1121 const soinfo* needed_by = task->is_dt_needed() ? task->get_needed_by() : nullptr;
1122 if (is_greylisted(name, needed_by)) {
1123 // print warning only if needed by non-system library
1124 if (needed_by == nullptr || !is_system_library(needed_by->get_realpath())) {
1125 const soinfo* needed_or_dlopened_by = task->get_needed_by();
1126 const char* sopath = needed_or_dlopened_by == nullptr ? "(unknown)" :
1127 needed_or_dlopened_by->get_realpath();
1128 DL_WARN("library \"%s\" (\"%s\") needed or dlopened by \"%s\" is not accessible for the namespace \"%s\""
1129 " - the access is temporarily granted as a workaround for http://b/26394120, note that the access"
1130 " will be removed in future releases of Android.",
1131 name, realpath.c_str(), sopath, ns->get_name());
1132 add_dlwarning(sopath, "unauthorized access to", name);
1133 }
1134 } else {
1135 // do not load libraries if they are not accessible for the specified namespace.
1136 const char* needed_or_dlopened_by = task->get_needed_by() == nullptr ?
1137 "(unknown)" :
1138 task->get_needed_by()->get_realpath();
Dimitry Ivanovd17a3772016-03-01 13:11:28 -08001139
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001140 DL_ERR("library \"%s\" needed or dlopened by \"%s\" is not accessible for the namespace \"%s\"",
1141 name, needed_or_dlopened_by, ns->get_name());
Dimitry Ivanovd17a3772016-03-01 13:11:28 -08001142
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001143 PRINT("library \"%s\" (\"%s\") needed or dlopened by \"%s\" is not accessible for the"
1144 " namespace: [name=\"%s\", ld_library_paths=\"%s\", default_library_paths=\"%s\","
1145 " permitted_paths=\"%s\"]",
1146 name, realpath.c_str(),
1147 needed_or_dlopened_by,
1148 ns->get_name(),
1149 android::base::Join(ns->get_ld_library_paths(), ':').c_str(),
1150 android::base::Join(ns->get_default_library_paths(), ':').c_str(),
1151 android::base::Join(ns->get_permitted_paths(), ':').c_str());
1152 return false;
1153 }
Dimitry Ivanov22840aa2015-12-04 18:28:49 -08001154 }
1155
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001156 soinfo* si = soinfo_alloc(ns, realpath.c_str(), &file_stat, file_offset, rtld_flags);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001157 if (si == nullptr) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001158 return false;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001159 }
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07001160
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001161 task->set_soinfo(si);
1162
1163 // Read the ELF header and some of the segments.
1164 if (!task->read(realpath.c_str(), file_stat.st_size)) {
Dmitriy Ivanovfd7a91e2015-11-06 10:44:37 -08001165 soinfo_free(si);
1166 task->set_soinfo(nullptr);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001167 return false;
1168 }
1169
1170 // find and set DT_RUNPATH and dt_soname
1171 // Note that these field values are temporary and are
1172 // going to be overwritten on soinfo::prelink_image
1173 // with values from PT_LOAD segments.
1174 const ElfReader& elf_reader = task->get_elf_reader();
1175 for (const ElfW(Dyn)* d = elf_reader.dynamic(); d->d_tag != DT_NULL; ++d) {
1176 if (d->d_tag == DT_RUNPATH) {
1177 si->set_dt_runpath(elf_reader.get_string(d->d_un.d_val));
1178 }
1179 if (d->d_tag == DT_SONAME) {
1180 si->set_soname(elf_reader.get_string(d->d_un.d_val));
1181 }
1182 }
1183
1184 for_each_dt_needed(task->get_elf_reader(), [&](const char* name) {
1185 load_tasks->push_back(LoadTask::create(name, si, task->get_readers_map()));
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001186 });
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07001187
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001188 return true;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001189}
1190
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001191static bool load_library(android_namespace_t* ns,
1192 LoadTask* task,
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001193 ZipArchiveCache* zip_archive_cache,
1194 LoadTaskList* load_tasks,
1195 int rtld_flags) {
1196 const char* name = task->get_name();
1197 soinfo* needed_by = task->get_needed_by();
1198 const android_dlextinfo* extinfo = task->get_extinfo();
1199
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001200 off64_t file_offset;
1201 std::string realpath;
Spencer Low0346ad72015-04-22 18:06:51 -07001202 if (extinfo != nullptr && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) {
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001203 file_offset = 0;
Spencer Low0346ad72015-04-22 18:06:51 -07001204 if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
1205 file_offset = extinfo->library_fd_offset;
1206 }
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001207
1208 if (!realpath_fd(extinfo->library_fd, &realpath)) {
1209 PRINT("warning: unable to get realpath for the library \"%s\" by extinfo->library_fd. "
1210 "Will use given name.", name);
1211 realpath = name;
1212 }
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001213
1214 task->set_fd(extinfo->library_fd, false);
1215 task->set_file_offset(file_offset);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001216 return load_library(ns, task, load_tasks, rtld_flags, realpath);
Spencer Low0346ad72015-04-22 18:06:51 -07001217 }
1218
1219 // Open the file.
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001220 int fd = open_library(ns, zip_archive_cache, name, needed_by, &file_offset, &realpath);
Spencer Low0346ad72015-04-22 18:06:51 -07001221 if (fd == -1) {
1222 DL_ERR("library \"%s\" not found", name);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001223 return false;
Spencer Low0346ad72015-04-22 18:06:51 -07001224 }
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001225
1226 task->set_fd(fd, true);
1227 task->set_file_offset(file_offset);
1228
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001229 return load_library(ns, task, load_tasks, rtld_flags, realpath);
Spencer Low0346ad72015-04-22 18:06:51 -07001230}
1231
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001232// Returns true if library was found and false in 2 cases
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001233// 1. (for default namespace only) The library was found but loaded under different
1234// target_sdk_version (*candidate != nullptr)
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001235// 2. The library was not found by soname (*candidate is nullptr)
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001236static bool find_loaded_library_by_soname(android_namespace_t* ns,
1237 const char* name, soinfo** candidate) {
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001238 *candidate = nullptr;
1239
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07001240 // Ignore filename with path.
1241 if (strchr(name, '/') != nullptr) {
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001242 return false;
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07001243 }
1244
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001245 uint32_t target_sdk_version = get_application_target_sdk_version();
1246
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001247 return !ns->soinfo_list().visit([&](soinfo* si) {
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07001248 const char* soname = si->get_soname();
1249 if (soname != nullptr && (strcmp(name, soname) == 0)) {
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001250 // If the library was opened under different target sdk version
1251 // skip this step and try to reopen it. The exceptions are
1252 // "libdl.so" and global group. There is no point in skipping
1253 // them because relocation process is going to use them
1254 // in any case.
Dimitry Ivanov3f660572016-09-09 10:00:39 -07001255
1256 // TODO (dimitry): remove this once linker stops imposing as libdl.so
1257 bool is_libdl = (si == solist_get_head());
1258
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001259 if (is_libdl || (si->get_dt_flags_1() & DF_1_GLOBAL) != 0 ||
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001260 !si->is_linked() || si->get_target_sdk_version() == target_sdk_version ||
1261 ns != &g_default_namespace) {
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001262 *candidate = si;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001263 return false;
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001264 } else if (*candidate == nullptr) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001265 // for the different sdk version in the default namespace
1266 // remember the first library.
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001267 *candidate = si;
1268 }
Ard Biesheuvel12c78bb2012-08-14 12:30:09 +02001269 }
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001270
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001271 return true;
1272 });
Ard Biesheuvel12c78bb2012-08-14 12:30:09 +02001273}
1274
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001275static bool find_library_internal(android_namespace_t* ns,
1276 LoadTask* task,
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001277 ZipArchiveCache* zip_archive_cache,
1278 LoadTaskList* load_tasks,
1279 int rtld_flags) {
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001280 soinfo* candidate;
1281
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001282 if (find_loaded_library_by_soname(ns, task->get_name(), &candidate)) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001283 task->set_soinfo(candidate);
1284 return true;
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001285 }
Dmitriy Ivanovb648a8a2014-05-19 15:06:58 -07001286
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001287 if (ns != &g_default_namespace) {
1288 // check public namespace
1289 candidate = g_public_namespace.find_if([&](soinfo* si) {
1290 return strcmp(task->get_name(), si->get_soname()) == 0;
1291 });
1292
1293 if (candidate != nullptr) {
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001294 ns->add_soinfo(candidate);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001295 task->set_soinfo(candidate);
1296 return true;
1297 }
1298 }
1299
Dmitriy Ivanovb648a8a2014-05-19 15:06:58 -07001300 // Library might still be loaded, the accurate detection
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001301 // of this fact is done by load_library.
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001302 TRACE("[ \"%s\" find_loaded_library_by_soname failed (*candidate=%s@%p). Trying harder...]",
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001303 task->get_name(), candidate == nullptr ? "n/a" : candidate->get_realpath(), candidate);
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001304
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001305 if (load_library(ns, task, zip_archive_cache, load_tasks, rtld_flags)) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001306 return true;
1307 } else {
1308 // In case we were unable to load the library but there
1309 // is a candidate loaded under the same soname but different
1310 // sdk level - return it anyways.
1311 if (candidate != nullptr) {
1312 task->set_soinfo(candidate);
1313 return true;
1314 }
Elliott Hughesd23736e2012-11-01 15:16:56 -07001315 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001316
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001317 return false;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001318}
1319
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001320static void soinfo_unload(soinfo* si);
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001321static void soinfo_unload(soinfo* soinfos[], size_t count);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001322
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001323// TODO: this is slightly unusual way to construct
1324// the global group for relocation. Not every RTLD_GLOBAL
1325// library is included in this group for backwards-compatibility
1326// reasons.
1327//
1328// This group consists of the main executable, LD_PRELOADs
1329// and libraries with the DF_1_GLOBAL flag set.
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001330static soinfo_list_t make_global_group(android_namespace_t* ns) {
1331 soinfo_list_t global_group;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001332 ns->soinfo_list().for_each([&](soinfo* si) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001333 if ((si->get_dt_flags_1() & DF_1_GLOBAL) != 0) {
1334 global_group.push_back(si);
1335 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001336 });
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001337
1338 return global_group;
1339}
1340
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07001341// This function provides a list of libraries to be shared
1342// by the namespace. For the default namespace this is the global
1343// group (see make_global_group). For all others this is a group
1344// of RTLD_GLOBAL libraries (which includes the global group from
1345// the default namespace).
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001346static soinfo_list_t get_shared_group(android_namespace_t* ns) {
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07001347 if (ns == &g_default_namespace) {
1348 return make_global_group(ns);
1349 }
1350
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001351 soinfo_list_t shared_group;
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07001352 ns->soinfo_list().for_each([&](soinfo* si) {
1353 if ((si->get_rtld_flags() & RTLD_GLOBAL) != 0) {
1354 shared_group.push_back(si);
1355 }
1356 });
1357
1358 return shared_group;
1359}
1360
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001361static void shuffle(std::vector<LoadTask*>* v) {
1362 for (size_t i = 0, size = v->size(); i < size; ++i) {
1363 size_t n = size - i;
1364 size_t r = arc4random_uniform(n);
1365 std::swap((*v)[n-1], (*v)[r]);
1366 }
1367}
1368
Evgenii Stepanov0cdef7e2015-07-06 17:56:31 -07001369// add_as_children - add first-level loaded libraries (i.e. library_names[], but
1370// not their transitive dependencies) as children of the start_with library.
1371// This is false when find_libraries is called for dlopen(), when newly loaded
1372// libraries must form a disjoint tree.
Dimitry Ivanov3f660572016-09-09 10:00:39 -07001373bool find_libraries(android_namespace_t* ns,
1374 soinfo* start_with,
1375 const char* const library_names[],
1376 size_t library_names_count,
1377 soinfo* soinfos[],
1378 std::vector<soinfo*>* ld_preloads,
1379 size_t ld_preloads_count,
1380 int rtld_flags,
1381 const android_dlextinfo* extinfo,
1382 bool add_as_children) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001383 // Step 0: prepare.
1384 LoadTaskList load_tasks;
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001385 std::unordered_map<const soinfo*, ElfReader> readers_map;
1386
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001387 for (size_t i = 0; i < library_names_count; ++i) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001388 const char* name = library_names[i];
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001389 load_tasks.push_back(LoadTask::create(name, start_with, &readers_map));
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001390 }
1391
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001392 // Construct global_group.
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001393 soinfo_list_t global_group = make_global_group(ns);
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001394
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001395 // If soinfos array is null allocate one on stack.
1396 // The array is needed in case of failure; for example
1397 // when library_names[] = {libone.so, libtwo.so} and libone.so
1398 // is loaded correctly but libtwo.so failed for some reason.
1399 // In this case libone.so should be unloaded on return.
1400 // See also implementation of failure_guard below.
1401
1402 if (soinfos == nullptr) {
1403 size_t soinfos_size = sizeof(soinfo*)*library_names_count;
1404 soinfos = reinterpret_cast<soinfo**>(alloca(soinfos_size));
1405 memset(soinfos, 0, soinfos_size);
1406 }
1407
1408 // list of libraries to link - see step 2.
1409 size_t soinfos_count = 0;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001410
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001411 auto scope_guard = make_scope_guard([&]() {
1412 for (LoadTask* t : load_tasks) {
1413 LoadTask::deleter(t);
1414 }
1415 });
1416
Dmitriy Ivanovd9ff7222014-09-08 16:22:22 -07001417 auto failure_guard = make_scope_guard([&]() {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001418 // Housekeeping
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001419 soinfo_unload(soinfos, soinfos_count);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001420 });
1421
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001422 ZipArchiveCache zip_archive_cache;
1423
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001424 // Step 1: expand the list of load_tasks to include
1425 // all DT_NEEDED libraries (do not load them just yet)
1426 for (size_t i = 0; i<load_tasks.size(); ++i) {
1427 LoadTask* task = load_tasks[i];
Evgenii Stepanov68650822015-06-10 13:38:39 -07001428 soinfo* needed_by = task->get_needed_by();
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001429
Dmitriy Ivanovedfc9f62015-09-02 16:32:02 -07001430 bool is_dt_needed = needed_by != nullptr && (needed_by != start_with || add_as_children);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001431 task->set_extinfo(is_dt_needed ? nullptr : extinfo);
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001432 task->set_dt_needed(is_dt_needed);
Dmitriy Ivanovedfc9f62015-09-02 16:32:02 -07001433
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001434 if(!find_library_internal(ns, task, &zip_archive_cache, &load_tasks, rtld_flags)) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001435 return false;
1436 }
1437
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001438 soinfo* si = task->get_soinfo();
1439
Dmitriy Ivanovedfc9f62015-09-02 16:32:02 -07001440 if (is_dt_needed) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001441 needed_by->add_child(si);
1442 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001443
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001444 if (si->is_linked()) {
1445 si->increment_ref_count();
1446 }
1447
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001448 // When ld_preloads is not null, the first
1449 // ld_preloads_count libs are in fact ld_preloads.
1450 if (ld_preloads != nullptr && soinfos_count < ld_preloads_count) {
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07001451 ld_preloads->push_back(si);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001452 }
1453
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001454 if (soinfos_count < library_names_count) {
1455 soinfos[soinfos_count++] = si;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001456 }
1457 }
1458
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001459 // Step 2: Load libraries in random order (see b/24047022)
1460 LoadTaskList load_list;
1461 for (auto&& task : load_tasks) {
1462 soinfo* si = task->get_soinfo();
1463 auto pred = [&](const LoadTask* t) {
1464 return t->get_soinfo() == si;
1465 };
1466
1467 if (!si->is_linked() &&
1468 std::find_if(load_list.begin(), load_list.end(), pred) == load_list.end() ) {
1469 load_list.push_back(task);
1470 }
1471 }
1472 shuffle(&load_list);
1473
1474 for (auto&& task : load_list) {
1475 if (!task->load()) {
1476 return false;
1477 }
1478 }
1479
1480 // Step 3: pre-link all DT_NEEDED libraries in breadth first order.
1481 for (auto&& task : load_tasks) {
1482 soinfo* si = task->get_soinfo();
1483 if (!si->is_linked() && !si->prelink_image()) {
1484 return false;
1485 }
1486 }
1487
1488 // Step 4: Add LD_PRELOADed libraries to the global group for
1489 // future runs. There is no need to explicitly add them to
1490 // the global group for this run because they are going to
1491 // appear in the local group in the correct order.
1492 if (ld_preloads != nullptr) {
1493 for (auto&& si : *ld_preloads) {
1494 si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL);
1495 }
1496 }
1497
1498
1499 // Step 5: link libraries.
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001500 soinfo_list_t local_group;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001501 walk_dependencies_tree(
Evgenii Stepanov0cdef7e2015-07-06 17:56:31 -07001502 (start_with != nullptr && add_as_children) ? &start_with : soinfos,
1503 (start_with != nullptr && add_as_children) ? 1 : soinfos_count,
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001504 [&] (soinfo* si) {
1505 local_group.push_back(si);
1506 return true;
1507 });
1508
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001509 // We need to increment ref_count in case
1510 // the root of the local group was not linked.
1511 bool was_local_group_root_linked = local_group.front()->is_linked();
1512
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001513 bool linked = local_group.visit([&](soinfo* si) {
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001514 if (!si->is_linked()) {
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08001515 if (!si->link_image(global_group, local_group, extinfo)) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001516 return false;
1517 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001518 }
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001519
1520 return true;
1521 });
1522
1523 if (linked) {
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001524 local_group.for_each([](soinfo* si) {
1525 if (!si->is_linked()) {
1526 si->set_linked();
1527 }
1528 });
1529
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001530 failure_guard.disable();
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001531 }
1532
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001533 if (!was_local_group_root_linked) {
1534 local_group.front()->increment_ref_count();
1535 }
1536
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001537 return linked;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001538}
1539
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001540static soinfo* find_library(android_namespace_t* ns,
1541 const char* name, int rtld_flags,
Evgenii Stepanov0cdef7e2015-07-06 17:56:31 -07001542 const android_dlextinfo* extinfo,
1543 soinfo* needed_by) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001544 soinfo* si;
1545
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001546 if (name == nullptr) {
Dimitry Ivanov3f660572016-09-09 10:00:39 -07001547 si = solist_get_somain();
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001548 } else if (!find_libraries(ns, needed_by, &name, 1, &si, nullptr, 0, rtld_flags,
Evgenii Stepanov0cdef7e2015-07-06 17:56:31 -07001549 extinfo, /* add_as_children */ false)) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001550 return nullptr;
1551 }
1552
Elliott Hughesd23736e2012-11-01 15:16:56 -07001553 return si;
1554}
Elliott Hughesbedfe382012-08-14 14:07:59 -07001555
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001556static void soinfo_unload(soinfo* root) {
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001557 if (root->is_linked()) {
1558 root = root->get_local_group_root();
1559 }
1560
1561 if (!root->can_unload()) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001562 TRACE("not unloading \"%s\" - the binary is flagged with NODELETE", root->get_realpath());
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -07001563 return;
1564 }
1565
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001566 soinfo_unload(&root, 1);
1567}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001568
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001569static void soinfo_unload(soinfo* soinfos[], size_t count) {
1570 // Note that the library can be loaded but not linked;
1571 // in which case there is no root but we still need
1572 // to walk the tree and unload soinfos involved.
1573 //
1574 // This happens on unsuccessful dlopen, when one of
1575 // the DT_NEEDED libraries could not be linked/found.
1576 if (count == 0) {
1577 return;
1578 }
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001579
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001580 soinfo_list_t unload_list;
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001581 for (size_t i = 0; i < count; ++i) {
1582 soinfo* si = soinfos[i];
Dmitriy Ivanov5ae82cb2014-12-02 17:08:42 -08001583
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001584 if (si->can_unload()) {
1585 size_t ref_count = si->is_linked() ? si->decrement_ref_count() : 0;
1586 if (ref_count == 0) {
1587 unload_list.push_back(si);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001588 } else {
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001589 TRACE("not unloading '%s' group, decrementing ref_count to %zd",
1590 si->get_realpath(), ref_count);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001591 }
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001592 } else {
1593 TRACE("not unloading '%s' - the binary is flagged with NODELETE", si->get_realpath());
1594 return;
1595 }
1596 }
1597
1598 // This is used to identify soinfos outside of the load-group
1599 // note that we cannot have > 1 in the array and have any of them
1600 // linked. This is why we can safely use the first one.
1601 soinfo* root = soinfos[0];
1602
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001603 soinfo_list_t local_unload_list;
1604 soinfo_list_t external_unload_list;
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001605 soinfo* si = nullptr;
1606
1607 while ((si = unload_list.pop_front()) != nullptr) {
1608 if (local_unload_list.contains(si)) {
1609 continue;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001610 }
Elliott Hughesd23736e2012-11-01 15:16:56 -07001611
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001612 local_unload_list.push_back(si);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001613
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001614 if (si->has_min_version(0)) {
1615 soinfo* child = nullptr;
1616 while ((child = si->get_children().pop_front()) != nullptr) {
1617 TRACE("%s@%p needs to unload %s@%p", si->get_realpath(), si,
1618 child->get_realpath(), child);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001619
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001620 if (local_unload_list.contains(child)) {
1621 continue;
1622 } else if (child->is_linked() && child->get_local_group_root() != root) {
1623 external_unload_list.push_back(child);
1624 } else {
1625 unload_list.push_front(child);
1626 }
1627 }
1628 } else {
1629#if !defined(__work_around_b_24465209__)
1630 __libc_fatal("soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
1631#else
1632 PRINT("warning: soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
1633 for_each_dt_needed(si, [&] (const char* library_name) {
1634 TRACE("deprecated (old format of soinfo): %s needs to unload %s",
1635 si->get_realpath(), library_name);
1636
1637 soinfo* needed = find_library(si->get_primary_namespace(),
1638 library_name, RTLD_NOLOAD, nullptr, nullptr);
1639
1640 if (needed != nullptr) {
1641 // Not found: for example if symlink was deleted between dlopen and dlclose
1642 // Since we cannot really handle errors at this point - print and continue.
1643 PRINT("warning: couldn't find %s needed by %s on unload.",
1644 library_name, si->get_realpath());
1645 return;
1646 } else if (local_unload_list.contains(needed)) {
1647 // already visited
1648 return;
1649 } else if (needed->is_linked() && needed->get_local_group_root() != root) {
1650 // external group
1651 external_unload_list.push_back(needed);
1652 } else {
1653 // local group
1654 unload_list.push_front(needed);
1655 }
1656 });
1657#endif
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001658 }
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001659 }
1660
1661 local_unload_list.for_each([](soinfo* si) {
1662 si->call_destructors();
1663 });
1664
1665 while ((si = local_unload_list.pop_front()) != nullptr) {
1666 notify_gdb_of_unload(si);
1667 soinfo_free(si);
1668 }
1669
1670 while ((si = external_unload_list.pop_front()) != nullptr) {
1671 soinfo_unload(si);
Dmitriy Ivanova2547052014-11-18 12:03:09 -08001672 }
1673}
1674
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001675static std::string symbol_display_name(const char* sym_name, const char* sym_ver) {
1676 if (sym_ver == nullptr) {
1677 return sym_name;
1678 }
1679
Dimitry Ivanov9cf99cb2015-12-11 14:22:24 -08001680 return std::string(sym_name) + ", version " + sym_ver;
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001681}
1682
Dimitry Ivanovaca299a2016-04-11 12:42:58 -07001683static android_namespace_t* get_caller_namespace(soinfo* caller) {
1684 return caller != nullptr ? caller->get_primary_namespace() : g_anonymous_namespace;
1685}
1686
Elliott Hughesa4aafd12014-01-13 16:37:47 -08001687void do_android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size) {
Christopher Ferris052fa3a2014-08-26 20:48:11 -07001688 // Use basic string manipulation calls to avoid snprintf.
1689 // snprintf indirectly calls pthread_getspecific to get the size of a buffer.
1690 // When debug malloc is enabled, this call returns 0. This in turn causes
1691 // snprintf to do nothing, which causes libraries to fail to load.
1692 // See b/17302493 for further details.
1693 // Once the above bug is fixed, this code can be modified to use
1694 // snprintf again.
Evgenii Stepanovd640b222015-07-10 17:54:01 -07001695 size_t required_len = 0;
1696 for (size_t i = 0; g_default_ld_paths[i] != nullptr; ++i) {
1697 required_len += strlen(g_default_ld_paths[i]) + 1;
1698 }
Christopher Ferris052fa3a2014-08-26 20:48:11 -07001699 if (buffer_size < required_len) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07001700 __libc_fatal("android_get_LD_LIBRARY_PATH failed, buffer too small: "
1701 "buffer len %zu, required len %zu", buffer_size, required_len);
Christopher Ferris052fa3a2014-08-26 20:48:11 -07001702 }
Evgenii Stepanovd640b222015-07-10 17:54:01 -07001703 char* end = buffer;
1704 for (size_t i = 0; g_default_ld_paths[i] != nullptr; ++i) {
1705 if (i > 0) *end++ = ':';
1706 end = stpcpy(end, g_default_ld_paths[i]);
1707 }
Elliott Hughesa4aafd12014-01-13 16:37:47 -08001708}
1709
Elliott Hughescade4c32012-12-20 14:42:14 -08001710void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path) {
Nick Kralevich6bb01b62015-03-07 13:37:05 -08001711 parse_LD_LIBRARY_PATH(ld_library_path);
Elliott Hughescade4c32012-12-20 14:42:14 -08001712}
1713
Dimitry Ivanovb996d602016-07-11 18:11:39 -07001714static std::string android_dlextinfo_to_string(const android_dlextinfo* info) {
1715 if (info == nullptr) {
1716 return "(null)";
1717 }
1718
1719 return android::base::StringPrintf("[flags=0x%" PRIx64 ","
1720 " reserved_addr=%p,"
1721 " reserved_size=0x%zx,"
1722 " relro_fd=%d,"
1723 " library_fd=%d,"
1724 " library_fd_offset=0x%" PRIx64 ","
1725 " library_namespace=%s@%p]",
1726 info->flags,
1727 info->reserved_addr,
1728 info->reserved_size,
1729 info->relro_fd,
1730 info->library_fd,
1731 info->library_fd_offset,
1732 (info->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0 ?
1733 (info->library_namespace != nullptr ?
1734 info->library_namespace->get_name() : "(null)") : "(n/a)",
1735 (info->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0 ?
1736 info->library_namespace : nullptr);
1737}
1738
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001739void* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo,
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001740 void* caller_addr) {
1741 soinfo* const caller = find_containing_library(caller_addr);
Dimitry Ivanovb996d602016-07-11 18:11:39 -07001742 android_namespace_t* ns = get_caller_namespace(caller);
1743
1744 LD_LOG(kLogDlopen,
1745 "dlopen(name=\"%s\", flags=0x%x, extinfo=%s, caller=\"%s\", caller_ns=%s@%p) ...",
1746 name,
1747 flags,
1748 android_dlextinfo_to_string(extinfo).c_str(),
1749 caller == nullptr ? "(null)" : caller->get_realpath(),
1750 ns == nullptr ? "(null)" : ns->get_name(),
1751 ns);
1752
1753 auto failure_guard = make_scope_guard([&]() {
1754 LD_LOG(kLogDlopen, "... dlopen failed: %s", linker_get_error_buffer());
1755 });
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001756
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -07001757 if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL|RTLD_NODELETE|RTLD_NOLOAD)) != 0) {
Elliott Hughese66190d2012-12-18 15:57:55 -08001758 DL_ERR("invalid flags to dlopen: %x", flags);
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07001759 return nullptr;
Elliott Hughese66190d2012-12-18 15:57:55 -08001760 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001761
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001762 if (extinfo != nullptr) {
1763 if ((extinfo->flags & ~(ANDROID_DLEXT_VALID_FLAG_BITS)) != 0) {
1764 DL_ERR("invalid extended flags to android_dlopen_ext: 0x%" PRIx64, extinfo->flags);
1765 return nullptr;
1766 }
Dmitriy Ivanov126af752015-10-07 16:34:20 -07001767
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001768 if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) == 0 &&
Dmitriy Ivanova6c12792014-10-21 12:09:18 -07001769 (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07001770 DL_ERR("invalid extended flag combination (ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET without "
1771 "ANDROID_DLEXT_USE_LIBRARY_FD): 0x%" PRIx64, extinfo->flags);
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001772 return nullptr;
1773 }
Dmitriy Ivanov126af752015-10-07 16:34:20 -07001774
1775 if ((extinfo->flags & ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS) != 0 &&
1776 (extinfo->flags & (ANDROID_DLEXT_RESERVED_ADDRESS | ANDROID_DLEXT_RESERVED_ADDRESS_HINT)) != 0) {
1777 DL_ERR("invalid extended flag combination: ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS is not "
1778 "compatible with ANDROID_DLEXT_RESERVED_ADDRESS/ANDROID_DLEXT_RESERVED_ADDRESS_HINT");
1779 return nullptr;
1780 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001781
1782 if ((extinfo->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0) {
1783 if (extinfo->library_namespace == nullptr) {
1784 DL_ERR("ANDROID_DLEXT_USE_NAMESPACE is set but extinfo->library_namespace is null");
1785 return nullptr;
1786 }
1787 ns = extinfo->library_namespace;
1788 }
Torne (Richard Coles)012cb452014-02-06 14:34:21 +00001789 }
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -08001790
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -07001791 std::string asan_name_holder;
1792
1793 const char* translated_name = name;
1794 if (g_is_asan) {
1795 if (file_is_in_dir(name, kSystemLibDir)) {
1796 asan_name_holder = std::string(kAsanSystemLibDir) + "/" + basename(name);
1797 if (file_exists(asan_name_holder.c_str())) {
1798 translated_name = asan_name_holder.c_str();
1799 PRINT("linker_asan dlopen translating \"%s\" -> \"%s\"", name, translated_name);
1800 }
1801 } else if (file_is_in_dir(name, kVendorLibDir)) {
1802 asan_name_holder = std::string(kAsanVendorLibDir) + "/" + basename(name);
1803 if (file_exists(asan_name_holder.c_str())) {
1804 translated_name = asan_name_holder.c_str();
1805 PRINT("linker_asan dlopen translating \"%s\" -> \"%s\"", name, translated_name);
1806 }
1807 }
1808 }
1809
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -08001810 ProtectedDataGuard guard;
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -07001811 soinfo* si = find_library(ns, translated_name, flags, extinfo, caller);
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07001812 if (si != nullptr) {
Dimitry Ivanovb996d602016-07-11 18:11:39 -07001813 failure_guard.disable();
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08001814 si->call_constructors();
Dimitry Ivanovb996d602016-07-11 18:11:39 -07001815 void* handle = si->to_handle();
1816 LD_LOG(kLogDlopen,
1817 "... dlopen successful: realpath=\"%s\", soname=\"%s\", handle=%p",
1818 si->get_realpath(), si->get_soname(), handle);
1819 return handle;
Elliott Hughesd23736e2012-11-01 15:16:56 -07001820 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001821
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001822 return nullptr;
Elliott Hughesd23736e2012-11-01 15:16:56 -07001823}
1824
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001825int do_dladdr(const void* addr, Dl_info* info) {
1826 // Determine if this address can be found in any library currently mapped.
1827 soinfo* si = find_containing_library(addr);
1828 if (si == nullptr) {
1829 return 0;
1830 }
1831
1832 memset(info, 0, sizeof(Dl_info));
1833
1834 info->dli_fname = si->get_realpath();
1835 // Address at which the shared object is loaded.
1836 info->dli_fbase = reinterpret_cast<void*>(si->base);
1837
1838 // Determine if any symbol in the library contains the specified address.
1839 ElfW(Sym)* sym = si->find_symbol_by_address(addr);
1840 if (sym != nullptr) {
1841 info->dli_sname = si->get_string(sym->st_name);
1842 info->dli_saddr = reinterpret_cast<void*>(si->resolve_symbol_address(sym));
1843 }
1844
1845 return 1;
1846}
1847
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001848static soinfo* soinfo_from_handle(void* handle) {
1849 if ((reinterpret_cast<uintptr_t>(handle) & 1) != 0) {
1850 auto it = g_soinfo_handles_map.find(reinterpret_cast<uintptr_t>(handle));
1851 if (it == g_soinfo_handles_map.end()) {
1852 return nullptr;
1853 } else {
1854 return it->second;
1855 }
1856 }
1857
1858 return static_cast<soinfo*>(handle);
1859}
1860
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001861bool do_dlsym(void* handle, const char* sym_name, const char* sym_ver,
1862 void* caller_addr, void** symbol) {
1863#if !defined(__LP64__)
1864 if (handle == nullptr) {
1865 DL_ERR("dlsym failed: library handle is null");
1866 return false;
1867 }
1868#endif
1869
1870 if (sym_name == nullptr) {
1871 DL_ERR("dlsym failed: symbol name is null");
1872 return false;
1873 }
1874
1875 soinfo* found = nullptr;
1876 const ElfW(Sym)* sym = nullptr;
1877 soinfo* caller = find_containing_library(caller_addr);
Dimitry Ivanovaca299a2016-04-11 12:42:58 -07001878 android_namespace_t* ns = get_caller_namespace(caller);
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001879
1880 version_info vi_instance;
1881 version_info* vi = nullptr;
1882
1883 if (sym_ver != nullptr) {
Dimitry Ivanov9cf99cb2015-12-11 14:22:24 -08001884 vi_instance.name = sym_ver;
1885 vi_instance.elf_hash = calculate_elf_hash(sym_ver);
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001886 vi = &vi_instance;
1887 }
1888
1889 if (handle == RTLD_DEFAULT || handle == RTLD_NEXT) {
1890 sym = dlsym_linear_lookup(ns, sym_name, vi, &found, caller, handle);
1891 } else {
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001892 soinfo* si = soinfo_from_handle(handle);
1893 if (si == nullptr) {
1894 DL_ERR("dlsym failed: invalid handle: %p", handle);
1895 return false;
1896 }
1897 sym = dlsym_handle_lookup(si, &found, sym_name, vi);
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001898 }
1899
1900 if (sym != nullptr) {
1901 uint32_t bind = ELF_ST_BIND(sym->st_info);
1902
1903 if ((bind == STB_GLOBAL || bind == STB_WEAK) && sym->st_shndx != 0) {
1904 *symbol = reinterpret_cast<void*>(found->resolve_symbol_address(sym));
1905 return true;
1906 }
1907
1908 DL_ERR("symbol \"%s\" found but not global", symbol_display_name(sym_name, sym_ver).c_str());
1909 return false;
1910 }
1911
1912 DL_ERR("undefined symbol: %s", symbol_display_name(sym_name, sym_ver).c_str());
1913 return false;
1914}
1915
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001916int do_dlclose(void* handle) {
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -08001917 ProtectedDataGuard guard;
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001918 soinfo* si = soinfo_from_handle(handle);
1919 if (si == nullptr) {
1920 DL_ERR("invalid handle: %p", handle);
1921 return -1;
1922 }
1923
Dmitriy Ivanovb648a8a2014-05-19 15:06:58 -07001924 soinfo_unload(si);
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07001925 return 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001926}
1927
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08001928bool init_namespaces(const char* public_ns_sonames, const char* anon_ns_library_path) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001929 if (g_public_namespace_initialized) {
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08001930 DL_ERR("public namespace has already been initialized.");
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001931 return false;
1932 }
1933
Dimitry Ivanov54807612016-04-21 14:57:38 -07001934 if (public_ns_sonames == nullptr || public_ns_sonames[0] == '\0') {
1935 DL_ERR("error initializing public namespace: the list of public libraries is empty.");
1936 return false;
1937 }
1938
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08001939 std::vector<std::string> sonames = android::base::Split(public_ns_sonames, ":");
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001940
1941 ProtectedDataGuard guard;
1942
1943 auto failure_guard = make_scope_guard([&]() {
1944 g_public_namespace.clear();
1945 });
1946
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001947 for (const auto& soname : sonames) {
Dmitriy Ivanov3cc35e22015-11-17 18:36:50 -08001948 soinfo* candidate = nullptr;
1949
1950 find_loaded_library_by_soname(&g_default_namespace, soname.c_str(), &candidate);
1951
1952 if (candidate == nullptr) {
Christopher Ferris523e2a92016-06-17 13:46:36 -07001953 DL_ERR("error initializing public namespace: a library with soname \"%s\""
1954 " was not found in the default namespace", soname.c_str());
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001955 return false;
1956 }
1957
1958 candidate->set_nodelete();
1959 g_public_namespace.push_back(candidate);
1960 }
1961
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001962 g_public_namespace_initialized = true;
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08001963
1964 // create anonymous namespace
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08001965 // When the caller is nullptr - create_namespace will take global group
1966 // from the anonymous namespace, which is fine because anonymous namespace
1967 // is still pointing to the default one.
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08001968 android_namespace_t* anon_ns =
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08001969 create_namespace(nullptr, "(anonymous)", nullptr, anon_ns_library_path,
Dimitry Ivanov52408632016-05-23 10:31:11 -07001970 ANDROID_NAMESPACE_TYPE_REGULAR, nullptr, &g_default_namespace);
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08001971
1972 if (anon_ns == nullptr) {
1973 g_public_namespace_initialized = false;
1974 return false;
1975 }
1976 g_anonymous_namespace = anon_ns;
1977 failure_guard.disable();
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001978 return true;
1979}
1980
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001981static void add_soinfos_to_namespace(const soinfo_list_t& soinfos, android_namespace_t* ns) {
1982 ns->add_soinfos(soinfos);
1983 for (auto si : soinfos) {
1984 si->add_secondary_namespace(ns);
1985 }
1986}
1987
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08001988android_namespace_t* create_namespace(const void* caller_addr,
1989 const char* name,
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001990 const char* ld_library_path,
1991 const char* default_library_path,
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08001992 uint64_t type,
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07001993 const char* permitted_when_isolated_path,
1994 android_namespace_t* parent_namespace) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001995 if (!g_public_namespace_initialized) {
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08001996 DL_ERR("cannot create namespace: public namespace is not initialized.");
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001997 return nullptr;
1998 }
1999
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002000 if (parent_namespace == nullptr) {
Dimitry Ivanov52408632016-05-23 10:31:11 -07002001 // if parent_namespace is nullptr -> set it to the caller namespace
2002 soinfo* caller_soinfo = find_containing_library(caller_addr);
2003
2004 parent_namespace = caller_soinfo != nullptr ?
2005 caller_soinfo->get_primary_namespace() :
2006 g_anonymous_namespace;
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002007 }
2008
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002009 ProtectedDataGuard guard;
2010 std::vector<std::string> ld_library_paths;
2011 std::vector<std::string> default_library_paths;
Dimitry Ivanov284ae352015-12-08 10:47:13 -08002012 std::vector<std::string> permitted_paths;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002013
2014 parse_path(ld_library_path, ":", &ld_library_paths);
2015 parse_path(default_library_path, ":", &default_library_paths);
Dimitry Ivanov284ae352015-12-08 10:47:13 -08002016 parse_path(permitted_when_isolated_path, ":", &permitted_paths);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002017
2018 android_namespace_t* ns = new (g_namespace_allocator.alloc()) android_namespace_t();
2019 ns->set_name(name);
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002020 ns->set_isolated((type & ANDROID_NAMESPACE_TYPE_ISOLATED) != 0);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002021 ns->set_ld_library_paths(std::move(ld_library_paths));
2022 ns->set_default_library_paths(std::move(default_library_paths));
Dimitry Ivanov284ae352015-12-08 10:47:13 -08002023 ns->set_permitted_paths(std::move(permitted_paths));
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002024
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002025 if ((type & ANDROID_NAMESPACE_TYPE_SHARED) != 0) {
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002026 // If shared - clone the parent namespace
Dimitry Ivanovb943f302016-08-03 16:00:10 -07002027 add_soinfos_to_namespace(parent_namespace->soinfo_list(), ns);
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002028 } else {
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002029 // If not shared - copy only the shared group
Dimitry Ivanovb943f302016-08-03 16:00:10 -07002030 add_soinfos_to_namespace(get_shared_group(parent_namespace), ns);
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002031 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002032
2033 return ns;
2034}
2035
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002036ElfW(Addr) call_ifunc_resolver(ElfW(Addr) resolver_addr) {
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07002037 typedef ElfW(Addr) (*ifunc_resolver_t)(void);
2038 ifunc_resolver_t ifunc_resolver = reinterpret_cast<ifunc_resolver_t>(resolver_addr);
2039 ElfW(Addr) ifunc_addr = ifunc_resolver();
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002040 TRACE_TYPE(RELO, "Called ifunc_resolver@%p. The result is %p",
2041 ifunc_resolver, reinterpret_cast<void*>(ifunc_addr));
Brigid Smithc5a13ef2014-07-23 11:22:25 -07002042
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07002043 return ifunc_addr;
Brigid Smithc5a13ef2014-07-23 11:22:25 -07002044}
Brigid Smithc5a13ef2014-07-23 11:22:25 -07002045
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002046const version_info* VersionTracker::get_version_info(ElfW(Versym) source_symver) const {
2047 if (source_symver < 2 ||
2048 source_symver >= version_infos.size() ||
2049 version_infos[source_symver].name == nullptr) {
2050 return nullptr;
2051 }
2052
2053 return &version_infos[source_symver];
2054}
2055
2056void VersionTracker::add_version_info(size_t source_index,
2057 ElfW(Word) elf_hash,
2058 const char* ver_name,
2059 const soinfo* target_si) {
2060 if (source_index >= version_infos.size()) {
2061 version_infos.resize(source_index+1);
2062 }
2063
2064 version_infos[source_index].elf_hash = elf_hash;
2065 version_infos[source_index].name = ver_name;
2066 version_infos[source_index].target_si = target_si;
2067}
2068
2069bool VersionTracker::init_verneed(const soinfo* si_from) {
2070 uintptr_t verneed_ptr = si_from->get_verneed_ptr();
2071
2072 if (verneed_ptr == 0) {
2073 return true;
2074 }
2075
2076 size_t verneed_cnt = si_from->get_verneed_cnt();
2077
2078 for (size_t i = 0, offset = 0; i<verneed_cnt; ++i) {
2079 const ElfW(Verneed)* verneed = reinterpret_cast<ElfW(Verneed)*>(verneed_ptr + offset);
2080 size_t vernaux_offset = offset + verneed->vn_aux;
2081 offset += verneed->vn_next;
2082
2083 if (verneed->vn_version != 1) {
2084 DL_ERR("unsupported verneed[%zd] vn_version: %d (expected 1)", i, verneed->vn_version);
2085 return false;
2086 }
2087
2088 const char* target_soname = si_from->get_string(verneed->vn_file);
2089 // find it in dependencies
2090 soinfo* target_si = si_from->get_children().find_if([&](const soinfo* si) {
Dmitriy Ivanov406d9962015-05-06 11:05:27 -07002091 return si->get_soname() != nullptr && strcmp(si->get_soname(), target_soname) == 0;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002092 });
2093
2094 if (target_si == nullptr) {
2095 DL_ERR("cannot find \"%s\" from verneed[%zd] in DT_NEEDED list for \"%s\"",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002096 target_soname, i, si_from->get_realpath());
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002097 return false;
2098 }
2099
2100 for (size_t j = 0; j<verneed->vn_cnt; ++j) {
2101 const ElfW(Vernaux)* vernaux = reinterpret_cast<ElfW(Vernaux)*>(verneed_ptr + vernaux_offset);
2102 vernaux_offset += vernaux->vna_next;
2103
2104 const ElfW(Word) elf_hash = vernaux->vna_hash;
2105 const char* ver_name = si_from->get_string(vernaux->vna_name);
2106 ElfW(Half) source_index = vernaux->vna_other;
2107
2108 add_version_info(source_index, elf_hash, ver_name, target_si);
2109 }
2110 }
2111
2112 return true;
2113}
2114
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002115template <typename F>
2116static bool for_each_verdef(const soinfo* si, F functor) {
2117 if (!si->has_min_version(2)) {
2118 return true;
2119 }
2120
2121 uintptr_t verdef_ptr = si->get_verdef_ptr();
2122 if (verdef_ptr == 0) {
2123 return true;
2124 }
2125
2126 size_t offset = 0;
2127
2128 size_t verdef_cnt = si->get_verdef_cnt();
2129 for (size_t i = 0; i<verdef_cnt; ++i) {
2130 const ElfW(Verdef)* verdef = reinterpret_cast<ElfW(Verdef)*>(verdef_ptr + offset);
2131 size_t verdaux_offset = offset + verdef->vd_aux;
2132 offset += verdef->vd_next;
2133
2134 if (verdef->vd_version != 1) {
2135 DL_ERR("unsupported verdef[%zd] vd_version: %d (expected 1) library: %s",
2136 i, verdef->vd_version, si->get_realpath());
2137 return false;
2138 }
2139
2140 if ((verdef->vd_flags & VER_FLG_BASE) != 0) {
2141 // "this is the version of the file itself. It must not be used for
2142 // matching a symbol. It can be used to match references."
2143 //
2144 // http://www.akkadia.org/drepper/symbol-versioning
2145 continue;
2146 }
2147
2148 if (verdef->vd_cnt == 0) {
2149 DL_ERR("invalid verdef[%zd] vd_cnt == 0 (version without a name)", i);
2150 return false;
2151 }
2152
2153 const ElfW(Verdaux)* verdaux = reinterpret_cast<ElfW(Verdaux)*>(verdef_ptr + verdaux_offset);
2154
2155 if (functor(i, verdef, verdaux) == true) {
2156 break;
2157 }
2158 }
2159
2160 return true;
2161}
2162
2163bool find_verdef_version_index(const soinfo* si, const version_info* vi, ElfW(Versym)* versym) {
2164 if (vi == nullptr) {
2165 *versym = kVersymNotNeeded;
2166 return true;
2167 }
2168
2169 *versym = kVersymGlobal;
2170
2171 return for_each_verdef(si,
2172 [&](size_t, const ElfW(Verdef)* verdef, const ElfW(Verdaux)* verdaux) {
2173 if (verdef->vd_hash == vi->elf_hash &&
2174 strcmp(vi->name, si->get_string(verdaux->vda_name)) == 0) {
2175 *versym = verdef->vd_ndx;
2176 return true;
2177 }
2178
2179 return false;
2180 }
2181 );
2182}
2183
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002184bool VersionTracker::init_verdef(const soinfo* si_from) {
2185 return for_each_verdef(si_from,
2186 [&](size_t, const ElfW(Verdef)* verdef, const ElfW(Verdaux)* verdaux) {
2187 add_version_info(verdef->vd_ndx, verdef->vd_hash,
2188 si_from->get_string(verdaux->vda_name), si_from);
2189 return false;
2190 }
2191 );
2192}
2193
2194bool VersionTracker::init(const soinfo* si_from) {
2195 if (!si_from->has_min_version(2)) {
2196 return true;
2197 }
2198
2199 return init_verneed(si_from) && init_verdef(si_from);
2200}
2201
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002202// TODO (dimitry): Methods below need to be moved out of soinfo
2203// and in more isolated file in order minimize dependencies on
2204// unnecessary object in the linker binary. Consider making them
2205// independent from soinfo (?).
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002206bool soinfo::lookup_version_info(const VersionTracker& version_tracker, ElfW(Word) sym,
2207 const char* sym_name, const version_info** vi) {
2208 const ElfW(Versym)* sym_ver_ptr = get_versym(sym);
2209 ElfW(Versym) sym_ver = sym_ver_ptr == nullptr ? 0 : *sym_ver_ptr;
2210
2211 if (sym_ver != VER_NDX_LOCAL && sym_ver != VER_NDX_GLOBAL) {
2212 *vi = version_tracker.get_version_info(sym_ver);
2213
2214 if (*vi == nullptr) {
2215 DL_ERR("cannot find verneed/verdef for version index=%d "
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002216 "referenced by symbol \"%s\" at \"%s\"", sym_ver, sym_name, get_realpath());
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002217 return false;
2218 }
2219 } else {
2220 // there is no version info
2221 *vi = nullptr;
2222 }
2223
2224 return true;
2225}
2226
Dimitry Ivanov576a3752016-08-09 06:58:55 -07002227#if !defined(__mips__)
2228#if defined(USE_RELA)
2229static ElfW(Addr) get_addend(ElfW(Rela)* rela, ElfW(Addr) reloc_addr __unused) {
2230 return rela->r_addend;
2231}
2232#else
2233static ElfW(Addr) get_addend(ElfW(Rel)* rel, ElfW(Addr) reloc_addr) {
2234 if (ELFW(R_TYPE)(rel->r_info) == R_GENERIC_RELATIVE ||
2235 ELFW(R_TYPE)(rel->r_info) == R_GENERIC_IRELATIVE) {
2236 return *reinterpret_cast<ElfW(Addr)*>(reloc_addr);
2237 }
2238 return 0;
2239}
2240#endif
2241
Dmitriy Ivanovfa26eee2015-02-03 16:06:47 -08002242template<typename ElfRelIteratorT>
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07002243bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& rel_iterator,
2244 const soinfo_list_t& global_group, const soinfo_list_t& local_group) {
Dmitriy Ivanovfa26eee2015-02-03 16:06:47 -08002245 for (size_t idx = 0; rel_iterator.has_next(); ++idx) {
2246 const auto rel = rel_iterator.next();
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002247 if (rel == nullptr) {
2248 return false;
2249 }
2250
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002251 ElfW(Word) type = ELFW(R_TYPE)(rel->r_info);
2252 ElfW(Word) sym = ELFW(R_SYM)(rel->r_info);
2253
2254 ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rel->r_offset + load_bias);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002255 ElfW(Addr) sym_addr = 0;
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07002256 const char* sym_name = nullptr;
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002257 ElfW(Addr) addend = get_addend(rel, reloc);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002258
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07002259 DEBUG("Processing \"%s\" relocation at index %zd", get_realpath(), idx);
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002260 if (type == R_GENERIC_NONE) {
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002261 continue;
2262 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002263
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002264 const ElfW(Sym)* s = nullptr;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002265 soinfo* lsi = nullptr;
2266
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002267 if (sym != 0) {
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002268 sym_name = get_string(symtab_[sym].st_name);
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002269 const version_info* vi = nullptr;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002270
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002271 if (!lookup_version_info(version_tracker, sym, sym_name, &vi)) {
2272 return false;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002273 }
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002274
2275 if (!soinfo_do_lookup(this, sym_name, vi, &lsi, global_group, local_group, &s)) {
2276 return false;
2277 }
2278
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07002279 if (s == nullptr) {
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002280 // We only allow an undefined symbol if this is a weak reference...
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002281 s = &symtab_[sym];
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002282 if (ELF_ST_BIND(s->st_info) != STB_WEAK) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002283 DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, get_realpath());
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002284 return false;
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002285 }
2286
2287 /* IHI0044C AAELF 4.5.1.1:
2288
2289 Libraries are not searched to resolve weak references.
2290 It is not an error for a weak reference to remain unsatisfied.
2291
2292 During linking, the value of an undefined weak reference is:
2293 - Zero if the relocation type is absolute
2294 - The address of the place if the relocation is pc-relative
2295 - The address of nominal base address if the relocation
2296 type is base-relative.
2297 */
2298
2299 switch (type) {
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002300 case R_GENERIC_JUMP_SLOT:
2301 case R_GENERIC_GLOB_DAT:
2302 case R_GENERIC_RELATIVE:
2303 case R_GENERIC_IRELATIVE:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002304#if defined(__aarch64__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002305 case R_AARCH64_ABS64:
2306 case R_AARCH64_ABS32:
2307 case R_AARCH64_ABS16:
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002308#elif defined(__x86_64__)
2309 case R_X86_64_32:
2310 case R_X86_64_64:
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002311#elif defined(__arm__)
2312 case R_ARM_ABS32:
2313#elif defined(__i386__)
2314 case R_386_32:
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002315#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002316 /*
2317 * The sym_addr was initialized to be zero above, or the relocation
2318 * code below does not care about value of sym_addr.
2319 * No need to do anything.
2320 */
2321 break;
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002322#if defined(__x86_64__)
Dimitry Ivanovd338aac2015-01-13 22:31:54 +00002323 case R_X86_64_PC32:
2324 sym_addr = reloc;
2325 break;
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002326#elif defined(__i386__)
2327 case R_386_PC32:
2328 sym_addr = reloc;
2329 break;
2330#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002331 default:
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002332 DL_ERR("unknown weak reloc type %d @ %p (%zu)", type, rel, idx);
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002333 return false;
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002334 }
Dmitriy Ivanovec83a612015-07-26 07:37:09 -07002335 } else { // We got a definition.
2336#if !defined(__LP64__)
2337 // When relocating dso with text_relocation .text segment is
2338 // not executable. We need to restore elf flags before resolving
2339 // STT_GNU_IFUNC symbol.
2340 bool protect_segments = has_text_relocations &&
2341 lsi == this &&
2342 ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC;
2343 if (protect_segments) {
2344 if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
2345 DL_ERR("can't protect segments for \"%s\": %s",
2346 get_realpath(), strerror(errno));
2347 return false;
2348 }
2349 }
2350#endif
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07002351 sym_addr = lsi->resolve_symbol_address(s);
Dmitriy Ivanovec83a612015-07-26 07:37:09 -07002352#if !defined(__LP64__)
2353 if (protect_segments) {
2354 if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
2355 DL_ERR("can't unprotect loadable segments for \"%s\": %s",
2356 get_realpath(), strerror(errno));
2357 return false;
2358 }
2359 }
2360#endif
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002361 }
2362 count_relocation(kRelocSymbol);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002363 }
2364
2365 switch (type) {
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002366 case R_GENERIC_JUMP_SLOT:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002367 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002368 MARK(rel->r_offset);
2369 TRACE_TYPE(RELO, "RELO JMP_SLOT %16p <- %16p %s\n",
2370 reinterpret_cast<void*>(reloc),
2371 reinterpret_cast<void*>(sym_addr + addend), sym_name);
2372
2373 *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002374 break;
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002375 case R_GENERIC_GLOB_DAT:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002376 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002377 MARK(rel->r_offset);
2378 TRACE_TYPE(RELO, "RELO GLOB_DAT %16p <- %16p %s\n",
2379 reinterpret_cast<void*>(reloc),
2380 reinterpret_cast<void*>(sym_addr + addend), sym_name);
2381 *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002382 break;
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002383 case R_GENERIC_RELATIVE:
2384 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002385 MARK(rel->r_offset);
2386 TRACE_TYPE(RELO, "RELO RELATIVE %16p <- %16p\n",
2387 reinterpret_cast<void*>(reloc),
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002388 reinterpret_cast<void*>(load_bias + addend));
2389 *reinterpret_cast<ElfW(Addr)*>(reloc) = (load_bias + addend);
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002390 break;
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002391 case R_GENERIC_IRELATIVE:
2392 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002393 MARK(rel->r_offset);
2394 TRACE_TYPE(RELO, "RELO IRELATIVE %16p <- %16p\n",
2395 reinterpret_cast<void*>(reloc),
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002396 reinterpret_cast<void*>(load_bias + addend));
Dmitriy Ivanovec83a612015-07-26 07:37:09 -07002397 {
2398#if !defined(__LP64__)
2399 // When relocating dso with text_relocation .text segment is
2400 // not executable. We need to restore elf flags for this
2401 // particular call.
2402 if (has_text_relocations) {
2403 if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
2404 DL_ERR("can't protect segments for \"%s\": %s",
2405 get_realpath(), strerror(errno));
2406 return false;
2407 }
2408 }
2409#endif
2410 ElfW(Addr) ifunc_addr = call_ifunc_resolver(load_bias + addend);
2411#if !defined(__LP64__)
2412 // Unprotect it afterwards...
2413 if (has_text_relocations) {
2414 if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
2415 DL_ERR("can't unprotect loadable segments for \"%s\": %s",
2416 get_realpath(), strerror(errno));
2417 return false;
2418 }
2419 }
2420#endif
2421 *reinterpret_cast<ElfW(Addr)*>(reloc) = ifunc_addr;
2422 }
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002423 break;
2424
2425#if defined(__aarch64__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002426 case R_AARCH64_ABS64:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002427 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002428 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002429 TRACE_TYPE(RELO, "RELO ABS64 %16llx <- %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002430 reloc, sym_addr + addend, sym_name);
2431 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend;
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002432 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002433 case R_AARCH64_ABS32:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002434 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002435 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002436 TRACE_TYPE(RELO, "RELO ABS32 %16llx <- %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002437 reloc, sym_addr + addend, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002438 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002439 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT32_MIN);
2440 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT32_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002441 if ((min_value <= (sym_addr + addend)) &&
2442 ((sym_addr + addend) <= max_value)) {
2443 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend;
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002444 } else {
2445 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002446 sym_addr + addend, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002447 return false;
2448 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002449 }
2450 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002451 case R_AARCH64_ABS16:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002452 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002453 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002454 TRACE_TYPE(RELO, "RELO ABS16 %16llx <- %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002455 reloc, sym_addr + addend, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002456 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002457 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN);
2458 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT16_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002459 if ((min_value <= (sym_addr + addend)) &&
2460 ((sym_addr + addend) <= max_value)) {
2461 *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002462 } else {
2463 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002464 sym_addr + addend, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002465 return false;
2466 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002467 }
2468 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002469 case R_AARCH64_PREL64:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002470 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002471 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002472 TRACE_TYPE(RELO, "RELO REL64 %16llx <- %16llx - %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002473 reloc, sym_addr + addend, rel->r_offset, sym_name);
2474 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset;
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002475 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002476 case R_AARCH64_PREL32:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002477 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002478 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002479 TRACE_TYPE(RELO, "RELO REL32 %16llx <- %16llx - %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002480 reloc, sym_addr + addend, rel->r_offset, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002481 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002482 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT32_MIN);
2483 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT32_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002484 if ((min_value <= (sym_addr + addend - rel->r_offset)) &&
2485 ((sym_addr + addend - rel->r_offset) <= max_value)) {
2486 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset;
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002487 } else {
2488 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002489 sym_addr + addend - rel->r_offset, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002490 return false;
2491 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002492 }
2493 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002494 case R_AARCH64_PREL16:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002495 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002496 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002497 TRACE_TYPE(RELO, "RELO REL16 %16llx <- %16llx - %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002498 reloc, sym_addr + addend, rel->r_offset, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002499 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002500 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN);
2501 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT16_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002502 if ((min_value <= (sym_addr + addend - rel->r_offset)) &&
2503 ((sym_addr + addend - rel->r_offset) <= max_value)) {
2504 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset;
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002505 } else {
2506 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002507 sym_addr + addend - rel->r_offset, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002508 return false;
2509 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002510 }
2511 break;
2512
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002513 case R_AARCH64_COPY:
Nick Kralevich76e289c2014-07-03 12:04:31 -07002514 /*
2515 * ET_EXEC is not supported so this should not happen.
2516 *
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002517 * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0056b/IHI0056B_aaelf64.pdf
Nick Kralevich76e289c2014-07-03 12:04:31 -07002518 *
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002519 * Section 4.6.11 "Dynamic relocations"
Nick Kralevich76e289c2014-07-03 12:04:31 -07002520 * R_AARCH64_COPY may only appear in executable objects where e_type is
2521 * set to ET_EXEC.
2522 */
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002523 DL_ERR("%s R_AARCH64_COPY relocations are not supported", get_realpath());
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002524 return false;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002525 case R_AARCH64_TLS_TPREL64:
Elliott Hughes0266ae52014-02-10 17:46:57 -08002526 TRACE_TYPE(RELO, "RELO TLS_TPREL64 *** %16llx <- %16llx - %16llx\n",
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002527 reloc, (sym_addr + addend), rel->r_offset);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002528 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002529 case R_AARCH64_TLS_DTPREL32:
Elliott Hughes0266ae52014-02-10 17:46:57 -08002530 TRACE_TYPE(RELO, "RELO TLS_DTPREL32 *** %16llx <- %16llx - %16llx\n",
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002531 reloc, (sym_addr + addend), rel->r_offset);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002532 break;
2533#elif defined(__x86_64__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002534 case R_X86_64_32:
2535 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002536 MARK(rel->r_offset);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002537 TRACE_TYPE(RELO, "RELO R_X86_64_32 %08zx <- +%08zx %s", static_cast<size_t>(reloc),
2538 static_cast<size_t>(sym_addr), sym_name);
Junichi Uekawaff35b1e2015-11-18 10:18:59 +09002539 *reinterpret_cast<Elf32_Addr*>(reloc) = sym_addr + addend;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002540 break;
2541 case R_X86_64_64:
2542 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002543 MARK(rel->r_offset);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002544 TRACE_TYPE(RELO, "RELO R_X86_64_64 %08zx <- +%08zx %s", static_cast<size_t>(reloc),
2545 static_cast<size_t>(sym_addr), sym_name);
Junichi Uekawaff35b1e2015-11-18 10:18:59 +09002546 *reinterpret_cast<Elf64_Addr*>(reloc) = sym_addr + addend;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002547 break;
2548 case R_X86_64_PC32:
2549 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002550 MARK(rel->r_offset);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002551 TRACE_TYPE(RELO, "RELO R_X86_64_PC32 %08zx <- +%08zx (%08zx - %08zx) %s",
2552 static_cast<size_t>(reloc), static_cast<size_t>(sym_addr - reloc),
2553 static_cast<size_t>(sym_addr), static_cast<size_t>(reloc), sym_name);
Junichi Uekawaff35b1e2015-11-18 10:18:59 +09002554 *reinterpret_cast<Elf32_Addr*>(reloc) = sym_addr + addend - reloc;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002555 break;
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002556#elif defined(__arm__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002557 case R_ARM_ABS32:
2558 count_relocation(kRelocAbsolute);
2559 MARK(rel->r_offset);
2560 TRACE_TYPE(RELO, "RELO ABS %08x <- %08x %s", reloc, sym_addr, sym_name);
2561 *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
2562 break;
2563 case R_ARM_REL32:
2564 count_relocation(kRelocRelative);
2565 MARK(rel->r_offset);
2566 TRACE_TYPE(RELO, "RELO REL32 %08x <- %08x - %08x %s",
2567 reloc, sym_addr, rel->r_offset, sym_name);
2568 *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr - rel->r_offset;
2569 break;
2570 case R_ARM_COPY:
2571 /*
2572 * ET_EXEC is not supported so this should not happen.
2573 *
2574 * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044d/IHI0044D_aaelf.pdf
2575 *
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002576 * Section 4.6.1.10 "Dynamic relocations"
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002577 * R_ARM_COPY may only appear in executable objects where e_type is
2578 * set to ET_EXEC.
2579 */
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002580 DL_ERR("%s R_ARM_COPY relocations are not supported", get_realpath());
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002581 return false;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002582#elif defined(__i386__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002583 case R_386_32:
2584 count_relocation(kRelocRelative);
2585 MARK(rel->r_offset);
2586 TRACE_TYPE(RELO, "RELO R_386_32 %08x <- +%08x %s", reloc, sym_addr, sym_name);
2587 *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
2588 break;
2589 case R_386_PC32:
2590 count_relocation(kRelocRelative);
2591 MARK(rel->r_offset);
2592 TRACE_TYPE(RELO, "RELO R_386_PC32 %08x <- +%08x (%08x - %08x) %s",
2593 reloc, (sym_addr - reloc), sym_addr, reloc, sym_name);
2594 *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr - reloc);
2595 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002596#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002597 default:
2598 DL_ERR("unknown reloc type %d @ %p (%zu)", type, rel, idx);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002599 return false;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002600 }
2601 }
2602 return true;
Raghu Gandhamd7daacb2012-07-31 12:07:22 -07002603}
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002604#endif // !defined(__mips__)
Raghu Gandhamd7daacb2012-07-31 12:07:22 -07002605
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002606// An empty list of soinfos
Dimitry Ivanovb943f302016-08-03 16:00:10 -07002607static soinfo_list_t g_empty_list;
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07002608
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002609bool soinfo::prelink_image() {
Ningsheng Jiane93be992014-09-16 15:22:10 +08002610 /* Extract dynamic section */
2611 ElfW(Word) dynamic_flags = 0;
2612 phdr_table_get_dynamic_section(phdr, phnum, load_bias, &dynamic, &dynamic_flags);
Dmitriy Ivanov498eb182014-09-05 14:57:59 -07002613
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002614 /* We can't log anything until the linker is relocated */
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002615 bool relocating_linker = (flags_ & FLAG_LINKER) != 0;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002616 if (!relocating_linker) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07002617 INFO("[ Linking \"%s\" ]", get_realpath());
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002618 DEBUG("si->base = %p si->flags = 0x%08x", reinterpret_cast<void*>(base), flags_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002619 }
2620
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002621 if (dynamic == nullptr) {
David 'Digit' Turnerb52e4382012-06-19 01:24:17 +02002622 if (!relocating_linker) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002623 DL_ERR("missing PT_DYNAMIC in \"%s\"", get_realpath());
David 'Digit' Turnerb52e4382012-06-19 01:24:17 +02002624 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002625 return false;
2626 } else {
2627 if (!relocating_linker) {
2628 DEBUG("dynamic = %p", dynamic);
David 'Digit' Turner63f99f42012-06-19 00:08:39 +02002629 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002630 }
David 'Digit' Turner63f99f42012-06-19 00:08:39 +02002631
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07002632#if defined(__arm__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002633 (void) phdr_table_get_arm_exidx(phdr, phnum, load_bias,
2634 &ARM_exidx, &ARM_exidx_count);
David 'Digit' Turner63f99f42012-06-19 00:08:39 +02002635#endif
2636
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002637 // Extract useful information from dynamic section.
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07002638 // Note that: "Except for the DT_NULL element at the end of the array,
2639 // and the relative order of DT_NEEDED elements, entries may appear in any order."
2640 //
2641 // source: http://www.sco.com/developers/gabi/1998-04-29/ch5.dynamic.html
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002642 uint32_t needed_count = 0;
2643 for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
2644 DEBUG("d = %p, d[0](tag) = %p d[1](val) = %p",
2645 d, reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
2646 switch (d->d_tag) {
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002647 case DT_SONAME:
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07002648 // this is parsed after we have strtab initialized (see below).
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002649 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002650
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002651 case DT_HASH:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002652 nbucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0];
2653 nchain_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
2654 bucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8);
2655 chain_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8 + nbucket_ * 4);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002656 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002657
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002658 case DT_GNU_HASH:
Dmitriy Ivanov3597b802015-03-09 12:02:02 -07002659 gnu_nbucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0];
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002660 // skip symndx
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002661 gnu_maskwords_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[2];
2662 gnu_shift2_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[3];
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002663
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002664 gnu_bloom_filter_ = reinterpret_cast<ElfW(Addr)*>(load_bias + d->d_un.d_ptr + 16);
Dmitriy Ivanov3597b802015-03-09 12:02:02 -07002665 gnu_bucket_ = reinterpret_cast<uint32_t*>(gnu_bloom_filter_ + gnu_maskwords_);
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002666 // amend chain for symndx = header[1]
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002667 gnu_chain_ = gnu_bucket_ + gnu_nbucket_ -
2668 reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002669
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002670 if (!powerof2(gnu_maskwords_)) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002671 DL_ERR("invalid maskwords for gnu_hash = 0x%x, in \"%s\" expecting power to two",
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002672 gnu_maskwords_, get_realpath());
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002673 return false;
2674 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002675 --gnu_maskwords_;
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002676
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002677 flags_ |= FLAG_GNU_HASH;
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002678 break;
2679
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002680 case DT_STRTAB:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002681 strtab_ = reinterpret_cast<const char*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002682 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002683
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07002684 case DT_STRSZ:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002685 strtab_size_ = d->d_un.d_val;
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07002686 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002687
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002688 case DT_SYMTAB:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002689 symtab_ = reinterpret_cast<ElfW(Sym)*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002690 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002691
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002692 case DT_SYMENT:
2693 if (d->d_un.d_val != sizeof(ElfW(Sym))) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002694 DL_ERR("invalid DT_SYMENT: %zd in \"%s\"",
2695 static_cast<size_t>(d->d_un.d_val), get_realpath());
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002696 return false;
2697 }
2698 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002699
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002700 case DT_PLTREL:
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002701#if defined(USE_RELA)
2702 if (d->d_un.d_val != DT_RELA) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002703 DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_RELA", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002704 return false;
2705 }
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002706#else
2707 if (d->d_un.d_val != DT_REL) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002708 DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_REL", get_realpath());
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002709 return false;
2710 }
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002711#endif
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002712 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002713
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002714 case DT_JMPREL:
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07002715#if defined(USE_RELA)
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002716 plt_rela_ = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002717#else
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002718 plt_rel_ = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002719#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002720 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002721
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002722 case DT_PLTRELSZ:
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07002723#if defined(USE_RELA)
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002724 plt_rela_count_ = d->d_un.d_val / sizeof(ElfW(Rela));
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002725#else
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002726 plt_rel_count_ = d->d_un.d_val / sizeof(ElfW(Rel));
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002727#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002728 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002729
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002730 case DT_PLTGOT:
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002731#if defined(__mips__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002732 // Used by mips and mips64.
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002733 plt_got_ = reinterpret_cast<ElfW(Addr)**>(load_bias + d->d_un.d_ptr);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002734#endif
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002735 // Ignore for other platforms... (because RTLD_LAZY is not supported)
2736 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002737
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002738 case DT_DEBUG:
2739 // Set the DT_DEBUG entry to the address of _r_debug for GDB
2740 // if the dynamic table is writable
Chris Dearman99186652014-02-06 20:36:51 -08002741// FIXME: not working currently for N64
2742// The flags for the LOAD and DYNAMIC program headers do not agree.
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002743// The LOAD section containing the dynamic table has been mapped as
Chris Dearman99186652014-02-06 20:36:51 -08002744// read-only, but the DYNAMIC header claims it is writable.
2745#if !(defined(__mips__) && defined(__LP64__))
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002746 if ((dynamic_flags & PF_W) != 0) {
2747 d->d_un.d_val = reinterpret_cast<uintptr_t>(&_r_debug);
2748 }
Chris Dearman99186652014-02-06 20:36:51 -08002749#endif
Dmitriy Ivanovc6292ea2015-02-13 16:29:50 -08002750 break;
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07002751#if defined(USE_RELA)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002752 case DT_RELA:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002753 rela_ = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002754 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002755
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002756 case DT_RELASZ:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002757 rela_count_ = d->d_un.d_val / sizeof(ElfW(Rela));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002758 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002759
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002760 case DT_ANDROID_RELA:
2761 android_relocs_ = reinterpret_cast<uint8_t*>(load_bias + d->d_un.d_ptr);
2762 break;
2763
2764 case DT_ANDROID_RELASZ:
2765 android_relocs_size_ = d->d_un.d_val;
2766 break;
2767
2768 case DT_ANDROID_REL:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002769 DL_ERR("unsupported DT_ANDROID_REL in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002770 return false;
2771
2772 case DT_ANDROID_RELSZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002773 DL_ERR("unsupported DT_ANDROID_RELSZ in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002774 return false;
2775
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002776 case DT_RELAENT:
2777 if (d->d_un.d_val != sizeof(ElfW(Rela))) {
Dmitriy Ivanovf240aa82014-09-16 23:34:20 -07002778 DL_ERR("invalid DT_RELAENT: %zd", static_cast<size_t>(d->d_un.d_val));
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002779 return false;
2780 }
2781 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002782
2783 // ignored (see DT_RELCOUNT comments for details)
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002784 case DT_RELACOUNT:
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002785 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002786
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002787 case DT_REL:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002788 DL_ERR("unsupported DT_REL in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002789 return false;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002790
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002791 case DT_RELSZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002792 DL_ERR("unsupported DT_RELSZ in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002793 return false;
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002794
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002795#else
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002796 case DT_REL:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002797 rel_ = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002798 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002799
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002800 case DT_RELSZ:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002801 rel_count_ = d->d_un.d_val / sizeof(ElfW(Rel));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002802 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002803
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002804 case DT_RELENT:
2805 if (d->d_un.d_val != sizeof(ElfW(Rel))) {
Dmitriy Ivanovf240aa82014-09-16 23:34:20 -07002806 DL_ERR("invalid DT_RELENT: %zd", static_cast<size_t>(d->d_un.d_val));
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002807 return false;
2808 }
2809 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002810
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002811 case DT_ANDROID_REL:
2812 android_relocs_ = reinterpret_cast<uint8_t*>(load_bias + d->d_un.d_ptr);
2813 break;
2814
2815 case DT_ANDROID_RELSZ:
2816 android_relocs_size_ = d->d_un.d_val;
2817 break;
2818
2819 case DT_ANDROID_RELA:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002820 DL_ERR("unsupported DT_ANDROID_RELA in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002821 return false;
2822
2823 case DT_ANDROID_RELASZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002824 DL_ERR("unsupported DT_ANDROID_RELASZ in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002825 return false;
2826
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002827 // "Indicates that all RELATIVE relocations have been concatenated together,
2828 // and specifies the RELATIVE relocation count."
2829 //
2830 // TODO: Spec also mentions that this can be used to optimize relocation process;
2831 // Not currently used by bionic linker - ignored.
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002832 case DT_RELCOUNT:
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002833 break;
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002834
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002835 case DT_RELA:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002836 DL_ERR("unsupported DT_RELA in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002837 return false;
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002838
2839 case DT_RELASZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002840 DL_ERR("unsupported DT_RELASZ in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002841 return false;
2842
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002843#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002844 case DT_INIT:
Dimitry Ivanov55437462016-07-20 15:33:07 -07002845 init_func_ = reinterpret_cast<linker_ctor_function_t>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002846 DEBUG("%s constructors (DT_INIT) found at %p", get_realpath(), init_func_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002847 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002848
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002849 case DT_FINI:
Dimitry Ivanov55437462016-07-20 15:33:07 -07002850 fini_func_ = reinterpret_cast<linker_dtor_function_t>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002851 DEBUG("%s destructors (DT_FINI) found at %p", get_realpath(), fini_func_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002852 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002853
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002854 case DT_INIT_ARRAY:
Dimitry Ivanov55437462016-07-20 15:33:07 -07002855 init_array_ = reinterpret_cast<linker_ctor_function_t*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002856 DEBUG("%s constructors (DT_INIT_ARRAY) found at %p", get_realpath(), init_array_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002857 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002858
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002859 case DT_INIT_ARRAYSZ:
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -08002860 init_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002861 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002862
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002863 case DT_FINI_ARRAY:
Dimitry Ivanov55437462016-07-20 15:33:07 -07002864 fini_array_ = reinterpret_cast<linker_dtor_function_t*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002865 DEBUG("%s destructors (DT_FINI_ARRAY) found at %p", get_realpath(), fini_array_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002866 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002867
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002868 case DT_FINI_ARRAYSZ:
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -08002869 fini_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002870 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002871
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002872 case DT_PREINIT_ARRAY:
Dimitry Ivanov55437462016-07-20 15:33:07 -07002873 preinit_array_ = reinterpret_cast<linker_ctor_function_t*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002874 DEBUG("%s constructors (DT_PREINIT_ARRAY) found at %p", get_realpath(), preinit_array_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002875 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002876
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002877 case DT_PREINIT_ARRAYSZ:
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -08002878 preinit_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002879 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002880
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002881 case DT_TEXTREL:
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00002882#if defined(__LP64__)
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002883 DL_ERR("text relocations (DT_TEXTREL) found in 64-bit ELF file \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002884 return false;
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00002885#else
2886 has_text_relocations = true;
2887 break;
2888#endif
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002889
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002890 case DT_SYMBOLIC:
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -07002891 has_DT_SYMBOLIC = true;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002892 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002893
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002894 case DT_NEEDED:
2895 ++needed_count;
2896 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002897
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002898 case DT_FLAGS:
2899 if (d->d_un.d_val & DF_TEXTREL) {
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00002900#if defined(__LP64__)
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002901 DL_ERR("text relocations (DF_TEXTREL) found in 64-bit ELF file \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002902 return false;
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00002903#else
2904 has_text_relocations = true;
2905#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002906 }
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -07002907 if (d->d_un.d_val & DF_SYMBOLIC) {
2908 has_DT_SYMBOLIC = true;
2909 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002910 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002911
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07002912 case DT_FLAGS_1:
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07002913 set_dt_flags_1(d->d_un.d_val);
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -07002914
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07002915 if ((d->d_un.d_val & ~SUPPORTED_DT_FLAGS_1) != 0) {
Dmitriy Ivanov087005f2015-05-28 11:44:31 -07002916 DL_WARN("%s: unsupported flags DT_FLAGS_1=%p", get_realpath(), reinterpret_cast<void*>(d->d_un.d_val));
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07002917 }
2918 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002919#if defined(__mips__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002920 case DT_MIPS_RLD_MAP:
2921 // Set the DT_MIPS_RLD_MAP entry to the address of _r_debug for GDB.
2922 {
2923 r_debug** dp = reinterpret_cast<r_debug**>(load_bias + d->d_un.d_ptr);
2924 *dp = &_r_debug;
2925 }
2926 break;
Lazar Trsic83b44a92016-04-06 13:39:17 +02002927 case DT_MIPS_RLD_MAP_REL:
2928 // Set the DT_MIPS_RLD_MAP_REL entry to the address of _r_debug for GDB.
Raghu Gandham68815722014-12-18 19:12:19 -08002929 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002930 r_debug** dp = reinterpret_cast<r_debug**>(
2931 reinterpret_cast<ElfW(Addr)>(d) + d->d_un.d_val);
Raghu Gandham68815722014-12-18 19:12:19 -08002932 *dp = &_r_debug;
2933 }
2934 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002935
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002936 case DT_MIPS_RLD_VERSION:
2937 case DT_MIPS_FLAGS:
2938 case DT_MIPS_BASE_ADDRESS:
2939 case DT_MIPS_UNREFEXTNO:
2940 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002941
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002942 case DT_MIPS_SYMTABNO:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002943 mips_symtabno_ = d->d_un.d_val;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002944 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002945
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002946 case DT_MIPS_LOCAL_GOTNO:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002947 mips_local_gotno_ = d->d_un.d_val;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002948 break;
2949
2950 case DT_MIPS_GOTSYM:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002951 mips_gotsym_ = d->d_un.d_val;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002952 break;
2953#endif
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002954 // Ignored: "Its use has been superseded by the DF_BIND_NOW flag"
2955 case DT_BIND_NOW:
2956 break;
2957
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002958 case DT_VERSYM:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002959 versym_ = reinterpret_cast<ElfW(Versym)*>(load_bias + d->d_un.d_ptr);
2960 break;
2961
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002962 case DT_VERDEF:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002963 verdef_ptr_ = load_bias + d->d_un.d_ptr;
2964 break;
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002965 case DT_VERDEFNUM:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002966 verdef_cnt_ = d->d_un.d_val;
2967 break;
2968
Alexander Ivchenkoe8314332014-12-02 15:32:25 +03002969 case DT_VERNEED:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002970 verneed_ptr_ = load_bias + d->d_un.d_ptr;
2971 break;
2972
Alexander Ivchenkoe8314332014-12-02 15:32:25 +03002973 case DT_VERNEEDNUM:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002974 verneed_cnt_ = d->d_un.d_val;
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002975 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002976
Evgenii Stepanov68650822015-06-10 13:38:39 -07002977 case DT_RUNPATH:
2978 // this is parsed after we have strtab initialized (see below).
2979 break;
2980
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002981 default:
Dmitriy Ivanov8f61d992014-09-16 14:31:06 -07002982 if (!relocating_linker) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002983 DL_WARN("%s: unused DT entry: type %p arg %p", get_realpath(),
Dmitriy Ivanov8f61d992014-09-16 14:31:06 -07002984 reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
2985 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002986 break;
Brian Carlstromd4ee82d2013-02-28 15:58:45 -08002987 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002988 }
2989
Duane Sandbc425c72015-06-01 16:29:14 -07002990#if defined(__mips__) && !defined(__LP64__)
2991 if (!mips_check_and_adjust_fp_modes()) {
2992 return false;
2993 }
2994#endif
2995
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002996 DEBUG("si->base = %p, si->strtab = %p, si->symtab = %p",
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002997 reinterpret_cast<void*>(base), strtab_, symtab_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002998
2999 // Sanity checks.
3000 if (relocating_linker && needed_count != 0) {
3001 DL_ERR("linker cannot have DT_NEEDED dependencies on other libraries");
3002 return false;
3003 }
Dmitriy Ivanov3597b802015-03-09 12:02:02 -07003004 if (nbucket_ == 0 && gnu_nbucket_ == 0) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003005 DL_ERR("empty/missing DT_HASH/DT_GNU_HASH in \"%s\" "
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003006 "(new hash type from the future?)", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003007 return false;
3008 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003009 if (strtab_ == 0) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003010 DL_ERR("empty/missing DT_STRTAB in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003011 return false;
3012 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003013 if (symtab_ == 0) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003014 DL_ERR("empty/missing DT_SYMTAB in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003015 return false;
3016 }
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003017
Dmitriy Ivanov624b8f12015-06-08 10:41:33 -07003018 // second pass - parse entries relying on strtab
3019 for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
Evgenii Stepanov68650822015-06-10 13:38:39 -07003020 switch (d->d_tag) {
3021 case DT_SONAME:
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07003022 set_soname(get_string(d->d_un.d_val));
Evgenii Stepanov68650822015-06-10 13:38:39 -07003023 break;
3024 case DT_RUNPATH:
Evgenii Stepanov68650822015-06-10 13:38:39 -07003025 set_dt_runpath(get_string(d->d_un.d_val));
3026 break;
Dmitriy Ivanov624b8f12015-06-08 10:41:33 -07003027 }
3028 }
3029
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003030 // Before M release linker was using basename in place of soname.
Dmitriy Ivanov19133522015-06-02 17:36:54 -07003031 // In the case when dt_soname is absent some apps stop working
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003032 // because they can't find dt_needed library by soname.
3033 // This workaround should keep them working. (applies only
Dmitriy Ivanov19133522015-06-02 17:36:54 -07003034 // for apps targeting sdk version <=22). Make an exception for
3035 // the main executable and linker; they do not need to have dt_soname
Dimitry Ivanov3f660572016-09-09 10:00:39 -07003036 if (soname_ == nullptr &&
3037 this != solist_get_somain() &&
3038 (flags_ & FLAG_LINKER) == 0 &&
Dmitriy Ivanov19133522015-06-02 17:36:54 -07003039 get_application_target_sdk_version() <= 22) {
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003040 soname_ = basename(realpath_.c_str());
3041 DL_WARN("%s: is missing DT_SONAME will use basename as a replacement: \"%s\"",
3042 get_realpath(), soname_);
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07003043 // 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 -07003044 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003045 return true;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07003046}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003047
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003048bool soinfo::link_image(const soinfo_list_t& global_group, const soinfo_list_t& local_group,
3049 const android_dlextinfo* extinfo) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003050
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08003051 local_group_root_ = local_group.front();
3052 if (local_group_root_ == nullptr) {
3053 local_group_root_ = this;
3054 }
3055
Dmitriy Ivanov19133522015-06-02 17:36:54 -07003056 if ((flags_ & FLAG_LINKER) == 0 && local_group_root_ == this) {
3057 target_sdk_version_ = get_application_target_sdk_version();
3058 }
3059
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003060 VersionTracker version_tracker;
3061
3062 if (!version_tracker.init(this)) {
3063 return false;
3064 }
3065
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003066#if !defined(__LP64__)
3067 if (has_text_relocations) {
Dmitriy Ivanove4ad91f2015-06-12 15:00:31 -07003068 // Fail if app is targeting sdk version > 22
Dmitriy Ivanov80687862015-10-09 13:58:46 -07003069 if (get_application_target_sdk_version() > 22) {
Dmitriy Ivanovfae39d22015-10-13 11:07:56 -07003070 PRINT("%s: has text relocations", get_realpath());
Dmitriy Ivanove4ad91f2015-06-12 15:00:31 -07003071 DL_ERR("%s: has text relocations", get_realpath());
3072 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 Ivanov56be6ed2015-04-01 21:18:48 +00003076 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
3218 std::vector<std::string> ld_default_paths;
3219 for (size_t i = 0; g_default_ld_paths[i] != nullptr; ++i) {
3220 ld_default_paths.push_back(g_default_ld_paths[i]);
3221 }
3222
3223 g_default_namespace.set_default_library_paths(std::move(ld_default_paths));
Evgenii Stepanovd640b222015-07-10 17:54:01 -07003224};
3225