blob: 96f424e74fff64b5a4322f0eb190332f26d5983c [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>
Dimitry Ivanovbf34ba32017-04-21 13:12:05 -070039#include <sys/vfs.h>
Elliott Hughes46882792012-08-03 16:49:39 -070040#include <unistd.h>
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080041
Dmitriy Ivanov0d150942014-08-22 12:25:04 -070042#include <new>
Dmitriy Ivanovd165f562015-03-23 18:43:02 -070043#include <string>
Dmitriy Ivanovb4827502015-09-28 16:38:31 -070044#include <unordered_map>
Dmitriy Ivanovd165f562015-03-23 18:43:02 -070045#include <vector>
Dmitriy Ivanov0d150942014-08-22 12:25:04 -070046
Tom Cherryb8ab6182017-04-05 16:20:29 -070047#include <android-base/scopeguard.h>
48
Christopher Ferris7a3681e2017-04-24 17:48:32 -070049#include <async_safe/log.h>
50
Elliott Hughes46882792012-08-03 16:49:39 -070051// Private C library headers.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080052
53#include "linker.h"
Dmitriy Ivanovc9ce70d2015-03-10 15:30:26 -070054#include "linker_block_allocator.h"
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -070055#include "linker_cfi.h"
Dimitry Ivanov4cabfaa2017-03-07 11:19:05 -080056#include "linker_config.h"
Dimitry Ivanov6b788ee2016-02-17 16:08:03 -080057#include "linker_gdb_support.h"
Dimitry Ivanov48ec2882016-08-04 11:50:36 -070058#include "linker_globals.h"
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080059#include "linker_debug.h"
Dimitry Ivanov769b33f2016-07-21 11:33:40 -070060#include "linker_dlwarning.h"
Dimitry Ivanov3f660572016-09-09 10:00:39 -070061#include "linker_main.h"
Dimitry Ivanovb943f302016-08-03 16:00:10 -070062#include "linker_namespaces.h"
Dmitriy Ivanov18870d32015-04-22 13:10:04 -070063#include "linker_sleb128.h"
David 'Digit' Turner23363ed2012-06-18 18:13:49 +020064#include "linker_phdr.h"
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -080065#include "linker_relocs.h"
Dmitriy Ivanovfa26eee2015-02-03 16:06:47 -080066#include "linker_reloc_iterators.h"
Dmitriy Ivanova1feb112015-10-01 18:41:57 -070067#include "linker_utils.h"
tony.ys_liub4474402015-07-29 18:00:22 +080068
dimitryfe1b27c2017-08-11 14:43:21 +020069#include "android-base/macros.h"
Elliott Hughes939a7e02015-12-04 15:27:46 -080070#include "android-base/strings.h"
Dimitry Ivanovb996d602016-07-11 18:11:39 -070071#include "android-base/stringprintf.h"
Simon Baldwinaef71952015-01-16 13:22:54 +000072#include "ziparchive/zip_archive.h"
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080073
dimitry06016f22018-01-05 11:39:28 +010074static std::unordered_map<void*, size_t> g_dso_handle_counters;
75
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -070076static android_namespace_t* g_anonymous_namespace = &g_default_namespace;
Jiyong Park01de74e2017-04-03 23:10:37 +090077static std::unordered_map<std::string, android_namespace_t*> g_exported_namespaces;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -070078
Dmitriy Ivanov600bc3c2015-03-10 15:43:50 -070079static LinkerTypeAllocator<soinfo> g_soinfo_allocator;
80static LinkerTypeAllocator<LinkedListEntry<soinfo>> g_soinfo_links_allocator;
Magnus Malmbornba98d922012-09-12 13:00:55 +020081
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -070082static LinkerTypeAllocator<android_namespace_t> g_namespace_allocator;
Dimitry Ivanovaca299a2016-04-11 12:42:58 -070083static LinkerTypeAllocator<LinkedListEntry<android_namespace_t>> g_namespace_list_allocator;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -070084
dimitryfe1b27c2017-08-11 14:43:21 +020085static const char* const kLdConfigArchFilePath = "/system/etc/ld.config." ABI_STRING ".txt";
86
Dimitry Ivanov4cabfaa2017-03-07 11:19:05 -080087static const char* const kLdConfigFilePath = "/system/etc/ld.config.txt";
88
Elliott Hughes4eeb1f12013-10-25 17:38:02 -070089#if defined(__LP64__)
Dimitry Ivanova1446972017-03-17 00:08:23 +000090static const char* const kSystemLibDir = "/system/lib64";
Alin Jerpelea074a9fd2017-09-25 17:47:49 +020091static const char* const kOdmLibDir = "/odm/lib64";
Dimitry Ivanova1446972017-03-17 00:08:23 +000092static const char* const kVendorLibDir = "/vendor/lib64";
Vishwath Mohan4113def2017-03-29 15:31:34 -070093static const char* const kAsanSystemLibDir = "/data/asan/system/lib64";
Alin Jerpelea074a9fd2017-09-25 17:47:49 +020094static const char* const kAsanOdmLibDir = "/data/asan/odm/lib64";
Vishwath Mohan4113def2017-03-29 15:31:34 -070095static const char* const kAsanVendorLibDir = "/data/asan/vendor/lib64";
Elliott Hughes011bc0b2013-10-08 14:27:10 -070096#else
Dimitry Ivanova1446972017-03-17 00:08:23 +000097static const char* const kSystemLibDir = "/system/lib";
Alin Jerpelea074a9fd2017-09-25 17:47:49 +020098static const char* const kOdmLibDir = "/odm/lib";
Dimitry Ivanova1446972017-03-17 00:08:23 +000099static const char* const kVendorLibDir = "/vendor/lib";
Vishwath Mohan4113def2017-03-29 15:31:34 -0700100static const char* const kAsanSystemLibDir = "/data/asan/system/lib";
Alin Jerpelea074a9fd2017-09-25 17:47:49 +0200101static const char* const kAsanOdmLibDir = "/data/asan/odm/lib";
Vishwath Mohan4113def2017-03-29 15:31:34 -0700102static const char* const kAsanVendorLibDir = "/data/asan/vendor/lib";
Elliott Hughes011bc0b2013-10-08 14:27:10 -0700103#endif
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700104
Vishwath Mohan4113def2017-03-29 15:31:34 -0700105static const char* const kAsanLibDirPrefix = "/data/asan";
106
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700107static const char* const kDefaultLdPaths[] = {
108 kSystemLibDir,
Alin Jerpelea074a9fd2017-09-25 17:47:49 +0200109 kOdmLibDir,
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700110 kVendorLibDir,
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700111 nullptr
Elliott Hughes124fae92012-10-31 14:20:03 -0700112};
David Bartleybc3a5c22009-06-02 18:27:28 -0700113
Evgenii Stepanovd640b222015-07-10 17:54:01 -0700114static const char* const kAsanDefaultLdPaths[] = {
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700115 kAsanSystemLibDir,
116 kSystemLibDir,
Alin Jerpelea074a9fd2017-09-25 17:47:49 +0200117 kAsanOdmLibDir,
118 kOdmLibDir,
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700119 kAsanVendorLibDir,
120 kVendorLibDir,
Evgenii Stepanovd640b222015-07-10 17:54:01 -0700121 nullptr
122};
123
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700124// Is ASAN enabled?
125static bool g_is_asan = false;
126
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -0700127static CFIShadowWriter g_cfi_shadow;
128
129CFIShadowWriter* get_cfi_shadow() {
130 return &g_cfi_shadow;
131}
132
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700133static bool is_system_library(const std::string& realpath) {
134 for (const auto& dir : g_default_namespace.get_default_library_paths()) {
135 if (file_is_in_dir(realpath, dir)) {
136 return true;
137 }
138 }
139 return false;
140}
141
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700142// Checks if the file exists and not a directory.
143static bool file_exists(const char* path) {
Dimitry Ivanov4cf70242016-08-11 11:11:52 -0700144 struct stat s;
145
146 if (stat(path, &s) != 0) {
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700147 return false;
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700148 }
Dimitry Ivanov4cf70242016-08-11 11:11:52 -0700149
150 return S_ISREG(s.st_mode);
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700151}
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700152
Dimitry Ivanov35c8e3b2017-02-27 12:17:47 -0800153static std::string resolve_soname(const std::string& name) {
154 // We assume that soname equals to basename here
155
156 // TODO(dimitry): consider having honest absolute-path -> soname resolution
157 // note that since we might end up refusing to load this library because
158 // it is not in shared libs list we need to get the soname without actually loading
159 // the library.
160 //
161 // On the other hand there are several places where we already assume that
162 // soname == basename in particular for any not-loaded library mentioned
163 // in DT_NEEDED list.
164 return basename(name.c_str());
165}
166
167static bool maybe_accessible_via_namespace_links(android_namespace_t* ns, const char* name) {
168 std::string soname = resolve_soname(name);
169 for (auto& ns_link : ns->linked_namespaces()) {
170 if (ns_link.is_accessible(soname.c_str())) {
171 return true;
172 }
173 }
174
175 return false;
176}
177
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700178// TODO(dimitry): The grey-list is a workaround for http://b/26394120 ---
179// gradually remove libraries from this list until it is gone.
Dimitry Ivanov35c8e3b2017-02-27 12:17:47 -0800180static bool is_greylisted(android_namespace_t* ns, const char* name, const soinfo* needed_by) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700181 static const char* const kLibraryGreyList[] = {
182 "libandroid_runtime.so",
183 "libbinder.so",
184 "libcrypto.so",
185 "libcutils.so",
186 "libexpat.so",
187 "libgui.so",
188 "libmedia.so",
189 "libnativehelper.so",
190 "libskia.so",
191 "libssl.so",
192 "libstagefright.so",
193 "libsqlite.so",
194 "libui.so",
195 "libutils.so",
196 "libvorbisidec.so",
197 nullptr
198 };
199
Elliott Hughes5bc78c82016-11-16 11:35:43 -0800200 // If you're targeting N, you don't get the greylist.
Elliott Hughes9e27e582017-03-23 17:42:49 -0700201 if (g_greylist_disabled || get_application_target_sdk_version() >= __ANDROID_API_N__) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700202 return false;
203 }
204
205 // if the library needed by a system library - implicitly assume it
Dimitry Ivanov35c8e3b2017-02-27 12:17:47 -0800206 // is greylisted unless it is in the list of shared libraries for one or
207 // more linked namespaces
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700208 if (needed_by != nullptr && is_system_library(needed_by->get_realpath())) {
Dimitry Ivanov35c8e3b2017-02-27 12:17:47 -0800209 return !maybe_accessible_via_namespace_links(ns, name);
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700210 }
211
212 // if this is an absolute path - make sure it points to /system/lib(64)
213 if (name[0] == '/' && dirname(name) == kSystemLibDir) {
214 // and reduce the path to basename
215 name = basename(name);
216 }
217
218 for (size_t i = 0; kLibraryGreyList[i] != nullptr; ++i) {
219 if (strcmp(name, kLibraryGreyList[i]) == 0) {
220 return true;
221 }
222 }
223
224 return false;
225}
226// END OF WORKAROUND
227
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700228static std::vector<std::string> g_ld_preload_names;
Elliott Hughesa4aafd12014-01-13 16:37:47 -0800229
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800230static bool g_anonymous_namespace_initialized;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700231
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800232#if STATS
Elliott Hughesbedfe382012-08-14 14:07:59 -0700233struct linker_stats_t {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700234 int count[kRelocMax];
Elliott Hughesbedfe382012-08-14 14:07:59 -0700235};
236
237static linker_stats_t linker_stats;
238
Dmitriy Ivanov114ff692015-01-14 11:36:38 -0800239void count_relocation(RelocationKind kind) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700240 ++linker_stats.count[kind];
Elliott Hughesbedfe382012-08-14 14:07:59 -0700241}
242#else
Dmitriy Ivanov114ff692015-01-14 11:36:38 -0800243void count_relocation(RelocationKind) {
Elliott Hughesbedfe382012-08-14 14:07:59 -0700244}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800245#endif
246
247#if COUNT_PAGES
Dmitriy Ivanov114ff692015-01-14 11:36:38 -0800248uint32_t bitmask[4096];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800249#endif
250
Elliott Hughesbedfe382012-08-14 14:07:59 -0700251static void notify_gdb_of_load(soinfo* info) {
Dimitry Ivanove97d8ed2016-03-01 15:55:56 -0800252 if (info->is_linker() || info->is_main_executable()) {
253 // gdb already knows about the linker and the main executable.
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700254 return;
255 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800256
Dimitry Ivanov6b788ee2016-02-17 16:08:03 -0800257 link_map* map = &(info->link_map_head);
Nicolas Geoffray0fa54102016-02-18 09:31:24 +0000258
Dimitry Ivanov6b788ee2016-02-17 16:08:03 -0800259 map->l_addr = info->load_bias;
260 // link_map l_name field is not const.
261 map->l_name = const_cast<char*>(info->get_realpath());
262 map->l_ld = info->dynamic;
Nicolas Geoffray0fa54102016-02-18 09:31:24 +0000263
Dimitry Ivanove97d8ed2016-03-01 15:55:56 -0800264 CHECK(map->l_name != nullptr);
265 CHECK(map->l_name[0] != '\0');
266
Dimitry Ivanov6b788ee2016-02-17 16:08:03 -0800267 notify_gdb_of_load(map);
Iliyan Malchev5e12d7e2009-03-24 19:02:00 -0700268}
269
Elliott Hughesbedfe382012-08-14 14:07:59 -0700270static void notify_gdb_of_unload(soinfo* info) {
Dimitry Ivanov6b788ee2016-02-17 16:08:03 -0800271 notify_gdb_of_unload(&(info->link_map_head));
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800272}
273
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -0700274LinkedListEntry<soinfo>* SoinfoListAllocator::alloc() {
275 return g_soinfo_links_allocator.alloc();
276}
277
278void SoinfoListAllocator::free(LinkedListEntry<soinfo>* entry) {
279 g_soinfo_links_allocator.free(entry);
280}
281
Dimitry Ivanovaca299a2016-04-11 12:42:58 -0700282LinkedListEntry<android_namespace_t>* NamespaceListAllocator::alloc() {
283 return g_namespace_list_allocator.alloc();
284}
285
286void NamespaceListAllocator::free(LinkedListEntry<android_namespace_t>* entry) {
287 g_namespace_list_allocator.free(entry);
288}
289
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700290soinfo* soinfo_alloc(android_namespace_t* ns, const char* name,
291 struct stat* file_stat, off64_t file_offset,
292 uint32_t rtld_flags) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700293 if (strlen(name) >= PATH_MAX) {
Elliott Hughes7b0af7a2017-09-15 16:09:22 -0700294 async_safe_fatal("library name \"%s\" too long", name);
Magnus Malmbornba98d922012-09-12 13:00:55 +0200295 }
296
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700297 TRACE("name %s: allocating soinfo for ns=%p", name, ns);
298
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700299 soinfo* si = new (g_soinfo_allocator.alloc()) soinfo(ns, name, file_stat,
300 file_offset, rtld_flags);
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -0700301
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700302 solist_add_soinfo(si);
Magnus Malmbornba98d922012-09-12 13:00:55 +0200303
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -0700304 si->generate_handle();
305 ns->add_soinfo(si);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700306
Elliott Hughesca0c11b2013-03-12 10:40:45 -0700307 TRACE("name %s: allocated soinfo @ %p", name, si);
Magnus Malmbornba98d922012-09-12 13:00:55 +0200308 return si;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800309}
310
Elliott Hughesfaf05ba2014-02-11 16:59:37 -0800311static void soinfo_free(soinfo* si) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700312 if (si == nullptr) {
313 return;
314 }
315
316 if (si->base != 0 && si->size != 0) {
Dimitry Ivanovf45b0e92016-01-15 11:13:35 -0800317 if (!si->is_mapped_by_caller()) {
318 munmap(reinterpret_cast<void*>(si->base), si->size);
319 } else {
320 // remap the region as PROT_NONE, MAP_ANONYMOUS | MAP_NORESERVE
321 mmap(reinterpret_cast<void*>(si->base), si->size, PROT_NONE,
322 MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
323 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700324 }
325
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700326 TRACE("name %s: freeing soinfo @ %p", si->get_realpath(), si);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700327
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700328 if (!solist_remove_soinfo(si)) {
dimitry965d06d2017-11-28 16:03:07 +0100329 async_safe_fatal("soinfo=%p is not in soinfo_list (double unload?)", si);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700330 }
Elliott Hughes46882792012-08-03 16:49:39 -0700331
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700332 // clear links to/from si
333 si->remove_all_links();
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -0700334
Dmitriy Ivanov609f11b2015-07-08 15:26:46 -0700335 si->~soinfo();
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700336 g_soinfo_allocator.free(si);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800337}
338
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700339static void parse_path(const char* path, const char* delimiters,
340 std::vector<std::string>* resolved_paths) {
341 std::vector<std::string> paths;
342 split_path(path, delimiters, &paths);
343 resolve_paths(paths, resolved_paths);
344}
345
Elliott Hughescade4c32012-12-20 14:42:14 -0800346static void parse_LD_LIBRARY_PATH(const char* path) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700347 std::vector<std::string> ld_libary_paths;
348 parse_path(path, ":", &ld_libary_paths);
349 g_default_namespace.set_ld_library_paths(std::move(ld_libary_paths));
Elliott Hughescade4c32012-12-20 14:42:14 -0800350}
351
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700352static bool realpath_fd(int fd, std::string* realpath) {
353 std::vector<char> buf(PATH_MAX), proc_self_fd(PATH_MAX);
Christopher Ferris7a3681e2017-04-24 17:48:32 -0700354 async_safe_format_buffer(&proc_self_fd[0], proc_self_fd.size(), "/proc/self/fd/%d", fd);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700355 if (readlink(&proc_self_fd[0], &buf[0], buf.size()) == -1) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700356 PRINT("readlink(\"%s\") failed: %s [fd=%d]", &proc_self_fd[0], strerror(errno), fd);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700357 return false;
358 }
359
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700360 *realpath = &buf[0];
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700361 return true;
362}
363
Elliott Hughes4eeb1f12013-10-25 17:38:02 -0700364#if defined(__arm__)
Elliott Hughes46882792012-08-03 16:49:39 -0700365
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700366// For a given PC, find the .so that it belongs to.
367// Returns the base address of the .ARM.exidx section
368// for that .so, and the number of 8-byte entries
369// in that section (via *pcount).
370//
371// Intended to be called by libc's __gnu_Unwind_Find_exidx().
Dimitry Ivanovd9e427c2016-11-22 16:55:25 -0800372_Unwind_Ptr do_dl_unwind_find_exidx(_Unwind_Ptr pc, int* pcount) {
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700373 for (soinfo* si = solist_get_head(); si != 0; si = si->next) {
Elliott Hughesf2c6ad62017-04-21 10:25:56 -0700374 if ((pc >= si->base) && (pc < (si->base + si->size))) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700375 *pcount = si->ARM_exidx_count;
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -0800376 return reinterpret_cast<_Unwind_Ptr>(si->ARM_exidx);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800377 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700378 }
379 *pcount = 0;
Elliott Hughesf2c6ad62017-04-21 10:25:56 -0700380 return 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800381}
Elliott Hughes46882792012-08-03 16:49:39 -0700382
Christopher Ferris24053a42013-08-19 17:45:09 -0700383#endif
Elliott Hughes46882792012-08-03 16:49:39 -0700384
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700385// Here, we only have to provide a callback to iterate across all the
386// loaded libraries. gcc_eh does the rest.
Dmitriy Ivanov7271caf2015-06-29 14:48:25 -0700387int do_dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void* data) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700388 int rv = 0;
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700389 for (soinfo* si = solist_get_head(); si != nullptr; si = si->next) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700390 dl_phdr_info dl_info;
391 dl_info.dlpi_addr = si->link_map_head.l_addr;
392 dl_info.dlpi_name = si->link_map_head.l_name;
393 dl_info.dlpi_phdr = si->phdr;
394 dl_info.dlpi_phnum = si->phnum;
395 rv = cb(&dl_info, sizeof(dl_phdr_info), data);
396 if (rv != 0) {
397 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800398 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700399 }
400 return rv;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800401}
Elliott Hughes46882792012-08-03 16:49:39 -0700402
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800403
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700404bool soinfo_do_lookup(soinfo* si_from, const char* name, const version_info* vi,
Dimitry Ivanovb943f302016-08-03 16:00:10 -0700405 soinfo** si_found_in, const soinfo_list_t& global_group,
406 const soinfo_list_t& local_group, const ElfW(Sym)** symbol) {
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800407 SymbolName symbol_name(name);
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700408 const ElfW(Sym)* s = nullptr;
Iliyan Malchev6ed80c82009-09-28 19:38:04 -0700409
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -0700410 /* "This element's presence in a shared object library alters the dynamic linker's
411 * symbol resolution algorithm for references within the library. Instead of starting
412 * a symbol search with the executable file, the dynamic linker starts from the shared
413 * object itself. If the shared object fails to supply the referenced symbol, the
414 * dynamic linker then searches the executable file and other shared objects as usual."
415 *
416 * http://www.sco.com/developers/gabi/2012-12-31/ch5.dynamic.html
417 *
418 * Note that this is unlikely since static linker avoids generating
419 * relocations for -Bsymbolic linked dynamic executables.
420 */
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700421 if (si_from->has_DT_SYMBOLIC) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700422 DEBUG("%s: looking up %s in local scope (DT_SYMBOLIC)", si_from->get_realpath(), name);
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700423 if (!si_from->find_symbol_by_name(symbol_name, vi, &s)) {
424 return false;
425 }
426
Dmitriy Ivanov8f61d992014-09-16 14:31:06 -0700427 if (s != nullptr) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700428 *si_found_in = si_from;
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -0700429 }
430 }
431
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700432 // 1. Look for it in global_group
433 if (s == nullptr) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700434 bool error = false;
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700435 global_group.visit([&](soinfo* global_si) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700436 DEBUG("%s: looking up %s in %s (from global group)",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700437 si_from->get_realpath(), name, global_si->get_realpath());
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700438 if (!global_si->find_symbol_by_name(symbol_name, vi, &s)) {
439 error = true;
440 return false;
441 }
442
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -0700443 if (s != nullptr) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700444 *si_found_in = global_si;
445 return false;
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -0700446 }
Dmitriy Ivanovc2048942014-08-29 10:15:25 -0700447
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700448 return true;
449 });
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700450
451 if (error) {
452 return false;
453 }
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -0700454 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700455
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700456 // 2. Look for it in the local group
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700457 if (s == nullptr) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700458 bool error = false;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700459 local_group.visit([&](soinfo* local_si) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700460 if (local_si == si_from && si_from->has_DT_SYMBOLIC) {
Dmitriy Ivanove47b3f82014-10-23 14:19:07 -0700461 // we already did this - skip
462 return true;
463 }
464
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700465 DEBUG("%s: looking up %s in %s (from local group)",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700466 si_from->get_realpath(), name, local_si->get_realpath());
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700467 if (!local_si->find_symbol_by_name(symbol_name, vi, &s)) {
468 error = true;
469 return false;
470 }
471
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700472 if (s != nullptr) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700473 *si_found_in = local_si;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700474 return false;
475 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700476
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700477 return true;
478 });
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700479
480 if (error) {
481 return false;
482 }
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700483 }
484
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700485 if (s != nullptr) {
486 TRACE_TYPE(LOOKUP, "si %s sym %s s->st_value = %p, "
487 "found in %s, base = %p, load bias = %p",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700488 si_from->get_realpath(), name, reinterpret_cast<void*>(s->st_value),
489 (*si_found_in)->get_realpath(), reinterpret_cast<void*>((*si_found_in)->base),
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700490 reinterpret_cast<void*>((*si_found_in)->load_bias));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700491 }
Iliyan Malchev6ed80c82009-09-28 19:38:04 -0700492
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700493 *symbol = s;
494 return true;
Iliyan Malchev6ed80c82009-09-28 19:38:04 -0700495}
496
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700497ProtectedDataGuard::ProtectedDataGuard() {
498 if (ref_count_++ == 0) {
499 protect_data(PROT_READ | PROT_WRITE);
500 }
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700501
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700502 if (ref_count_ == 0) { // overflow
Christopher Ferris7a3681e2017-04-24 17:48:32 -0700503 async_safe_fatal("Too many nested calls to dlopen()");
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -0800504 }
Dimitry Ivanov68e6c032017-02-01 12:55:11 -0800505}
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -0800506
Dimitry Ivanov68e6c032017-02-01 12:55:11 -0800507ProtectedDataGuard::~ProtectedDataGuard() {
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700508 if (--ref_count_ == 0) {
509 protect_data(PROT_READ);
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -0800510 }
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700511}
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -0800512
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700513void ProtectedDataGuard::protect_data(int protection) {
514 g_soinfo_allocator.protect_all(protection);
515 g_soinfo_links_allocator.protect_all(protection);
516 g_namespace_allocator.protect_all(protection);
517 g_namespace_list_allocator.protect_all(protection);
518}
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -0800519
520size_t ProtectedDataGuard::ref_count_ = 0;
521
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700522// Each size has it's own allocator.
523template<size_t size>
524class SizeBasedAllocator {
525 public:
526 static void* alloc() {
527 return allocator_.alloc();
528 }
Dmitriy Ivanov4bea4982014-08-29 14:01:48 -0700529
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700530 static void free(void* ptr) {
531 allocator_.free(ptr);
532 }
Dmitriy Ivanov4bea4982014-08-29 14:01:48 -0700533
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700534 private:
535 static LinkerBlockAllocator allocator_;
536};
537
538template<size_t size>
539LinkerBlockAllocator SizeBasedAllocator<size>::allocator_(size);
540
541template<typename T>
542class TypeBasedAllocator {
543 public:
544 static T* alloc() {
545 return reinterpret_cast<T*>(SizeBasedAllocator<sizeof(T)>::alloc());
546 }
547
548 static void free(T* ptr) {
549 SizeBasedAllocator<sizeof(T)>::free(ptr);
550 }
551};
552
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700553class LoadTask {
554 public:
555 struct deleter_t {
556 void operator()(LoadTask* t) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700557 t->~LoadTask();
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700558 TypeBasedAllocator<LoadTask>::free(t);
559 }
560 };
561
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700562 static deleter_t deleter;
563
Dimitry Ivanov7d429d32017-02-01 15:28:52 -0800564 static LoadTask* create(const char* name,
565 soinfo* needed_by,
Jiyong Park02586a22017-05-20 01:01:24 +0900566 android_namespace_t* start_from,
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700567 std::unordered_map<const soinfo*, ElfReader>* readers_map) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700568 LoadTask* ptr = TypeBasedAllocator<LoadTask>::alloc();
Jiyong Park02586a22017-05-20 01:01:24 +0900569 return new (ptr) LoadTask(name, needed_by, start_from, readers_map);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700570 }
571
572 const char* get_name() const {
573 return name_;
574 }
575
576 soinfo* get_needed_by() const {
577 return needed_by_;
578 }
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700579
580 soinfo* get_soinfo() const {
581 return si_;
582 }
583
584 void set_soinfo(soinfo* si) {
585 si_ = si;
586 }
587
588 off64_t get_file_offset() const {
589 return file_offset_;
590 }
591
592 void set_file_offset(off64_t offset) {
593 file_offset_ = offset;
594 }
595
596 int get_fd() const {
597 return fd_;
598 }
599
600 void set_fd(int fd, bool assume_ownership) {
601 fd_ = fd;
602 close_fd_ = assume_ownership;
603 }
604
605 const android_dlextinfo* get_extinfo() const {
606 return extinfo_;
607 }
608
609 void set_extinfo(const android_dlextinfo* extinfo) {
610 extinfo_ = extinfo;
611 }
612
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700613 bool is_dt_needed() const {
614 return is_dt_needed_;
615 }
616
617 void set_dt_needed(bool is_dt_needed) {
618 is_dt_needed_ = is_dt_needed;
619 }
620
Jiyong Park02586a22017-05-20 01:01:24 +0900621 // returns the namespace from where we need to start loading this.
622 const android_namespace_t* get_start_from() const {
623 return start_from_;
624 }
625
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700626 const ElfReader& get_elf_reader() const {
627 CHECK(si_ != nullptr);
628 return (*elf_readers_map_)[si_];
629 }
630
631 ElfReader& get_elf_reader() {
632 CHECK(si_ != nullptr);
633 return (*elf_readers_map_)[si_];
634 }
635
636 std::unordered_map<const soinfo*, ElfReader>* get_readers_map() {
637 return elf_readers_map_;
638 }
639
640 bool read(const char* realpath, off64_t file_size) {
641 ElfReader& elf_reader = get_elf_reader();
642 return elf_reader.Read(realpath, fd_, file_offset_, file_size);
643 }
644
645 bool load() {
646 ElfReader& elf_reader = get_elf_reader();
647 if (!elf_reader.Load(extinfo_)) {
648 return false;
649 }
650
651 si_->base = elf_reader.load_start();
652 si_->size = elf_reader.load_size();
Dimitry Ivanovf45b0e92016-01-15 11:13:35 -0800653 si_->set_mapped_by_caller(elf_reader.is_mapped_by_caller());
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700654 si_->load_bias = elf_reader.load_bias();
655 si_->phnum = elf_reader.phdr_count();
656 si_->phdr = elf_reader.loaded_phdr();
657
658 return true;
659 }
660
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700661 private:
Dimitry Ivanov7d429d32017-02-01 15:28:52 -0800662 LoadTask(const char* name,
663 soinfo* needed_by,
Jiyong Park02586a22017-05-20 01:01:24 +0900664 android_namespace_t* start_from,
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700665 std::unordered_map<const soinfo*, ElfReader>* readers_map)
666 : name_(name), needed_by_(needed_by), si_(nullptr),
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700667 fd_(-1), close_fd_(false), file_offset_(0), elf_readers_map_(readers_map),
Jiyong Park02586a22017-05-20 01:01:24 +0900668 is_dt_needed_(false), start_from_(start_from) {}
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700669
670 ~LoadTask() {
671 if (fd_ != -1 && close_fd_) {
672 close(fd_);
673 }
674 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700675
676 const char* name_;
677 soinfo* needed_by_;
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700678 soinfo* si_;
679 const android_dlextinfo* extinfo_;
680 int fd_;
681 bool close_fd_;
682 off64_t file_offset_;
683 std::unordered_map<const soinfo*, ElfReader>* elf_readers_map_;
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700684 // TODO(dimitry): needed by workaround for http://b/26394120 (the grey-list)
685 bool is_dt_needed_;
686 // END OF WORKAROUND
Jiyong Park02586a22017-05-20 01:01:24 +0900687 const android_namespace_t* const start_from_;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700688
689 DISALLOW_IMPLICIT_CONSTRUCTORS(LoadTask);
690};
691
Ningsheng Jiane93be992014-09-16 15:22:10 +0800692LoadTask::deleter_t LoadTask::deleter;
693
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700694template <typename T>
695using linked_list_t = LinkedList<T, TypeBasedAllocator<LinkedListEntry<T>>>;
696
697typedef linked_list_t<soinfo> SoinfoLinkedList;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700698typedef linked_list_t<const char> StringLinkedList;
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700699typedef std::vector<LoadTask*> LoadTaskList;
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700700
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800701enum walk_action_result_t : uint32_t {
702 kWalkStop = 0,
703 kWalkContinue = 1,
704 kWalkSkip = 2
705};
Dmitriy Ivanovaa0f2bd2014-07-28 17:32:20 -0700706
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700707// This function walks down the tree of soinfo dependencies
708// in breadth-first order and
709// * calls action(soinfo* si) for each node, and
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800710// * terminates walk if action returns kWalkStop
711// * skips children of the node if action
712// return kWalkSkip
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700713//
714// walk_dependencies_tree returns false if walk was terminated
715// by the action and true otherwise.
716template<typename F>
dimitry965d06d2017-11-28 16:03:07 +0100717static bool walk_dependencies_tree(soinfo* root_soinfo, F action) {
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700718 SoinfoLinkedList visit_list;
719 SoinfoLinkedList visited;
720
dimitry965d06d2017-11-28 16:03:07 +0100721 visit_list.push_back(root_soinfo);
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700722
723 soinfo* si;
724 while ((si = visit_list.pop_front()) != nullptr) {
725 if (visited.contains(si)) {
Dmitriy Ivanov042426b2014-08-12 21:02:13 -0700726 continue;
727 }
728
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800729 walk_action_result_t result = action(si);
730
731 if (result == kWalkStop) {
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700732 return false;
Dmitriy Ivanovaa0f2bd2014-07-28 17:32:20 -0700733 }
734
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700735 visited.push_back(si);
736
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800737 if (result != kWalkSkip) {
738 si->get_children().for_each([&](soinfo* child) {
739 visit_list.push_back(child);
740 });
741 }
Dmitriy Ivanovaa0f2bd2014-07-28 17:32:20 -0700742 }
743
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700744 return true;
745}
746
747
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800748static const ElfW(Sym)* dlsym_handle_lookup(android_namespace_t* ns,
749 soinfo* root,
750 soinfo* skip_until,
751 soinfo** found,
752 SymbolName& symbol_name,
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800753 const version_info* vi) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700754 const ElfW(Sym)* result = nullptr;
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700755 bool skip_lookup = skip_until != nullptr;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700756
dimitry965d06d2017-11-28 16:03:07 +0100757 walk_dependencies_tree(root, [&](soinfo* current_soinfo) {
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700758 if (skip_lookup) {
759 skip_lookup = current_soinfo != skip_until;
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800760 return kWalkContinue;
761 }
762
763 if (!ns->is_accessible(current_soinfo)) {
764 return kWalkSkip;
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700765 }
766
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800767 if (!current_soinfo->find_symbol_by_name(symbol_name, vi, &result)) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700768 result = nullptr;
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800769 return kWalkStop;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700770 }
771
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700772 if (result != nullptr) {
773 *found = current_soinfo;
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800774 return kWalkStop;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700775 }
776
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800777 return kWalkContinue;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700778 });
779
780 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800781}
782
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800783static const ElfW(Sym)* dlsym_linear_lookup(android_namespace_t* ns,
784 const char* name,
785 const version_info* vi,
786 soinfo** found,
787 soinfo* caller,
788 void* handle);
789
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700790// This is used by dlsym(3). It performs symbol lookup only within the
791// specified soinfo object and its dependencies in breadth first order.
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800792static const ElfW(Sym)* dlsym_handle_lookup(soinfo* si,
793 soinfo** found,
794 const char* name,
795 const version_info* vi) {
Dmitriy Ivanovf439b5a2015-05-30 13:04:39 -0700796 // According to man dlopen(3) and posix docs in the case when si is handle
797 // of the main executable we need to search not only in the executable and its
798 // dependencies but also in all libraries loaded with RTLD_GLOBAL.
799 //
800 // Since RTLD_GLOBAL is always set for the main executable and all dt_needed shared
801 // libraries and they are loaded in breath-first (correct) order we can just execute
802 // dlsym(RTLD_DEFAULT, ...); instead of doing two stage lookup.
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700803 if (si == solist_get_somain()) {
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800804 return dlsym_linear_lookup(&g_default_namespace, name, vi, found, nullptr, RTLD_DEFAULT);
Dmitriy Ivanovf439b5a2015-05-30 13:04:39 -0700805 }
806
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700807 SymbolName symbol_name(name);
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800808 // note that the namespace is not the namespace associated with caller_addr
809 // we use ns associated with root si intentionally here. Using caller_ns
810 // causes problems when user uses dlopen_ext to open a library in the separate
811 // namespace and then calls dlsym() on the handle.
812 return dlsym_handle_lookup(si->get_primary_namespace(), si, nullptr, found, symbol_name, vi);
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700813}
814
Brian Carlstromd4ee82d2013-02-28 15:58:45 -0800815/* This is used by dlsym(3) to performs a global symbol lookup. If the
816 start value is null (for RTLD_DEFAULT), the search starts at the
817 beginning of the global solist. Otherwise the search starts at the
818 specified soinfo (for RTLD_NEXT).
Iliyan Malchev6ed80c82009-09-28 19:38:04 -0700819 */
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800820static const ElfW(Sym)* dlsym_linear_lookup(android_namespace_t* ns,
821 const char* name,
822 const version_info* vi,
823 soinfo** found,
824 soinfo* caller,
825 void* handle) {
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800826 SymbolName symbol_name(name);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800827
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -0700828 auto& soinfo_list = ns->soinfo_list();
829 auto start = soinfo_list.begin();
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -0700830
831 if (handle == RTLD_NEXT) {
Dmitriy Ivanovb96ac412015-05-22 12:34:42 -0700832 if (caller == nullptr) {
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -0700833 return nullptr;
834 } else {
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -0700835 auto it = soinfo_list.find(caller);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700836 CHECK (it != soinfo_list.end());
837 start = ++it;
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -0700838 }
Elliott Hughescade4c32012-12-20 14:42:14 -0800839 }
840
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700841 const ElfW(Sym)* s = nullptr;
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -0700842 for (auto it = start, end = soinfo_list.end(); it != end; ++it) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700843 soinfo* si = *it;
Dmitriy Ivanov19133522015-06-02 17:36:54 -0700844 // Do not skip RTLD_LOCAL libraries in dlsym(RTLD_DEFAULT, ...)
Elliott Hughes5bc78c82016-11-16 11:35:43 -0800845 // if the library is opened by application with target api level < M.
Dmitriy Ivanov19133522015-06-02 17:36:54 -0700846 // See http://b/21565766
Elliott Hughes5bc78c82016-11-16 11:35:43 -0800847 if ((si->get_rtld_flags() & RTLD_GLOBAL) == 0 &&
848 si->get_target_sdk_version() >= __ANDROID_API_M__) {
Dmitriy Ivanove8ba50f2014-09-15 17:00:10 -0700849 continue;
850 }
851
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800852 if (!si->find_symbol_by_name(symbol_name, vi, &s)) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700853 return nullptr;
854 }
855
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700856 if (s != nullptr) {
Elliott Hughescade4c32012-12-20 14:42:14 -0800857 *found = si;
858 break;
Matt Fischer1698d9e2009-12-31 12:17:56 -0600859 }
Elliott Hughescade4c32012-12-20 14:42:14 -0800860 }
Matt Fischer1698d9e2009-12-31 12:17:56 -0600861
dimitry153168c2018-02-20 16:51:41 +0100862 // If not found - use dlsym_handle_lookup for caller's local_group
863 if (s == nullptr && caller != nullptr) {
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800864 soinfo* local_group_root = caller->get_local_group_root();
865
866 return dlsym_handle_lookup(local_group_root->get_primary_namespace(),
867 local_group_root,
868 (handle == RTLD_NEXT) ? caller : nullptr,
869 found,
870 symbol_name,
871 vi);
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -0700872 }
873
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700874 if (s != nullptr) {
Elliott Hughesc00f2cb2013-10-04 17:01:33 -0700875 TRACE_TYPE(LOOKUP, "%s s->st_value = %p, found->base = %p",
876 name, reinterpret_cast<void*>(s->st_value), reinterpret_cast<void*>((*found)->base));
Elliott Hughescade4c32012-12-20 14:42:14 -0800877 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800878
Elliott Hughescade4c32012-12-20 14:42:14 -0800879 return s;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800880}
881
Kito Chengfa8c05d2013-03-12 14:58:06 +0800882soinfo* find_containing_library(const void* p) {
Elliott Hughes0266ae52014-02-10 17:46:57 -0800883 ElfW(Addr) address = reinterpret_cast<ElfW(Addr)>(p);
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700884 for (soinfo* si = solist_get_head(); si != nullptr; si = si->next) {
Kito Chengfa8c05d2013-03-12 14:58:06 +0800885 if (address >= si->base && address - si->base < si->size) {
886 return si;
Matt Fischere2a8b1f2009-12-31 12:17:40 -0600887 }
Kito Chengfa8c05d2013-03-12 14:58:06 +0800888 }
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700889 return nullptr;
Matt Fischere2a8b1f2009-12-31 12:17:40 -0600890}
891
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700892class ZipArchiveCache {
893 public:
894 ZipArchiveCache() {}
895 ~ZipArchiveCache();
896
897 bool get_or_open(const char* zip_path, ZipArchiveHandle* handle);
898 private:
899 DISALLOW_COPY_AND_ASSIGN(ZipArchiveCache);
900
901 std::unordered_map<std::string, ZipArchiveHandle> cache_;
902};
903
904bool ZipArchiveCache::get_or_open(const char* zip_path, ZipArchiveHandle* handle) {
905 std::string key(zip_path);
906
907 auto it = cache_.find(key);
908 if (it != cache_.end()) {
909 *handle = it->second;
910 return true;
911 }
912
913 int fd = TEMP_FAILURE_RETRY(open(zip_path, O_RDONLY | O_CLOEXEC));
914 if (fd == -1) {
915 return false;
916 }
917
918 if (OpenArchiveFd(fd, "", handle) != 0) {
919 // invalid zip-file (?)
Yabin Cui722072d2016-03-21 17:10:12 -0700920 CloseArchive(handle);
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700921 close(fd);
922 return false;
923 }
924
925 cache_[key] = *handle;
926 return true;
927}
928
929ZipArchiveCache::~ZipArchiveCache() {
Dmitriy Ivanov5dce8942015-10-13 12:14:16 -0700930 for (const auto& it : cache_) {
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700931 CloseArchive(it.second);
932 }
933}
934
935static int open_library_in_zipfile(ZipArchiveCache* zip_archive_cache,
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700936 const char* const input_path,
937 off64_t* file_offset, std::string* realpath) {
938 std::string normalized_path;
939 if (!normalize_path(input_path, &normalized_path)) {
940 return -1;
941 }
942
943 const char* const path = normalized_path.c_str();
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700944 TRACE("Trying zip file open from path \"%s\" -> normalized \"%s\"", input_path, path);
Simon Baldwinaef71952015-01-16 13:22:54 +0000945
Dmitriy Ivanov402a7502015-06-09 13:46:51 -0700946 // Treat an '!/' separator inside a path as the separator between the name
Simon Baldwinaef71952015-01-16 13:22:54 +0000947 // of the zip file on disk and the subdirectory to search within it.
Dmitriy Ivanov402a7502015-06-09 13:46:51 -0700948 // For example, if path is "foo.zip!/bar/bas/x.so", then we search for
Simon Baldwinaef71952015-01-16 13:22:54 +0000949 // "bar/bas/x.so" within "foo.zip".
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700950 const char* const separator = strstr(path, kZipFileSeparator);
Simon Baldwinaef71952015-01-16 13:22:54 +0000951 if (separator == nullptr) {
952 return -1;
Elliott Hughes124fae92012-10-31 14:20:03 -0700953 }
Simon Baldwinaef71952015-01-16 13:22:54 +0000954
955 char buf[512];
956 if (strlcpy(buf, path, sizeof(buf)) >= sizeof(buf)) {
957 PRINT("Warning: ignoring very long library path: %s", path);
958 return -1;
959 }
960
961 buf[separator - path] = '\0';
962
963 const char* zip_path = buf;
Dmitriy Ivanov402a7502015-06-09 13:46:51 -0700964 const char* file_path = &buf[separator - path + 2];
Simon Baldwinaef71952015-01-16 13:22:54 +0000965 int fd = TEMP_FAILURE_RETRY(open(zip_path, O_RDONLY | O_CLOEXEC));
966 if (fd == -1) {
967 return -1;
968 }
969
970 ZipArchiveHandle handle;
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700971 if (!zip_archive_cache->get_or_open(zip_path, &handle)) {
Simon Baldwinaef71952015-01-16 13:22:54 +0000972 // invalid zip-file (?)
973 close(fd);
974 return -1;
975 }
976
Simon Baldwinaef71952015-01-16 13:22:54 +0000977 ZipEntry entry;
978
Yusuke Sato56f40fb2015-06-25 14:56:07 -0700979 if (FindEntry(handle, ZipString(file_path), &entry) != 0) {
Simon Baldwinaef71952015-01-16 13:22:54 +0000980 // Entry was not found.
981 close(fd);
982 return -1;
983 }
984
985 // Check if it is properly stored
986 if (entry.method != kCompressStored || (entry.offset % PAGE_SIZE) != 0) {
987 close(fd);
988 return -1;
989 }
990
991 *file_offset = entry.offset;
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700992
993 if (realpath_fd(fd, realpath)) {
994 *realpath += separator;
995 } else {
996 PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.",
997 normalized_path.c_str());
998 *realpath = normalized_path;
999 }
1000
Simon Baldwinaef71952015-01-16 13:22:54 +00001001 return fd;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001002}
1003
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07001004static bool format_path(char* buf, size_t buf_size, const char* path, const char* name) {
Christopher Ferris7a3681e2017-04-24 17:48:32 -07001005 int n = async_safe_format_buffer(buf, buf_size, "%s/%s", path, name);
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07001006 if (n < 0 || n >= static_cast<int>(buf_size)) {
1007 PRINT("Warning: ignoring very long library path: %s/%s", path, name);
1008 return false;
1009 }
Simon Baldwinaef71952015-01-16 13:22:54 +00001010
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07001011 return true;
1012}
1013
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001014static int open_library_on_paths(ZipArchiveCache* zip_archive_cache,
1015 const char* name, off64_t* file_offset,
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001016 const std::vector<std::string>& paths,
1017 std::string* realpath) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001018 for (const auto& path : paths) {
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07001019 char buf[512];
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001020 if (!format_path(buf, sizeof(buf), path.c_str(), name)) {
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07001021 continue;
1022 }
1023
1024 int fd = -1;
Dmitriy Ivanov730ed9d2015-07-16 04:52:06 -07001025 if (strstr(buf, kZipFileSeparator) != nullptr) {
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001026 fd = open_library_in_zipfile(zip_archive_cache, buf, file_offset, realpath);
Simon Baldwinaef71952015-01-16 13:22:54 +00001027 }
1028
1029 if (fd == -1) {
1030 fd = TEMP_FAILURE_RETRY(open(buf, O_RDONLY | O_CLOEXEC));
1031 if (fd != -1) {
1032 *file_offset = 0;
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001033 if (!realpath_fd(fd, realpath)) {
1034 PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.", buf);
1035 *realpath = buf;
1036 }
Simon Baldwinaef71952015-01-16 13:22:54 +00001037 }
1038 }
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07001039
1040 if (fd != -1) {
1041 return fd;
1042 }
Simon Baldwinaef71952015-01-16 13:22:54 +00001043 }
1044
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07001045 return -1;
Simon Baldwinaef71952015-01-16 13:22:54 +00001046}
1047
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001048static int open_library(android_namespace_t* ns,
1049 ZipArchiveCache* zip_archive_cache,
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001050 const char* name, soinfo *needed_by,
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001051 off64_t* file_offset, std::string* realpath) {
Jiyong Park02586a22017-05-20 01:01:24 +09001052 TRACE("[ opening %s at namespace %s]", name, ns->get_name());
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001053
Elliott Hughes124fae92012-10-31 14:20:03 -07001054 // 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 -07001055 if (strchr(name, '/') != nullptr) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001056 int fd = -1;
1057
Dmitriy Ivanov730ed9d2015-07-16 04:52:06 -07001058 if (strstr(name, kZipFileSeparator) != nullptr) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001059 fd = open_library_in_zipfile(zip_archive_cache, name, file_offset, realpath);
1060 }
1061
1062 if (fd == -1) {
1063 fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_CLOEXEC));
Simon Baldwinaef71952015-01-16 13:22:54 +00001064 if (fd != -1) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001065 *file_offset = 0;
1066 if (!realpath_fd(fd, realpath)) {
1067 PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.", name);
1068 *realpath = name;
1069 }
Simon Baldwinaef71952015-01-16 13:22:54 +00001070 }
1071 }
1072
Dmitriy Ivanove44fffd2015-03-17 17:12:18 -07001073 return fd;
Elliott Hughes124fae92012-10-31 14:20:03 -07001074 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001075
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001076 // Otherwise we try LD_LIBRARY_PATH first, and fall back to the default library path
1077 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 -07001078 if (fd == -1 && needed_by != nullptr) {
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001079 fd = open_library_on_paths(zip_archive_cache, name, file_offset, needed_by->get_dt_runpath(), realpath);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001080 // Check if the library is accessible
1081 if (fd != -1 && !ns->is_accessible(*realpath)) {
1082 fd = -1;
1083 }
Evgenii Stepanov68650822015-06-10 13:38:39 -07001084 }
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001085
Elliott Hughes124fae92012-10-31 14:20:03 -07001086 if (fd == -1) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001087 fd = open_library_on_paths(zip_archive_cache, name, file_offset, ns->get_default_library_paths(), realpath);
Elliott Hughes124fae92012-10-31 14:20:03 -07001088 }
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001089
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001090 // TODO(dimitry): workaround for http://b/26394120 (the grey-list)
Jiyong Park37b91af2017-05-05 22:07:05 +09001091 if (fd == -1 && ns->is_greylist_enabled() && is_greylisted(ns, name, needed_by)) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001092 // try searching for it on default_namespace default_library_path
1093 fd = open_library_on_paths(zip_archive_cache, name, file_offset,
1094 g_default_namespace.get_default_library_paths(), realpath);
1095 }
1096 // END OF WORKAROUND
1097
Elliott Hughes124fae92012-10-31 14:20:03 -07001098 return fd;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001099}
1100
Dimitry Ivanov3f660572016-09-09 10:00:39 -07001101const char* fix_dt_needed(const char* dt_needed, const char* sopath __unused) {
Dmitriy Ivanovd974e882015-05-27 18:29:41 -07001102#if !defined(__LP64__)
1103 // Work around incorrect DT_NEEDED entries for old apps: http://b/21364029
Elliott Hughes9076b0c2018-02-28 11:29:45 -08001104 int app_target_api_level = get_application_target_sdk_version();
1105 if (app_target_api_level < __ANDROID_API_M__) {
Dmitriy Ivanovd974e882015-05-27 18:29:41 -07001106 const char* bname = basename(dt_needed);
1107 if (bname != dt_needed) {
Elliott Hughes9076b0c2018-02-28 11:29:45 -08001108 DL_WARN_documented_change(__ANDROID_API_M__,
1109 "invalid-dt_needed-entries-enforced-for-api-level-23",
1110 "library \"%s\" has invalid DT_NEEDED entry \"%s\"",
1111 sopath, dt_needed, app_target_api_level);
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001112 add_dlwarning(sopath, "invalid DT_NEEDED entry", dt_needed);
Dmitriy Ivanovd974e882015-05-27 18:29:41 -07001113 }
1114
1115 return bname;
1116 }
1117#endif
1118 return dt_needed;
1119}
1120
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001121template<typename F>
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001122static void for_each_dt_needed(const ElfReader& elf_reader, F action) {
1123 for (const ElfW(Dyn)* d = elf_reader.dynamic(); d->d_tag != DT_NULL; ++d) {
1124 if (d->d_tag == DT_NEEDED) {
1125 action(fix_dt_needed(elf_reader.get_string(d->d_un.d_val), elf_reader.name()));
1126 }
1127 }
1128}
1129
Dimitry Ivanovd3e7d082017-03-27 14:11:02 -07001130static bool find_loaded_library_by_inode(android_namespace_t* ns,
1131 const struct stat& file_stat,
1132 off64_t file_offset,
1133 bool search_linked_namespaces,
1134 soinfo** candidate) {
1135
1136 auto predicate = [&](soinfo* si) {
1137 return si->get_st_dev() != 0 &&
1138 si->get_st_ino() != 0 &&
1139 si->get_st_dev() == file_stat.st_dev &&
1140 si->get_st_ino() == file_stat.st_ino &&
1141 si->get_file_offset() == file_offset;
1142 };
1143
1144 *candidate = ns->soinfo_list().find_if(predicate);
1145
1146 if (*candidate == nullptr && search_linked_namespaces) {
1147 for (auto& link : ns->linked_namespaces()) {
1148 android_namespace_t* linked_ns = link.linked_namespace();
1149 soinfo* si = linked_ns->soinfo_list().find_if(predicate);
1150
1151 if (si != nullptr && link.is_accessible(si->get_soname())) {
1152 *candidate = si;
1153 return true;
1154 }
1155 }
1156 }
1157
1158 return *candidate != nullptr;
1159}
1160
Evgenii Stepanov9e77a642017-07-27 14:55:44 -07001161static bool find_loaded_library_by_realpath(android_namespace_t* ns, const char* realpath,
1162 bool search_linked_namespaces, soinfo** candidate) {
1163 auto predicate = [&](soinfo* si) { return strcmp(realpath, si->get_realpath()) == 0; };
1164
1165 *candidate = ns->soinfo_list().find_if(predicate);
1166
1167 if (*candidate == nullptr && search_linked_namespaces) {
1168 for (auto& link : ns->linked_namespaces()) {
1169 android_namespace_t* linked_ns = link.linked_namespace();
1170 soinfo* si = linked_ns->soinfo_list().find_if(predicate);
1171
1172 if (si != nullptr && link.is_accessible(si->get_soname())) {
1173 *candidate = si;
1174 return true;
1175 }
1176 }
1177 }
1178
1179 return *candidate != nullptr;
1180}
1181
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001182static bool load_library(android_namespace_t* ns,
1183 LoadTask* task,
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001184 LoadTaskList* load_tasks,
1185 int rtld_flags,
Dimitry Ivanovd3e7d082017-03-27 14:11:02 -07001186 const std::string& realpath,
1187 bool search_linked_namespaces) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001188 off64_t file_offset = task->get_file_offset();
1189 const char* name = task->get_name();
1190 const android_dlextinfo* extinfo = task->get_extinfo();
1191
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001192 if ((file_offset % PAGE_SIZE) != 0) {
Dmitriy Ivanova6c12792014-10-21 12:09:18 -07001193 DL_ERR("file offset for the library \"%s\" is not page-aligned: %" PRId64, name, file_offset);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001194 return false;
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001195 }
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001196 if (file_offset < 0) {
1197 DL_ERR("file offset for the library \"%s\" is negative: %" PRId64, name, file_offset);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001198 return false;
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001199 }
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001200
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001201 struct stat file_stat;
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001202 if (TEMP_FAILURE_RETRY(fstat(task->get_fd(), &file_stat)) != 0) {
Dmitriy Ivanova6c12792014-10-21 12:09:18 -07001203 DL_ERR("unable to stat file for the library \"%s\": %s", name, strerror(errno));
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001204 return false;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001205 }
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001206 if (file_offset >= file_stat.st_size) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07001207 DL_ERR("file offset for the library \"%s\" >= file size: %" PRId64 " >= %" PRId64,
1208 name, file_offset, file_stat.st_size);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001209 return false;
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001210 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001211
1212 // Check for symlink and other situations where
Dmitriy Ivanov9b821362015-04-02 16:03:56 -07001213 // file can have different names, unless ANDROID_DLEXT_FORCE_LOAD is set
1214 if (extinfo == nullptr || (extinfo->flags & ANDROID_DLEXT_FORCE_LOAD) == 0) {
Dimitry Ivanovd3e7d082017-03-27 14:11:02 -07001215 soinfo* si = nullptr;
1216 if (find_loaded_library_by_inode(ns, file_stat, file_offset, search_linked_namespaces, &si)) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001217 TRACE("library \"%s\" is already loaded under different name/path \"%s\" - "
1218 "will return existing soinfo", name, si->get_realpath());
1219 task->set_soinfo(si);
1220 return true;
1221 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001222 }
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07001223
Dmitriy Ivanove8ba50f2014-09-15 17:00:10 -07001224 if ((rtld_flags & RTLD_NOLOAD) != 0) {
Dmitriy Ivanova6ac54a2014-09-09 10:21:42 -07001225 DL_ERR("library \"%s\" wasn't loaded and RTLD_NOLOAD prevented it", name);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001226 return false;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001227 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001228
Dimitry Ivanovbf34ba32017-04-21 13:12:05 -07001229 struct statfs fs_stat;
1230 if (TEMP_FAILURE_RETRY(fstatfs(task->get_fd(), &fs_stat)) != 0) {
1231 DL_ERR("unable to fstatfs file for the library \"%s\": %s", name, strerror(errno));
1232 return false;
1233 }
1234
1235 // do not check accessibility using realpath if fd is located on tmpfs
1236 // this enables use of memfd_create() for apps
1237 if ((fs_stat.f_type != TMPFS_MAGIC) && (!ns->is_accessible(realpath))) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001238 // TODO(dimitry): workaround for http://b/26394120 - the grey-list
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001239
1240 // TODO(dimitry) before O release: add a namespace attribute to have this enabled
1241 // only for classloader-namespaces
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001242 const soinfo* needed_by = task->is_dt_needed() ? task->get_needed_by() : nullptr;
Dimitry Ivanov35c8e3b2017-02-27 12:17:47 -08001243 if (is_greylisted(ns, name, needed_by)) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001244 // print warning only if needed by non-system library
1245 if (needed_by == nullptr || !is_system_library(needed_by->get_realpath())) {
1246 const soinfo* needed_or_dlopened_by = task->get_needed_by();
1247 const char* sopath = needed_or_dlopened_by == nullptr ? "(unknown)" :
1248 needed_or_dlopened_by->get_realpath();
Elliott Hughes9076b0c2018-02-28 11:29:45 -08001249 DL_WARN_documented_change(__ANDROID_API_N__,
1250 "private-api-enforced-for-api-level-24",
1251 "library \"%s\" (\"%s\") needed or dlopened by \"%s\" "
1252 "is not accessible by namespace \"%s\"",
1253 name, realpath.c_str(), sopath, ns->get_name());
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001254 add_dlwarning(sopath, "unauthorized access to", name);
1255 }
1256 } else {
1257 // do not load libraries if they are not accessible for the specified namespace.
1258 const char* needed_or_dlopened_by = task->get_needed_by() == nullptr ?
1259 "(unknown)" :
1260 task->get_needed_by()->get_realpath();
Dimitry Ivanovd17a3772016-03-01 13:11:28 -08001261
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001262 DL_ERR("library \"%s\" needed or dlopened by \"%s\" is not accessible for the namespace \"%s\"",
1263 name, needed_or_dlopened_by, ns->get_name());
Dimitry Ivanovd17a3772016-03-01 13:11:28 -08001264
Dimitry Ivanov35c8e3b2017-02-27 12:17:47 -08001265 // do not print this if a library is in the list of shared libraries for linked namespaces
1266 if (!maybe_accessible_via_namespace_links(ns, name)) {
1267 PRINT("library \"%s\" (\"%s\") needed or dlopened by \"%s\" is not accessible for the"
1268 " namespace: [name=\"%s\", ld_library_paths=\"%s\", default_library_paths=\"%s\","
1269 " permitted_paths=\"%s\"]",
1270 name, realpath.c_str(),
1271 needed_or_dlopened_by,
1272 ns->get_name(),
1273 android::base::Join(ns->get_ld_library_paths(), ':').c_str(),
1274 android::base::Join(ns->get_default_library_paths(), ':').c_str(),
1275 android::base::Join(ns->get_permitted_paths(), ':').c_str());
1276 }
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001277 return false;
1278 }
Dimitry Ivanov22840aa2015-12-04 18:28:49 -08001279 }
1280
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001281 soinfo* si = soinfo_alloc(ns, realpath.c_str(), &file_stat, file_offset, rtld_flags);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001282 if (si == nullptr) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001283 return false;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001284 }
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07001285
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001286 task->set_soinfo(si);
1287
1288 // Read the ELF header and some of the segments.
1289 if (!task->read(realpath.c_str(), file_stat.st_size)) {
Dmitriy Ivanovfd7a91e2015-11-06 10:44:37 -08001290 soinfo_free(si);
1291 task->set_soinfo(nullptr);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001292 return false;
1293 }
1294
1295 // find and set DT_RUNPATH and dt_soname
1296 // Note that these field values are temporary and are
1297 // going to be overwritten on soinfo::prelink_image
1298 // with values from PT_LOAD segments.
1299 const ElfReader& elf_reader = task->get_elf_reader();
1300 for (const ElfW(Dyn)* d = elf_reader.dynamic(); d->d_tag != DT_NULL; ++d) {
1301 if (d->d_tag == DT_RUNPATH) {
1302 si->set_dt_runpath(elf_reader.get_string(d->d_un.d_val));
1303 }
1304 if (d->d_tag == DT_SONAME) {
1305 si->set_soname(elf_reader.get_string(d->d_un.d_val));
1306 }
1307 }
1308
1309 for_each_dt_needed(task->get_elf_reader(), [&](const char* name) {
Jiyong Park02586a22017-05-20 01:01:24 +09001310 load_tasks->push_back(LoadTask::create(name, si, ns, task->get_readers_map()));
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001311 });
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07001312
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001313 return true;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001314}
1315
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001316static bool load_library(android_namespace_t* ns,
1317 LoadTask* task,
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001318 ZipArchiveCache* zip_archive_cache,
1319 LoadTaskList* load_tasks,
Dimitry Ivanovd3e7d082017-03-27 14:11:02 -07001320 int rtld_flags,
1321 bool search_linked_namespaces) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001322 const char* name = task->get_name();
1323 soinfo* needed_by = task->get_needed_by();
1324 const android_dlextinfo* extinfo = task->get_extinfo();
1325
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001326 off64_t file_offset;
1327 std::string realpath;
Spencer Low0346ad72015-04-22 18:06:51 -07001328 if (extinfo != nullptr && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) {
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001329 file_offset = 0;
Spencer Low0346ad72015-04-22 18:06:51 -07001330 if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
1331 file_offset = extinfo->library_fd_offset;
1332 }
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001333
1334 if (!realpath_fd(extinfo->library_fd, &realpath)) {
1335 PRINT("warning: unable to get realpath for the library \"%s\" by extinfo->library_fd. "
1336 "Will use given name.", name);
1337 realpath = name;
1338 }
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001339
1340 task->set_fd(extinfo->library_fd, false);
1341 task->set_file_offset(file_offset);
Dimitry Ivanovd3e7d082017-03-27 14:11:02 -07001342 return load_library(ns, task, load_tasks, rtld_flags, realpath, search_linked_namespaces);
Spencer Low0346ad72015-04-22 18:06:51 -07001343 }
1344
1345 // Open the file.
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001346 int fd = open_library(ns, zip_archive_cache, name, needed_by, &file_offset, &realpath);
Spencer Low0346ad72015-04-22 18:06:51 -07001347 if (fd == -1) {
1348 DL_ERR("library \"%s\" not found", name);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001349 return false;
Spencer Low0346ad72015-04-22 18:06:51 -07001350 }
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001351
1352 task->set_fd(fd, true);
1353 task->set_file_offset(file_offset);
1354
Dimitry Ivanovd3e7d082017-03-27 14:11:02 -07001355 return load_library(ns, task, load_tasks, rtld_flags, realpath, search_linked_namespaces);
Spencer Low0346ad72015-04-22 18:06:51 -07001356}
1357
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001358static bool find_loaded_library_by_soname(android_namespace_t* ns,
Dimitry Ivanovd3e7d082017-03-27 14:11:02 -07001359 const char* name,
1360 soinfo** candidate) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001361 return !ns->soinfo_list().visit([&](soinfo* si) {
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07001362 const char* soname = si->get_soname();
1363 if (soname != nullptr && (strcmp(name, soname) == 0)) {
Dimitry Ivanov3bd90612017-02-01 08:54:43 -08001364 *candidate = si;
1365 return false;
Ard Biesheuvel12c78bb2012-08-14 12:30:09 +02001366 }
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001367
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001368 return true;
1369 });
Ard Biesheuvel12c78bb2012-08-14 12:30:09 +02001370}
1371
Dimitry Ivanovd3e7d082017-03-27 14:11:02 -07001372// Returns true if library was found and false otherwise
1373static bool find_loaded_library_by_soname(android_namespace_t* ns,
1374 const char* name,
1375 bool search_linked_namespaces,
1376 soinfo** candidate) {
1377 *candidate = nullptr;
1378
1379 // Ignore filename with path.
1380 if (strchr(name, '/') != nullptr) {
1381 return false;
1382 }
1383
1384 bool found = find_loaded_library_by_soname(ns, name, candidate);
1385
1386 if (!found && search_linked_namespaces) {
1387 // if a library was not found - look into linked namespaces
1388 for (auto& link : ns->linked_namespaces()) {
1389 if (!link.is_accessible(name)) {
1390 continue;
1391 }
1392
1393 android_namespace_t* linked_ns = link.linked_namespace();
1394
1395 if (find_loaded_library_by_soname(linked_ns, name, candidate)) {
1396 return true;
1397 }
1398 }
1399 }
1400
1401 return found;
1402}
1403
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001404static bool find_library_in_linked_namespace(const android_namespace_link_t& namespace_link,
Jiyong Park02586a22017-05-20 01:01:24 +09001405 LoadTask* task) {
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001406 android_namespace_t* ns = namespace_link.linked_namespace();
1407
1408 soinfo* candidate;
1409 bool loaded = false;
1410
1411 std::string soname;
Dimitry Ivanovd3e7d082017-03-27 14:11:02 -07001412 if (find_loaded_library_by_soname(ns, task->get_name(), false, &candidate)) {
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001413 loaded = true;
1414 soname = candidate->get_soname();
1415 } else {
1416 soname = resolve_soname(task->get_name());
1417 }
1418
1419 if (!namespace_link.is_accessible(soname.c_str())) {
1420 // the library is not accessible via namespace_link
1421 return false;
1422 }
1423
1424 // if library is already loaded - return it
1425 if (loaded) {
1426 task->set_soinfo(candidate);
1427 return true;
1428 }
1429
Jiyong Park02586a22017-05-20 01:01:24 +09001430 // returning true with empty soinfo means that the library is okay to be
Logan Chien9ee45912018-01-18 12:05:09 +08001431 // loaded in the namespace but has not yet been loaded there before.
Jiyong Park02586a22017-05-20 01:01:24 +09001432 task->set_soinfo(nullptr);
1433 return true;
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001434}
1435
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001436static bool find_library_internal(android_namespace_t* ns,
1437 LoadTask* task,
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001438 ZipArchiveCache* zip_archive_cache,
1439 LoadTaskList* load_tasks,
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001440 int rtld_flags,
1441 bool search_linked_namespaces) {
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001442 soinfo* candidate;
1443
Dimitry Ivanovd3e7d082017-03-27 14:11:02 -07001444 if (find_loaded_library_by_soname(ns, task->get_name(), search_linked_namespaces, &candidate)) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001445 task->set_soinfo(candidate);
1446 return true;
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001447 }
Dmitriy Ivanovb648a8a2014-05-19 15:06:58 -07001448
1449 // Library might still be loaded, the accurate detection
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001450 // of this fact is done by load_library.
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001451 TRACE("[ \"%s\" find_loaded_library_by_soname failed (*candidate=%s@%p). Trying harder...]",
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001452 task->get_name(), candidate == nullptr ? "n/a" : candidate->get_realpath(), candidate);
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001453
Dimitry Ivanovd3e7d082017-03-27 14:11:02 -07001454 if (load_library(ns, task, zip_archive_cache, load_tasks, rtld_flags, search_linked_namespaces)) {
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001455 return true;
1456 }
1457
1458 if (search_linked_namespaces) {
1459 // if a library was not found - look into linked namespaces
dimitry8db36a52017-10-23 15:10:10 +02001460 // preserve current dlerror in the case it fails.
1461 DlErrorRestorer dlerror_restorer;
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001462 for (auto& linked_namespace : ns->linked_namespaces()) {
1463 if (find_library_in_linked_namespace(linked_namespace,
Jiyong Park02586a22017-05-20 01:01:24 +09001464 task)) {
1465 if (task->get_soinfo() == nullptr) {
1466 // try to load the library - once namespace boundary is crossed
1467 // we need to load a library within separate load_group
1468 // to avoid using symbols from foreign namespace while.
1469 //
1470 // However, actual linking is deferred until when the global group
1471 // is fully identified and is applied to all namespaces.
1472 // Otherwise, the libs in the linked namespace won't get symbols from
1473 // the global group.
1474 if (load_library(linked_namespace.linked_namespace(), task, zip_archive_cache, load_tasks, rtld_flags, false)) {
1475 return true;
1476 }
Jiyong Park02586a22017-05-20 01:01:24 +09001477 } else {
1478 // lib is already loaded
1479 return true;
1480 }
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001481 }
1482 }
1483 }
1484
1485 return false;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001486}
1487
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001488static void soinfo_unload(soinfo* si);
1489
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001490static void shuffle(std::vector<LoadTask*>* v) {
1491 for (size_t i = 0, size = v->size(); i < size; ++i) {
1492 size_t n = size - i;
1493 size_t r = arc4random_uniform(n);
1494 std::swap((*v)[n-1], (*v)[r]);
1495 }
1496}
1497
Evgenii Stepanov0cdef7e2015-07-06 17:56:31 -07001498// add_as_children - add first-level loaded libraries (i.e. library_names[], but
1499// not their transitive dependencies) as children of the start_with library.
1500// This is false when find_libraries is called for dlopen(), when newly loaded
1501// libraries must form a disjoint tree.
Dimitry Ivanov3f660572016-09-09 10:00:39 -07001502bool find_libraries(android_namespace_t* ns,
1503 soinfo* start_with,
1504 const char* const library_names[],
1505 size_t library_names_count,
1506 soinfo* soinfos[],
1507 std::vector<soinfo*>* ld_preloads,
1508 size_t ld_preloads_count,
1509 int rtld_flags,
1510 const android_dlextinfo* extinfo,
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001511 bool add_as_children,
Jiyong Park02586a22017-05-20 01:01:24 +09001512 bool search_linked_namespaces,
Jiyong Park02586a22017-05-20 01:01:24 +09001513 std::vector<android_namespace_t*>* namespaces) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001514 // Step 0: prepare.
dimitry965d06d2017-11-28 16:03:07 +01001515 std::unordered_map<const soinfo*, ElfReader> readers_map;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001516 LoadTaskList load_tasks;
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001517
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001518 for (size_t i = 0; i < library_names_count; ++i) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001519 const char* name = library_names[i];
Jiyong Park02586a22017-05-20 01:01:24 +09001520 load_tasks.push_back(LoadTask::create(name, start_with, ns, &readers_map));
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001521 }
1522
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001523 // If soinfos array is null allocate one on stack.
1524 // The array is needed in case of failure; for example
1525 // when library_names[] = {libone.so, libtwo.so} and libone.so
1526 // is loaded correctly but libtwo.so failed for some reason.
1527 // In this case libone.so should be unloaded on return.
1528 // See also implementation of failure_guard below.
1529
1530 if (soinfos == nullptr) {
1531 size_t soinfos_size = sizeof(soinfo*)*library_names_count;
1532 soinfos = reinterpret_cast<soinfo**>(alloca(soinfos_size));
1533 memset(soinfos, 0, soinfos_size);
1534 }
1535
1536 // list of libraries to link - see step 2.
1537 size_t soinfos_count = 0;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001538
Tom Cherryb8ab6182017-04-05 16:20:29 -07001539 auto scope_guard = android::base::make_scope_guard([&]() {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001540 for (LoadTask* t : load_tasks) {
1541 LoadTask::deleter(t);
1542 }
1543 });
1544
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001545 ZipArchiveCache zip_archive_cache;
1546
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001547 // Step 1: expand the list of load_tasks to include
1548 // all DT_NEEDED libraries (do not load them just yet)
1549 for (size_t i = 0; i<load_tasks.size(); ++i) {
1550 LoadTask* task = load_tasks[i];
Evgenii Stepanov68650822015-06-10 13:38:39 -07001551 soinfo* needed_by = task->get_needed_by();
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001552
Dmitriy Ivanovedfc9f62015-09-02 16:32:02 -07001553 bool is_dt_needed = needed_by != nullptr && (needed_by != start_with || add_as_children);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001554 task->set_extinfo(is_dt_needed ? nullptr : extinfo);
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001555 task->set_dt_needed(is_dt_needed);
Dmitriy Ivanovedfc9f62015-09-02 16:32:02 -07001556
Jiyong Park02586a22017-05-20 01:01:24 +09001557 // Note: start from the namespace that is stored in the LoadTask. This namespace
1558 // is different from the current namespace when the LoadTask is for a transitive
1559 // dependency and the lib that created the LoadTask is not found in the
1560 // current namespace but in one of the linked namespace.
1561 if (!find_library_internal(const_cast<android_namespace_t*>(task->get_start_from()),
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001562 task,
1563 &zip_archive_cache,
1564 &load_tasks,
1565 rtld_flags,
1566 search_linked_namespaces || is_dt_needed)) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001567 return false;
1568 }
1569
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001570 soinfo* si = task->get_soinfo();
1571
Dmitriy Ivanovedfc9f62015-09-02 16:32:02 -07001572 if (is_dt_needed) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001573 needed_by->add_child(si);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001574 }
1575
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001576 // When ld_preloads is not null, the first
1577 // ld_preloads_count libs are in fact ld_preloads.
1578 if (ld_preloads != nullptr && soinfos_count < ld_preloads_count) {
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07001579 ld_preloads->push_back(si);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001580 }
1581
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001582 if (soinfos_count < library_names_count) {
1583 soinfos[soinfos_count++] = si;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001584 }
1585 }
1586
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001587 // Step 2: Load libraries in random order (see b/24047022)
1588 LoadTaskList load_list;
1589 for (auto&& task : load_tasks) {
1590 soinfo* si = task->get_soinfo();
1591 auto pred = [&](const LoadTask* t) {
1592 return t->get_soinfo() == si;
1593 };
1594
1595 if (!si->is_linked() &&
1596 std::find_if(load_list.begin(), load_list.end(), pred) == load_list.end() ) {
1597 load_list.push_back(task);
1598 }
1599 }
1600 shuffle(&load_list);
1601
1602 for (auto&& task : load_list) {
1603 if (!task->load()) {
1604 return false;
1605 }
1606 }
1607
1608 // Step 3: pre-link all DT_NEEDED libraries in breadth first order.
1609 for (auto&& task : load_tasks) {
1610 soinfo* si = task->get_soinfo();
1611 if (!si->is_linked() && !si->prelink_image()) {
1612 return false;
1613 }
1614 }
1615
Jiyong Park02586a22017-05-20 01:01:24 +09001616 // Step 4: Construct the global group. Note: DF_1_GLOBAL bit of a library is
1617 // determined at step 3.
1618
1619 // Step 4-1: DF_1_GLOBAL bit is force set for LD_PRELOADed libs because they
1620 // must be added to the global group
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001621 if (ld_preloads != nullptr) {
1622 for (auto&& si : *ld_preloads) {
1623 si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL);
1624 }
1625 }
1626
Jiyong Park02586a22017-05-20 01:01:24 +09001627 // Step 4-2: Gather all DF_1_GLOBAL libs which were newly loaded during this
1628 // run. These will be the new member of the global group
1629 soinfo_list_t new_global_group_members;
1630 for (auto&& task : load_tasks) {
1631 soinfo* si = task->get_soinfo();
1632 if (!si->is_linked() && (si->get_dt_flags_1() & DF_1_GLOBAL) != 0) {
1633 new_global_group_members.push_back(si);
1634 }
1635 }
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001636
Jiyong Park02586a22017-05-20 01:01:24 +09001637 // Step 4-3: Add the new global group members to all the linked namespaces
Jiyong Park01162f22017-10-16 15:31:09 +09001638 if (namespaces != nullptr) {
Jiyong Park02586a22017-05-20 01:01:24 +09001639 for (auto linked_ns : *namespaces) {
Jiyong Park01162f22017-10-16 15:31:09 +09001640 for (auto si : new_global_group_members) {
1641 if (si->get_primary_namespace() != linked_ns) {
1642 linked_ns->add_soinfo(si);
1643 si->add_secondary_namespace(linked_ns);
1644 }
Jiyong Park02586a22017-05-20 01:01:24 +09001645 }
1646 }
1647 }
1648
dimitry965d06d2017-11-28 16:03:07 +01001649 // Step 5: Collect roots of local_groups.
1650 // Whenever needed_by->si link crosses a namespace boundary it forms its own local_group.
1651 // Here we collect new roots to link them separately later on. Note that we need to avoid
1652 // collecting duplicates. Also the order is important. They need to be linked in the same
1653 // BFS order we link individual libraries.
1654 std::vector<soinfo*> local_group_roots;
1655 if (start_with != nullptr && add_as_children) {
1656 local_group_roots.push_back(start_with);
1657 } else {
1658 CHECK(soinfos_count == 1);
1659 local_group_roots.push_back(soinfos[0]);
1660 }
1661
Jiyong Park02586a22017-05-20 01:01:24 +09001662 for (auto&& task : load_tasks) {
1663 soinfo* si = task->get_soinfo();
dimitry965d06d2017-11-28 16:03:07 +01001664 soinfo* needed_by = task->get_needed_by();
1665 bool is_dt_needed = needed_by != nullptr && (needed_by != start_with || add_as_children);
1666 android_namespace_t* needed_by_ns =
1667 is_dt_needed ? needed_by->get_primary_namespace() : ns;
1668
1669 if (!si->is_linked() && si->get_primary_namespace() != needed_by_ns) {
1670 auto it = std::find(local_group_roots.begin(), local_group_roots.end(), si);
1671 LD_LOG(kLogDlopen,
1672 "Crossing namespace boundary (si=%s@%p, si_ns=%s@%p, needed_by=%s@%p, ns=%s@%p, needed_by_ns=%s@%p) adding to local_group_roots: %s",
1673 si->get_realpath(),
1674 si,
1675 si->get_primary_namespace()->get_name(),
1676 si->get_primary_namespace(),
1677 needed_by == nullptr ? "(nullptr)" : needed_by->get_realpath(),
1678 needed_by,
1679 ns->get_name(),
1680 ns,
1681 needed_by_ns->get_name(),
1682 needed_by_ns,
1683 it == local_group_roots.end() ? "yes" : "no");
1684
1685 if (it == local_group_roots.end()) {
1686 local_group_roots.push_back(si);
Jiyong Park02586a22017-05-20 01:01:24 +09001687 }
1688 }
1689 }
1690
dimitry965d06d2017-11-28 16:03:07 +01001691 // Step 6: Link all local groups
1692 for (auto root : local_group_roots) {
1693 soinfo_list_t local_group;
1694 android_namespace_t* local_group_ns = root->get_primary_namespace();
1695
1696 walk_dependencies_tree(root,
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001697 [&] (soinfo* si) {
dimitry965d06d2017-11-28 16:03:07 +01001698 if (local_group_ns->is_accessible(si)) {
1699 local_group.push_back(si);
1700 return kWalkContinue;
1701 } else {
1702 return kWalkSkip;
1703 }
1704 });
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001705
dimitry965d06d2017-11-28 16:03:07 +01001706 soinfo_list_t global_group = local_group_ns->get_global_group();
1707 bool linked = local_group.visit([&](soinfo* si) {
1708 // Even though local group may contain accessible soinfos from other namesapces
1709 // we should avoid linking them (because if they are not linked -> they
1710 // are in the local_group_roots and will be linked later).
1711 if (!si->is_linked() && si->get_primary_namespace() == local_group_ns) {
1712 if (!si->link_image(global_group, local_group, extinfo) ||
1713 !get_cfi_shadow()->AfterLoad(si, solist_get_head())) {
1714 return false;
1715 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001716 }
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001717
dimitry965d06d2017-11-28 16:03:07 +01001718 return true;
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001719 });
Elliott Hughes27f18062017-11-29 18:47:42 +00001720
dimitry965d06d2017-11-28 16:03:07 +01001721 if (!linked) {
1722 return false;
1723 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001724 }
1725
dimitry965d06d2017-11-28 16:03:07 +01001726 // Step 7: Mark all load_tasks as linked and increment refcounts
1727 // for references between load_groups (at this point it does not matter if
1728 // referenced load_groups were loaded by previous dlopen or as part of this
1729 // one on step 6)
1730 if (start_with != nullptr && add_as_children) {
1731 start_with->set_linked();
1732 }
1733
1734 for (auto&& task : load_tasks) {
1735 soinfo* si = task->get_soinfo();
1736 si->set_linked();
1737 }
1738
1739 for (auto&& task : load_tasks) {
1740 soinfo* si = task->get_soinfo();
1741 soinfo* needed_by = task->get_needed_by();
1742 if (needed_by != nullptr &&
1743 needed_by != start_with &&
1744 needed_by->get_local_group_root() != si->get_local_group_root()) {
1745 si->increment_ref_count();
1746 }
1747 }
1748
1749
1750 return true;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001751}
1752
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001753static soinfo* find_library(android_namespace_t* ns,
1754 const char* name, int rtld_flags,
Evgenii Stepanov0cdef7e2015-07-06 17:56:31 -07001755 const android_dlextinfo* extinfo,
1756 soinfo* needed_by) {
dimitry965d06d2017-11-28 16:03:07 +01001757 soinfo* si = nullptr;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001758
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001759 if (name == nullptr) {
Dimitry Ivanov3f660572016-09-09 10:00:39 -07001760 si = solist_get_somain();
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001761 } else if (!find_libraries(ns,
1762 needed_by,
1763 &name,
1764 1,
1765 &si,
1766 nullptr,
1767 0,
1768 rtld_flags,
1769 extinfo,
1770 false /* add_as_children */,
dimitry965d06d2017-11-28 16:03:07 +01001771 true /* search_linked_namespaces */)) {
1772 if (si != nullptr) {
1773 soinfo_unload(si);
1774 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001775 return nullptr;
1776 }
1777
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001778 si->increment_ref_count();
1779
Elliott Hughesd23736e2012-11-01 15:16:56 -07001780 return si;
1781}
Elliott Hughesbedfe382012-08-14 14:07:59 -07001782
dimitry06016f22018-01-05 11:39:28 +01001783static void soinfo_unload_impl(soinfo* root) {
Dimitry Ivanov6705e8c2017-03-21 10:29:06 -07001784 ScopedTrace trace((std::string("unload ") + root->get_realpath()).c_str());
dimitry06016f22018-01-05 11:39:28 +01001785 bool is_linked = root->is_linked();
Dimitry Ivanov6705e8c2017-03-21 10:29:06 -07001786
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001787 if (!root->can_unload()) {
dimitryc92ce712017-10-27 14:12:53 +02001788 LD_LOG(kLogDlopen,
1789 "... dlclose(root=\"%s\"@%p) ... not unloading - the load group is flagged with NODELETE",
1790 root->get_realpath(),
1791 root);
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -07001792 return;
1793 }
1794
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001795
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001796 soinfo_list_t unload_list;
dimitry965d06d2017-11-28 16:03:07 +01001797 unload_list.push_back(root);
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001798
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001799 soinfo_list_t local_unload_list;
1800 soinfo_list_t external_unload_list;
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001801 soinfo* si = nullptr;
1802
1803 while ((si = unload_list.pop_front()) != nullptr) {
1804 if (local_unload_list.contains(si)) {
1805 continue;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001806 }
Elliott Hughesd23736e2012-11-01 15:16:56 -07001807
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001808 local_unload_list.push_back(si);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001809
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001810 if (si->has_min_version(0)) {
1811 soinfo* child = nullptr;
1812 while ((child = si->get_children().pop_front()) != nullptr) {
1813 TRACE("%s@%p needs to unload %s@%p", si->get_realpath(), si,
1814 child->get_realpath(), child);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001815
Dimitry Ivanovec90e242017-02-10 11:04:20 -08001816 child->get_parents().remove(si);
1817
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001818 if (local_unload_list.contains(child)) {
1819 continue;
1820 } else if (child->is_linked() && child->get_local_group_root() != root) {
1821 external_unload_list.push_back(child);
Dimitry Ivanovec90e242017-02-10 11:04:20 -08001822 } else if (child->get_parents().empty()) {
1823 unload_list.push_back(child);
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001824 }
1825 }
1826 } else {
1827#if !defined(__work_around_b_24465209__)
Christopher Ferris7a3681e2017-04-24 17:48:32 -07001828 async_safe_fatal("soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001829#else
1830 PRINT("warning: soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
1831 for_each_dt_needed(si, [&] (const char* library_name) {
1832 TRACE("deprecated (old format of soinfo): %s needs to unload %s",
1833 si->get_realpath(), library_name);
1834
1835 soinfo* needed = find_library(si->get_primary_namespace(),
1836 library_name, RTLD_NOLOAD, nullptr, nullptr);
1837
1838 if (needed != nullptr) {
1839 // Not found: for example if symlink was deleted between dlopen and dlclose
1840 // Since we cannot really handle errors at this point - print and continue.
1841 PRINT("warning: couldn't find %s needed by %s on unload.",
1842 library_name, si->get_realpath());
1843 return;
1844 } else if (local_unload_list.contains(needed)) {
1845 // already visited
1846 return;
1847 } else if (needed->is_linked() && needed->get_local_group_root() != root) {
1848 // external group
1849 external_unload_list.push_back(needed);
1850 } else {
1851 // local group
1852 unload_list.push_front(needed);
1853 }
1854 });
1855#endif
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001856 }
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001857 }
1858
1859 local_unload_list.for_each([](soinfo* si) {
dimitryc92ce712017-10-27 14:12:53 +02001860 LD_LOG(kLogDlopen,
1861 "... dlclose: calling destructors for \"%s\"@%p ... ",
1862 si->get_realpath(),
1863 si);
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001864 si->call_destructors();
dimitryc92ce712017-10-27 14:12:53 +02001865 LD_LOG(kLogDlopen,
1866 "... dlclose: calling destructors for \"%s\"@%p ... done",
1867 si->get_realpath(),
1868 si);
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001869 });
1870
1871 while ((si = local_unload_list.pop_front()) != nullptr) {
dimitryc92ce712017-10-27 14:12:53 +02001872 LD_LOG(kLogDlopen,
1873 "... dlclose: unloading \"%s\"@%p ...",
1874 si->get_realpath(),
1875 si);
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001876 notify_gdb_of_unload(si);
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -07001877 get_cfi_shadow()->BeforeUnload(si);
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001878 soinfo_free(si);
1879 }
1880
dimitry965d06d2017-11-28 16:03:07 +01001881 if (is_linked) {
1882 while ((si = external_unload_list.pop_front()) != nullptr) {
1883 LD_LOG(kLogDlopen,
1884 "... dlclose: unloading external reference \"%s\"@%p ...",
1885 si->get_realpath(),
1886 si);
1887 soinfo_unload(si);
1888 }
1889 } else {
1890 LD_LOG(kLogDlopen,
1891 "... dlclose: unload_si was not linked - not unloading external references ...");
Dmitriy Ivanova2547052014-11-18 12:03:09 -08001892 }
1893}
1894
dimitry06016f22018-01-05 11:39:28 +01001895static void soinfo_unload(soinfo* unload_si) {
1896 // Note that the library can be loaded but not linked;
1897 // in which case there is no root but we still need
1898 // to walk the tree and unload soinfos involved.
1899 //
1900 // This happens on unsuccessful dlopen, when one of
1901 // the DT_NEEDED libraries could not be linked/found.
1902 bool is_linked = unload_si->is_linked();
1903 soinfo* root = is_linked ? unload_si->get_local_group_root() : unload_si;
1904
1905 LD_LOG(kLogDlopen,
1906 "... dlclose(realpath=\"%s\"@%p) ... load group root is \"%s\"@%p",
1907 unload_si->get_realpath(),
1908 unload_si,
1909 root->get_realpath(),
1910 root);
1911
1912
1913 size_t ref_count = is_linked ? root->decrement_ref_count() : 0;
1914 if (ref_count > 0) {
1915 LD_LOG(kLogDlopen,
1916 "... dlclose(root=\"%s\"@%p) ... not unloading - decrementing ref_count to %zd",
1917 root->get_realpath(),
1918 root,
1919 ref_count);
1920 return;
1921 }
1922
1923 soinfo_unload_impl(root);
1924}
1925
1926void increment_dso_handle_reference_counter(void* dso_handle) {
1927 if (dso_handle == nullptr) {
1928 return;
1929 }
1930
1931 auto it = g_dso_handle_counters.find(dso_handle);
1932 if (it != g_dso_handle_counters.end()) {
1933 CHECK(++it->second != 0);
1934 } else {
1935 soinfo* si = find_containing_library(dso_handle);
1936 if (si != nullptr) {
1937 ProtectedDataGuard guard;
1938 si->set_tls_nodelete();
1939 } else {
1940 async_safe_fatal(
1941 "increment_dso_handle_reference_counter: Couldn't find soinfo by dso_handle=%p",
1942 dso_handle);
1943 }
1944 g_dso_handle_counters[dso_handle] = 1U;
1945 }
1946}
1947
1948void decrement_dso_handle_reference_counter(void* dso_handle) {
1949 if (dso_handle == nullptr) {
1950 return;
1951 }
1952
1953 auto it = g_dso_handle_counters.find(dso_handle);
1954 CHECK(it != g_dso_handle_counters.end());
1955 CHECK(it->second != 0);
1956
1957 if (--it->second == 0) {
1958 soinfo* si = find_containing_library(dso_handle);
1959 if (si != nullptr) {
1960 ProtectedDataGuard guard;
1961 si->unset_tls_nodelete();
1962 if (si->get_ref_count() == 0) {
1963 // Perform deferred unload - note that soinfo_unload_impl does not decrement ref_count
1964 soinfo_unload_impl(si);
1965 }
1966 } else {
1967 async_safe_fatal(
1968 "decrement_dso_handle_reference_counter: Couldn't find soinfo by dso_handle=%p",
1969 dso_handle);
1970 }
1971 g_dso_handle_counters.erase(it);
1972 }
1973}
1974
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001975static std::string symbol_display_name(const char* sym_name, const char* sym_ver) {
1976 if (sym_ver == nullptr) {
1977 return sym_name;
1978 }
1979
Dimitry Ivanov9cf99cb2015-12-11 14:22:24 -08001980 return std::string(sym_name) + ", version " + sym_ver;
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001981}
1982
Dimitry Ivanovaca299a2016-04-11 12:42:58 -07001983static android_namespace_t* get_caller_namespace(soinfo* caller) {
1984 return caller != nullptr ? caller->get_primary_namespace() : g_anonymous_namespace;
1985}
1986
Elliott Hughesa4aafd12014-01-13 16:37:47 -08001987void do_android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size) {
Christopher Ferris052fa3a2014-08-26 20:48:11 -07001988 // Use basic string manipulation calls to avoid snprintf.
1989 // snprintf indirectly calls pthread_getspecific to get the size of a buffer.
1990 // When debug malloc is enabled, this call returns 0. This in turn causes
1991 // snprintf to do nothing, which causes libraries to fail to load.
1992 // See b/17302493 for further details.
1993 // Once the above bug is fixed, this code can be modified to use
1994 // snprintf again.
Dimitry Ivanov77ad6422017-03-06 13:02:29 -08001995 const auto& default_ld_paths = g_default_namespace.get_default_library_paths();
1996
1997 size_t required_size = 0;
1998 for (const auto& path : default_ld_paths) {
1999 required_size += path.size() + 1;
Evgenii Stepanovd640b222015-07-10 17:54:01 -07002000 }
Dimitry Ivanov77ad6422017-03-06 13:02:29 -08002001
2002 if (buffer_size < required_size) {
Christopher Ferris7a3681e2017-04-24 17:48:32 -07002003 async_safe_fatal("android_get_LD_LIBRARY_PATH failed, buffer too small: "
2004 "buffer len %zu, required len %zu", buffer_size, required_size);
Christopher Ferris052fa3a2014-08-26 20:48:11 -07002005 }
Dimitry Ivanov77ad6422017-03-06 13:02:29 -08002006
Evgenii Stepanovd640b222015-07-10 17:54:01 -07002007 char* end = buffer;
Dimitry Ivanov77ad6422017-03-06 13:02:29 -08002008 for (size_t i = 0; i < default_ld_paths.size(); ++i) {
Evgenii Stepanovd640b222015-07-10 17:54:01 -07002009 if (i > 0) *end++ = ':';
Dimitry Ivanov77ad6422017-03-06 13:02:29 -08002010 end = stpcpy(end, default_ld_paths[i].c_str());
Evgenii Stepanovd640b222015-07-10 17:54:01 -07002011 }
Elliott Hughesa4aafd12014-01-13 16:37:47 -08002012}
2013
Elliott Hughescade4c32012-12-20 14:42:14 -08002014void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path) {
Nick Kralevich6bb01b62015-03-07 13:37:05 -08002015 parse_LD_LIBRARY_PATH(ld_library_path);
Elliott Hughescade4c32012-12-20 14:42:14 -08002016}
2017
Dimitry Ivanovb996d602016-07-11 18:11:39 -07002018static std::string android_dlextinfo_to_string(const android_dlextinfo* info) {
2019 if (info == nullptr) {
2020 return "(null)";
2021 }
2022
2023 return android::base::StringPrintf("[flags=0x%" PRIx64 ","
2024 " reserved_addr=%p,"
2025 " reserved_size=0x%zx,"
2026 " relro_fd=%d,"
2027 " library_fd=%d,"
2028 " library_fd_offset=0x%" PRIx64 ","
2029 " library_namespace=%s@%p]",
2030 info->flags,
2031 info->reserved_addr,
2032 info->reserved_size,
2033 info->relro_fd,
2034 info->library_fd,
2035 info->library_fd_offset,
2036 (info->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0 ?
2037 (info->library_namespace != nullptr ?
2038 info->library_namespace->get_name() : "(null)") : "(n/a)",
2039 (info->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0 ?
2040 info->library_namespace : nullptr);
2041}
2042
Dimitry Ivanovd9e427c2016-11-22 16:55:25 -08002043void* do_dlopen(const char* name, int flags,
2044 const android_dlextinfo* extinfo,
2045 const void* caller_addr) {
Dimitry Ivanov5c4a5802017-03-17 16:41:34 -07002046 std::string trace_prefix = std::string("dlopen: ") + (name == nullptr ? "(nullptr)" : name);
2047 ScopedTrace trace(trace_prefix.c_str());
2048 ScopedTrace loading_trace((trace_prefix + " - loading and linking").c_str());
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08002049 soinfo* const caller = find_containing_library(caller_addr);
Dimitry Ivanovb996d602016-07-11 18:11:39 -07002050 android_namespace_t* ns = get_caller_namespace(caller);
2051
2052 LD_LOG(kLogDlopen,
2053 "dlopen(name=\"%s\", flags=0x%x, extinfo=%s, caller=\"%s\", caller_ns=%s@%p) ...",
2054 name,
2055 flags,
2056 android_dlextinfo_to_string(extinfo).c_str(),
2057 caller == nullptr ? "(null)" : caller->get_realpath(),
2058 ns == nullptr ? "(null)" : ns->get_name(),
2059 ns);
2060
Tom Cherryb8ab6182017-04-05 16:20:29 -07002061 auto failure_guard = android::base::make_scope_guard(
2062 [&]() { LD_LOG(kLogDlopen, "... dlopen failed: %s", linker_get_error_buffer()); });
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08002063
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -07002064 if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL|RTLD_NODELETE|RTLD_NOLOAD)) != 0) {
Elliott Hughese66190d2012-12-18 15:57:55 -08002065 DL_ERR("invalid flags to dlopen: %x", flags);
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07002066 return nullptr;
Elliott Hughese66190d2012-12-18 15:57:55 -08002067 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002068
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07002069 if (extinfo != nullptr) {
2070 if ((extinfo->flags & ~(ANDROID_DLEXT_VALID_FLAG_BITS)) != 0) {
2071 DL_ERR("invalid extended flags to android_dlopen_ext: 0x%" PRIx64, extinfo->flags);
2072 return nullptr;
2073 }
Dmitriy Ivanov126af752015-10-07 16:34:20 -07002074
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07002075 if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) == 0 &&
Dmitriy Ivanova6c12792014-10-21 12:09:18 -07002076 (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002077 DL_ERR("invalid extended flag combination (ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET without "
2078 "ANDROID_DLEXT_USE_LIBRARY_FD): 0x%" PRIx64, extinfo->flags);
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07002079 return nullptr;
2080 }
Dmitriy Ivanov126af752015-10-07 16:34:20 -07002081
2082 if ((extinfo->flags & ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS) != 0 &&
2083 (extinfo->flags & (ANDROID_DLEXT_RESERVED_ADDRESS | ANDROID_DLEXT_RESERVED_ADDRESS_HINT)) != 0) {
2084 DL_ERR("invalid extended flag combination: ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS is not "
2085 "compatible with ANDROID_DLEXT_RESERVED_ADDRESS/ANDROID_DLEXT_RESERVED_ADDRESS_HINT");
2086 return nullptr;
2087 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002088
2089 if ((extinfo->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0) {
2090 if (extinfo->library_namespace == nullptr) {
2091 DL_ERR("ANDROID_DLEXT_USE_NAMESPACE is set but extinfo->library_namespace is null");
2092 return nullptr;
2093 }
2094 ns = extinfo->library_namespace;
2095 }
Torne (Richard Coles)012cb452014-02-06 14:34:21 +00002096 }
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -08002097
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -07002098 std::string asan_name_holder;
2099
2100 const char* translated_name = name;
Dimitry Ivanov6c14f862016-12-05 13:35:47 -08002101 if (g_is_asan && translated_name != nullptr && translated_name[0] == '/') {
Evgenii Stepanov9e77a642017-07-27 14:55:44 -07002102 char original_path[PATH_MAX];
2103 if (realpath(name, original_path) != nullptr) {
2104 asan_name_holder = std::string(kAsanLibDirPrefix) + original_path;
Vishwath Mohan4113def2017-03-29 15:31:34 -07002105 if (file_exists(asan_name_holder.c_str())) {
Evgenii Stepanov9e77a642017-07-27 14:55:44 -07002106 soinfo* si = nullptr;
2107 if (find_loaded_library_by_realpath(ns, original_path, true, &si)) {
2108 PRINT("linker_asan dlopen NOT translating \"%s\" -> \"%s\": library already loaded", name,
2109 asan_name_holder.c_str());
2110 } else {
2111 PRINT("linker_asan dlopen translating \"%s\" -> \"%s\"", name, translated_name);
2112 translated_name = asan_name_holder.c_str();
2113 }
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -07002114 }
2115 }
2116 }
2117
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -08002118 ProtectedDataGuard guard;
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -07002119 soinfo* si = find_library(ns, translated_name, flags, extinfo, caller);
Dimitry Ivanov5c4a5802017-03-17 16:41:34 -07002120 loading_trace.End();
2121
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07002122 if (si != nullptr) {
Dimitry Ivanovb996d602016-07-11 18:11:39 -07002123 void* handle = si->to_handle();
2124 LD_LOG(kLogDlopen,
Dimitry Ivanovae4a0c12016-11-21 10:44:35 -08002125 "... dlopen calling constructors: realpath=\"%s\", soname=\"%s\", handle=%p",
2126 si->get_realpath(), si->get_soname(), handle);
2127 si->call_constructors();
Tom Cherryb8ab6182017-04-05 16:20:29 -07002128 failure_guard.Disable();
Dimitry Ivanovae4a0c12016-11-21 10:44:35 -08002129 LD_LOG(kLogDlopen,
Dimitry Ivanovb996d602016-07-11 18:11:39 -07002130 "... dlopen successful: realpath=\"%s\", soname=\"%s\", handle=%p",
2131 si->get_realpath(), si->get_soname(), handle);
2132 return handle;
Elliott Hughesd23736e2012-11-01 15:16:56 -07002133 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002134
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07002135 return nullptr;
Elliott Hughesd23736e2012-11-01 15:16:56 -07002136}
2137
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08002138int do_dladdr(const void* addr, Dl_info* info) {
2139 // Determine if this address can be found in any library currently mapped.
2140 soinfo* si = find_containing_library(addr);
2141 if (si == nullptr) {
2142 return 0;
2143 }
2144
2145 memset(info, 0, sizeof(Dl_info));
2146
2147 info->dli_fname = si->get_realpath();
2148 // Address at which the shared object is loaded.
2149 info->dli_fbase = reinterpret_cast<void*>(si->base);
2150
2151 // Determine if any symbol in the library contains the specified address.
2152 ElfW(Sym)* sym = si->find_symbol_by_address(addr);
2153 if (sym != nullptr) {
2154 info->dli_sname = si->get_string(sym->st_name);
2155 info->dli_saddr = reinterpret_cast<void*>(si->resolve_symbol_address(sym));
2156 }
2157
2158 return 1;
2159}
2160
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07002161static soinfo* soinfo_from_handle(void* handle) {
2162 if ((reinterpret_cast<uintptr_t>(handle) & 1) != 0) {
2163 auto it = g_soinfo_handles_map.find(reinterpret_cast<uintptr_t>(handle));
2164 if (it == g_soinfo_handles_map.end()) {
2165 return nullptr;
2166 } else {
2167 return it->second;
2168 }
2169 }
2170
2171 return static_cast<soinfo*>(handle);
2172}
2173
Dimitry Ivanovd9e427c2016-11-22 16:55:25 -08002174bool do_dlsym(void* handle,
2175 const char* sym_name,
2176 const char* sym_ver,
2177 const void* caller_addr,
2178 void** symbol) {
Dimitry Ivanov6705e8c2017-03-21 10:29:06 -07002179 ScopedTrace trace("dlsym");
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08002180#if !defined(__LP64__)
2181 if (handle == nullptr) {
2182 DL_ERR("dlsym failed: library handle is null");
2183 return false;
2184 }
2185#endif
2186
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08002187 soinfo* found = nullptr;
2188 const ElfW(Sym)* sym = nullptr;
2189 soinfo* caller = find_containing_library(caller_addr);
Dimitry Ivanovaca299a2016-04-11 12:42:58 -07002190 android_namespace_t* ns = get_caller_namespace(caller);
Dimitry Ivanov4742abd2016-12-12 16:30:15 -08002191 soinfo* si = nullptr;
2192 if (handle != RTLD_DEFAULT && handle != RTLD_NEXT) {
2193 si = soinfo_from_handle(handle);
2194 }
2195
2196 LD_LOG(kLogDlsym,
2197 "dlsym(handle=%p(\"%s\"), sym_name=\"%s\", sym_ver=\"%s\", caller=\"%s\", caller_ns=%s@%p) ...",
2198 handle,
2199 si != nullptr ? si->get_realpath() : "n/a",
2200 sym_name,
2201 sym_ver,
2202 caller == nullptr ? "(null)" : caller->get_realpath(),
2203 ns == nullptr ? "(null)" : ns->get_name(),
2204 ns);
2205
Tom Cherryb8ab6182017-04-05 16:20:29 -07002206 auto failure_guard = android::base::make_scope_guard(
2207 [&]() { LD_LOG(kLogDlsym, "... dlsym failed: %s", linker_get_error_buffer()); });
Dimitry Ivanov4742abd2016-12-12 16:30:15 -08002208
2209 if (sym_name == nullptr) {
2210 DL_ERR("dlsym failed: symbol name is null");
2211 return false;
2212 }
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08002213
2214 version_info vi_instance;
2215 version_info* vi = nullptr;
2216
2217 if (sym_ver != nullptr) {
Dimitry Ivanov9cf99cb2015-12-11 14:22:24 -08002218 vi_instance.name = sym_ver;
2219 vi_instance.elf_hash = calculate_elf_hash(sym_ver);
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08002220 vi = &vi_instance;
2221 }
2222
2223 if (handle == RTLD_DEFAULT || handle == RTLD_NEXT) {
2224 sym = dlsym_linear_lookup(ns, sym_name, vi, &found, caller, handle);
2225 } else {
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07002226 if (si == nullptr) {
2227 DL_ERR("dlsym failed: invalid handle: %p", handle);
2228 return false;
2229 }
2230 sym = dlsym_handle_lookup(si, &found, sym_name, vi);
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08002231 }
2232
2233 if (sym != nullptr) {
2234 uint32_t bind = ELF_ST_BIND(sym->st_info);
2235
2236 if ((bind == STB_GLOBAL || bind == STB_WEAK) && sym->st_shndx != 0) {
2237 *symbol = reinterpret_cast<void*>(found->resolve_symbol_address(sym));
Tom Cherryb8ab6182017-04-05 16:20:29 -07002238 failure_guard.Disable();
Dimitry Ivanov4742abd2016-12-12 16:30:15 -08002239 LD_LOG(kLogDlsym,
2240 "... dlsym successful: sym_name=\"%s\", sym_ver=\"%s\", found in=\"%s\", address=%p",
2241 sym_name, sym_ver, found->get_soname(), *symbol);
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08002242 return true;
2243 }
2244
2245 DL_ERR("symbol \"%s\" found but not global", symbol_display_name(sym_name, sym_ver).c_str());
2246 return false;
2247 }
2248
2249 DL_ERR("undefined symbol: %s", symbol_display_name(sym_name, sym_ver).c_str());
2250 return false;
2251}
2252
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07002253int do_dlclose(void* handle) {
Dimitry Ivanov6705e8c2017-03-21 10:29:06 -07002254 ScopedTrace trace("dlclose");
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -08002255 ProtectedDataGuard guard;
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07002256 soinfo* si = soinfo_from_handle(handle);
2257 if (si == nullptr) {
2258 DL_ERR("invalid handle: %p", handle);
2259 return -1;
2260 }
2261
dimitryc92ce712017-10-27 14:12:53 +02002262 LD_LOG(kLogDlopen,
2263 "dlclose(handle=%p, realpath=\"%s\"@%p) ...",
2264 handle,
2265 si->get_realpath(),
2266 si);
Dmitriy Ivanovb648a8a2014-05-19 15:06:58 -07002267 soinfo_unload(si);
dimitryc92ce712017-10-27 14:12:53 +02002268 LD_LOG(kLogDlopen,
2269 "dlclose(handle=%p) ... done",
2270 handle);
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07002271 return 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002272}
2273
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -08002274bool init_anonymous_namespace(const char* shared_lib_sonames, const char* library_search_path) {
2275 if (g_anonymous_namespace_initialized) {
2276 DL_ERR("anonymous namespace has already been initialized.");
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002277 return false;
2278 }
2279
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002280 ProtectedDataGuard guard;
2281
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002282 // create anonymous namespace
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002283 // When the caller is nullptr - create_namespace will take global group
2284 // from the anonymous namespace, which is fine because anonymous namespace
2285 // is still pointing to the default one.
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002286 android_namespace_t* anon_ns =
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -08002287 create_namespace(nullptr,
2288 "(anonymous)",
2289 nullptr,
2290 library_search_path,
Dimitry Ivanovc9dced22017-03-27 15:42:17 -07002291 ANDROID_NAMESPACE_TYPE_ISOLATED,
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -08002292 nullptr,
2293 &g_default_namespace);
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002294
2295 if (anon_ns == nullptr) {
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -08002296 return false;
2297 }
2298
2299 if (!link_namespaces(anon_ns, &g_default_namespace, shared_lib_sonames)) {
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002300 return false;
2301 }
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08002302
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002303 g_anonymous_namespace = anon_ns;
Dimitry Ivanov3e0821d2017-03-07 11:02:10 -08002304 g_anonymous_namespace_initialized = true;
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -08002305
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002306 return true;
2307}
2308
Dimitry Ivanovb943f302016-08-03 16:00:10 -07002309static void add_soinfos_to_namespace(const soinfo_list_t& soinfos, android_namespace_t* ns) {
2310 ns->add_soinfos(soinfos);
2311 for (auto si : soinfos) {
2312 si->add_secondary_namespace(ns);
2313 }
2314}
2315
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002316android_namespace_t* create_namespace(const void* caller_addr,
2317 const char* name,
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002318 const char* ld_library_path,
2319 const char* default_library_path,
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002320 uint64_t type,
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002321 const char* permitted_when_isolated_path,
2322 android_namespace_t* parent_namespace) {
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002323 if (parent_namespace == nullptr) {
Dimitry Ivanov52408632016-05-23 10:31:11 -07002324 // if parent_namespace is nullptr -> set it to the caller namespace
2325 soinfo* caller_soinfo = find_containing_library(caller_addr);
2326
2327 parent_namespace = caller_soinfo != nullptr ?
2328 caller_soinfo->get_primary_namespace() :
2329 g_anonymous_namespace;
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002330 }
2331
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002332 ProtectedDataGuard guard;
2333 std::vector<std::string> ld_library_paths;
2334 std::vector<std::string> default_library_paths;
Dimitry Ivanov284ae352015-12-08 10:47:13 -08002335 std::vector<std::string> permitted_paths;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002336
2337 parse_path(ld_library_path, ":", &ld_library_paths);
2338 parse_path(default_library_path, ":", &default_library_paths);
Dimitry Ivanov284ae352015-12-08 10:47:13 -08002339 parse_path(permitted_when_isolated_path, ":", &permitted_paths);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002340
2341 android_namespace_t* ns = new (g_namespace_allocator.alloc()) android_namespace_t();
2342 ns->set_name(name);
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002343 ns->set_isolated((type & ANDROID_NAMESPACE_TYPE_ISOLATED) != 0);
Jiyong Park37b91af2017-05-05 22:07:05 +09002344 ns->set_greylist_enabled((type & ANDROID_NAMESPACE_TYPE_GREYLIST_ENABLED) != 0);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002345
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002346 if ((type & ANDROID_NAMESPACE_TYPE_SHARED) != 0) {
Dimitry Ivanovf1cb6692017-05-01 17:45:38 -07002347 // append parent namespace paths.
2348 std::copy(parent_namespace->get_ld_library_paths().begin(),
2349 parent_namespace->get_ld_library_paths().end(),
2350 back_inserter(ld_library_paths));
2351
2352 std::copy(parent_namespace->get_default_library_paths().begin(),
2353 parent_namespace->get_default_library_paths().end(),
2354 back_inserter(default_library_paths));
2355
2356 std::copy(parent_namespace->get_permitted_paths().begin(),
2357 parent_namespace->get_permitted_paths().end(),
2358 back_inserter(permitted_paths));
2359
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002360 // If shared - clone the parent namespace
Dimitry Ivanovb943f302016-08-03 16:00:10 -07002361 add_soinfos_to_namespace(parent_namespace->soinfo_list(), ns);
Dimitry Ivanovf1cb6692017-05-01 17:45:38 -07002362 // and copy parent namespace links
2363 for (auto& link : parent_namespace->linked_namespaces()) {
Logan Chien9ee45912018-01-18 12:05:09 +08002364 ns->add_linked_namespace(link.linked_namespace(), link.shared_lib_sonames(),
2365 link.allow_all_shared_libs());
Dimitry Ivanovf1cb6692017-05-01 17:45:38 -07002366 }
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002367 } else {
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002368 // If not shared - copy only the shared group
Jiyong Park02586a22017-05-20 01:01:24 +09002369 add_soinfos_to_namespace(parent_namespace->get_shared_group(), ns);
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002370 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002371
Dimitry Ivanovf1cb6692017-05-01 17:45:38 -07002372 ns->set_ld_library_paths(std::move(ld_library_paths));
2373 ns->set_default_library_paths(std::move(default_library_paths));
2374 ns->set_permitted_paths(std::move(permitted_paths));
2375
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002376 return ns;
2377}
2378
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -08002379bool link_namespaces(android_namespace_t* namespace_from,
2380 android_namespace_t* namespace_to,
2381 const char* shared_lib_sonames) {
2382 if (namespace_to == nullptr) {
2383 namespace_to = &g_default_namespace;
2384 }
2385
2386 if (namespace_from == nullptr) {
2387 DL_ERR("error linking namespaces: namespace_from is null.");
2388 return false;
2389 }
2390
2391 if (shared_lib_sonames == nullptr || shared_lib_sonames[0] == '\0') {
2392 DL_ERR("error linking namespaces \"%s\"->\"%s\": the list of shared libraries is empty.",
2393 namespace_from->get_name(), namespace_to->get_name());
2394 return false;
2395 }
2396
2397 auto sonames = android::base::Split(shared_lib_sonames, ":");
2398 std::unordered_set<std::string> sonames_set(sonames.begin(), sonames.end());
2399
2400 ProtectedDataGuard guard;
Logan Chien9ee45912018-01-18 12:05:09 +08002401 namespace_from->add_linked_namespace(namespace_to, sonames_set, false);
2402
2403 return true;
2404}
2405
2406bool link_namespaces_all_libs(android_namespace_t* namespace_from,
2407 android_namespace_t* namespace_to) {
2408 if (namespace_from == nullptr) {
2409 DL_ERR("error linking namespaces: namespace_from is null.");
2410 return false;
2411 }
2412
2413 if (namespace_to == nullptr) {
2414 DL_ERR("error linking namespaces: namespace_to is null.");
2415 return false;
2416 }
2417
2418 ProtectedDataGuard guard;
2419 namespace_from->add_linked_namespace(namespace_to, std::unordered_set<std::string>(), true);
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -08002420
2421 return true;
2422}
2423
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002424ElfW(Addr) call_ifunc_resolver(ElfW(Addr) resolver_addr) {
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07002425 typedef ElfW(Addr) (*ifunc_resolver_t)(void);
2426 ifunc_resolver_t ifunc_resolver = reinterpret_cast<ifunc_resolver_t>(resolver_addr);
2427 ElfW(Addr) ifunc_addr = ifunc_resolver();
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002428 TRACE_TYPE(RELO, "Called ifunc_resolver@%p. The result is %p",
2429 ifunc_resolver, reinterpret_cast<void*>(ifunc_addr));
Brigid Smithc5a13ef2014-07-23 11:22:25 -07002430
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07002431 return ifunc_addr;
Brigid Smithc5a13ef2014-07-23 11:22:25 -07002432}
Brigid Smithc5a13ef2014-07-23 11:22:25 -07002433
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002434const version_info* VersionTracker::get_version_info(ElfW(Versym) source_symver) const {
2435 if (source_symver < 2 ||
2436 source_symver >= version_infos.size() ||
2437 version_infos[source_symver].name == nullptr) {
2438 return nullptr;
2439 }
2440
2441 return &version_infos[source_symver];
2442}
2443
2444void VersionTracker::add_version_info(size_t source_index,
2445 ElfW(Word) elf_hash,
2446 const char* ver_name,
2447 const soinfo* target_si) {
2448 if (source_index >= version_infos.size()) {
2449 version_infos.resize(source_index+1);
2450 }
2451
2452 version_infos[source_index].elf_hash = elf_hash;
2453 version_infos[source_index].name = ver_name;
2454 version_infos[source_index].target_si = target_si;
2455}
2456
2457bool VersionTracker::init_verneed(const soinfo* si_from) {
2458 uintptr_t verneed_ptr = si_from->get_verneed_ptr();
2459
2460 if (verneed_ptr == 0) {
2461 return true;
2462 }
2463
2464 size_t verneed_cnt = si_from->get_verneed_cnt();
2465
2466 for (size_t i = 0, offset = 0; i<verneed_cnt; ++i) {
2467 const ElfW(Verneed)* verneed = reinterpret_cast<ElfW(Verneed)*>(verneed_ptr + offset);
2468 size_t vernaux_offset = offset + verneed->vn_aux;
2469 offset += verneed->vn_next;
2470
2471 if (verneed->vn_version != 1) {
2472 DL_ERR("unsupported verneed[%zd] vn_version: %d (expected 1)", i, verneed->vn_version);
2473 return false;
2474 }
2475
2476 const char* target_soname = si_from->get_string(verneed->vn_file);
2477 // find it in dependencies
2478 soinfo* target_si = si_from->get_children().find_if([&](const soinfo* si) {
Dmitriy Ivanov406d9962015-05-06 11:05:27 -07002479 return si->get_soname() != nullptr && strcmp(si->get_soname(), target_soname) == 0;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002480 });
2481
2482 if (target_si == nullptr) {
2483 DL_ERR("cannot find \"%s\" from verneed[%zd] in DT_NEEDED list for \"%s\"",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002484 target_soname, i, si_from->get_realpath());
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002485 return false;
2486 }
2487
2488 for (size_t j = 0; j<verneed->vn_cnt; ++j) {
2489 const ElfW(Vernaux)* vernaux = reinterpret_cast<ElfW(Vernaux)*>(verneed_ptr + vernaux_offset);
2490 vernaux_offset += vernaux->vna_next;
2491
2492 const ElfW(Word) elf_hash = vernaux->vna_hash;
2493 const char* ver_name = si_from->get_string(vernaux->vna_name);
2494 ElfW(Half) source_index = vernaux->vna_other;
2495
2496 add_version_info(source_index, elf_hash, ver_name, target_si);
2497 }
2498 }
2499
2500 return true;
2501}
2502
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002503template <typename F>
2504static bool for_each_verdef(const soinfo* si, F functor) {
2505 if (!si->has_min_version(2)) {
2506 return true;
2507 }
2508
2509 uintptr_t verdef_ptr = si->get_verdef_ptr();
2510 if (verdef_ptr == 0) {
2511 return true;
2512 }
2513
2514 size_t offset = 0;
2515
2516 size_t verdef_cnt = si->get_verdef_cnt();
2517 for (size_t i = 0; i<verdef_cnt; ++i) {
2518 const ElfW(Verdef)* verdef = reinterpret_cast<ElfW(Verdef)*>(verdef_ptr + offset);
2519 size_t verdaux_offset = offset + verdef->vd_aux;
2520 offset += verdef->vd_next;
2521
2522 if (verdef->vd_version != 1) {
2523 DL_ERR("unsupported verdef[%zd] vd_version: %d (expected 1) library: %s",
2524 i, verdef->vd_version, si->get_realpath());
2525 return false;
2526 }
2527
2528 if ((verdef->vd_flags & VER_FLG_BASE) != 0) {
2529 // "this is the version of the file itself. It must not be used for
2530 // matching a symbol. It can be used to match references."
2531 //
2532 // http://www.akkadia.org/drepper/symbol-versioning
2533 continue;
2534 }
2535
2536 if (verdef->vd_cnt == 0) {
2537 DL_ERR("invalid verdef[%zd] vd_cnt == 0 (version without a name)", i);
2538 return false;
2539 }
2540
2541 const ElfW(Verdaux)* verdaux = reinterpret_cast<ElfW(Verdaux)*>(verdef_ptr + verdaux_offset);
2542
2543 if (functor(i, verdef, verdaux) == true) {
2544 break;
2545 }
2546 }
2547
2548 return true;
2549}
2550
2551bool find_verdef_version_index(const soinfo* si, const version_info* vi, ElfW(Versym)* versym) {
2552 if (vi == nullptr) {
2553 *versym = kVersymNotNeeded;
2554 return true;
2555 }
2556
2557 *versym = kVersymGlobal;
2558
2559 return for_each_verdef(si,
2560 [&](size_t, const ElfW(Verdef)* verdef, const ElfW(Verdaux)* verdaux) {
2561 if (verdef->vd_hash == vi->elf_hash &&
2562 strcmp(vi->name, si->get_string(verdaux->vda_name)) == 0) {
2563 *versym = verdef->vd_ndx;
2564 return true;
2565 }
2566
2567 return false;
2568 }
2569 );
2570}
2571
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002572bool VersionTracker::init_verdef(const soinfo* si_from) {
2573 return for_each_verdef(si_from,
2574 [&](size_t, const ElfW(Verdef)* verdef, const ElfW(Verdaux)* verdaux) {
2575 add_version_info(verdef->vd_ndx, verdef->vd_hash,
2576 si_from->get_string(verdaux->vda_name), si_from);
2577 return false;
2578 }
2579 );
2580}
2581
2582bool VersionTracker::init(const soinfo* si_from) {
2583 if (!si_from->has_min_version(2)) {
2584 return true;
2585 }
2586
2587 return init_verneed(si_from) && init_verdef(si_from);
2588}
2589
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002590// TODO (dimitry): Methods below need to be moved out of soinfo
2591// and in more isolated file in order minimize dependencies on
2592// unnecessary object in the linker binary. Consider making them
2593// independent from soinfo (?).
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002594bool soinfo::lookup_version_info(const VersionTracker& version_tracker, ElfW(Word) sym,
2595 const char* sym_name, const version_info** vi) {
2596 const ElfW(Versym)* sym_ver_ptr = get_versym(sym);
2597 ElfW(Versym) sym_ver = sym_ver_ptr == nullptr ? 0 : *sym_ver_ptr;
2598
2599 if (sym_ver != VER_NDX_LOCAL && sym_ver != VER_NDX_GLOBAL) {
2600 *vi = version_tracker.get_version_info(sym_ver);
2601
2602 if (*vi == nullptr) {
2603 DL_ERR("cannot find verneed/verdef for version index=%d "
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002604 "referenced by symbol \"%s\" at \"%s\"", sym_ver, sym_name, get_realpath());
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002605 return false;
2606 }
2607 } else {
2608 // there is no version info
2609 *vi = nullptr;
2610 }
2611
2612 return true;
2613}
2614
Rahul Chaudhryf16b6592018-01-25 15:34:15 -08002615void soinfo::apply_relr_reloc(ElfW(Addr) offset) {
2616 ElfW(Addr) address = offset + load_bias;
2617 *reinterpret_cast<ElfW(Addr)*>(address) += load_bias;
2618}
2619
Rahul Chaudhryb7feec72017-12-19 15:25:23 -08002620// Process relocations in SHT_RELR section (experimental).
Rahul Chaudhryf16b6592018-01-25 15:34:15 -08002621// Details of the encoding are described in this post:
2622// https://groups.google.com/d/msg/generic-abi/bX460iggiKg/Pi9aSwwABgAJ
Rahul Chaudhryb7feec72017-12-19 15:25:23 -08002623bool soinfo::relocate_relr() {
2624 ElfW(Relr)* begin = relr_;
2625 ElfW(Relr)* end = relr_ + relr_count_;
Rahul Chaudhryf16b6592018-01-25 15:34:15 -08002626 constexpr size_t wordsize = sizeof(ElfW(Addr));
Rahul Chaudhryb7feec72017-12-19 15:25:23 -08002627
Rahul Chaudhryf16b6592018-01-25 15:34:15 -08002628 ElfW(Addr) base = 0;
Rahul Chaudhryb7feec72017-12-19 15:25:23 -08002629 for (ElfW(Relr)* current = begin; current < end; ++current) {
Rahul Chaudhryf16b6592018-01-25 15:34:15 -08002630 ElfW(Relr) entry = *current;
2631 ElfW(Addr) offset;
2632
2633 if ((entry&1) == 0) {
2634 // Even entry: encodes the offset for next relocation.
2635 offset = static_cast<ElfW(Addr)>(entry);
2636 apply_relr_reloc(offset);
2637 // Set base offset for subsequent bitmap entries.
2638 base = offset + wordsize;
2639 continue;
Rahul Chaudhryb7feec72017-12-19 15:25:23 -08002640 }
Rahul Chaudhryf16b6592018-01-25 15:34:15 -08002641
2642 // Odd entry: encodes bitmap for relocations starting at base.
2643 offset = base;
2644 while (entry != 0) {
2645 entry >>= 1;
2646 if ((entry&1) != 0) {
2647 apply_relr_reloc(offset);
Rahul Chaudhryb7feec72017-12-19 15:25:23 -08002648 }
Rahul Chaudhryf16b6592018-01-25 15:34:15 -08002649 offset += wordsize;
Rahul Chaudhryb7feec72017-12-19 15:25:23 -08002650 }
Rahul Chaudhryf16b6592018-01-25 15:34:15 -08002651
2652 // Advance base offset by 63 words for 64-bit platforms,
2653 // or 31 words for 32-bit platforms.
2654 base += (8*wordsize - 1) * wordsize;
Rahul Chaudhryb7feec72017-12-19 15:25:23 -08002655 }
2656 return true;
2657}
2658
Dimitry Ivanov576a3752016-08-09 06:58:55 -07002659#if !defined(__mips__)
2660#if defined(USE_RELA)
2661static ElfW(Addr) get_addend(ElfW(Rela)* rela, ElfW(Addr) reloc_addr __unused) {
2662 return rela->r_addend;
2663}
2664#else
2665static ElfW(Addr) get_addend(ElfW(Rel)* rel, ElfW(Addr) reloc_addr) {
2666 if (ELFW(R_TYPE)(rel->r_info) == R_GENERIC_RELATIVE ||
2667 ELFW(R_TYPE)(rel->r_info) == R_GENERIC_IRELATIVE) {
2668 return *reinterpret_cast<ElfW(Addr)*>(reloc_addr);
2669 }
2670 return 0;
2671}
2672#endif
2673
Dmitriy Ivanovfa26eee2015-02-03 16:06:47 -08002674template<typename ElfRelIteratorT>
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07002675bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& rel_iterator,
2676 const soinfo_list_t& global_group, const soinfo_list_t& local_group) {
Dmitriy Ivanovfa26eee2015-02-03 16:06:47 -08002677 for (size_t idx = 0; rel_iterator.has_next(); ++idx) {
2678 const auto rel = rel_iterator.next();
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002679 if (rel == nullptr) {
2680 return false;
2681 }
2682
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002683 ElfW(Word) type = ELFW(R_TYPE)(rel->r_info);
2684 ElfW(Word) sym = ELFW(R_SYM)(rel->r_info);
2685
2686 ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rel->r_offset + load_bias);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002687 ElfW(Addr) sym_addr = 0;
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07002688 const char* sym_name = nullptr;
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002689 ElfW(Addr) addend = get_addend(rel, reloc);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002690
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07002691 DEBUG("Processing \"%s\" relocation at index %zd", get_realpath(), idx);
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002692 if (type == R_GENERIC_NONE) {
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002693 continue;
2694 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002695
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002696 const ElfW(Sym)* s = nullptr;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002697 soinfo* lsi = nullptr;
2698
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002699 if (sym != 0) {
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002700 sym_name = get_string(symtab_[sym].st_name);
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002701 const version_info* vi = nullptr;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002702
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002703 if (!lookup_version_info(version_tracker, sym, sym_name, &vi)) {
2704 return false;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002705 }
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002706
2707 if (!soinfo_do_lookup(this, sym_name, vi, &lsi, global_group, local_group, &s)) {
2708 return false;
2709 }
2710
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07002711 if (s == nullptr) {
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002712 // We only allow an undefined symbol if this is a weak reference...
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002713 s = &symtab_[sym];
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002714 if (ELF_ST_BIND(s->st_info) != STB_WEAK) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002715 DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, get_realpath());
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002716 return false;
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002717 }
2718
2719 /* IHI0044C AAELF 4.5.1.1:
2720
2721 Libraries are not searched to resolve weak references.
2722 It is not an error for a weak reference to remain unsatisfied.
2723
2724 During linking, the value of an undefined weak reference is:
2725 - Zero if the relocation type is absolute
2726 - The address of the place if the relocation is pc-relative
2727 - The address of nominal base address if the relocation
2728 type is base-relative.
2729 */
2730
2731 switch (type) {
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002732 case R_GENERIC_JUMP_SLOT:
2733 case R_GENERIC_GLOB_DAT:
2734 case R_GENERIC_RELATIVE:
2735 case R_GENERIC_IRELATIVE:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002736#if defined(__aarch64__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002737 case R_AARCH64_ABS64:
2738 case R_AARCH64_ABS32:
2739 case R_AARCH64_ABS16:
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002740#elif defined(__x86_64__)
2741 case R_X86_64_32:
2742 case R_X86_64_64:
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002743#elif defined(__arm__)
2744 case R_ARM_ABS32:
2745#elif defined(__i386__)
2746 case R_386_32:
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002747#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002748 /*
2749 * The sym_addr was initialized to be zero above, or the relocation
2750 * code below does not care about value of sym_addr.
2751 * No need to do anything.
2752 */
2753 break;
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002754#if defined(__x86_64__)
Dimitry Ivanovd338aac2015-01-13 22:31:54 +00002755 case R_X86_64_PC32:
2756 sym_addr = reloc;
2757 break;
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002758#elif defined(__i386__)
2759 case R_386_PC32:
2760 sym_addr = reloc;
2761 break;
2762#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002763 default:
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002764 DL_ERR("unknown weak reloc type %d @ %p (%zu)", type, rel, idx);
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002765 return false;
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002766 }
Dmitriy Ivanovec83a612015-07-26 07:37:09 -07002767 } else { // We got a definition.
2768#if !defined(__LP64__)
2769 // When relocating dso with text_relocation .text segment is
2770 // not executable. We need to restore elf flags before resolving
2771 // STT_GNU_IFUNC symbol.
2772 bool protect_segments = has_text_relocations &&
2773 lsi == this &&
2774 ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC;
2775 if (protect_segments) {
2776 if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
2777 DL_ERR("can't protect segments for \"%s\": %s",
2778 get_realpath(), strerror(errno));
2779 return false;
2780 }
2781 }
2782#endif
Elliott Hughes9724e932018-03-23 18:46:07 -07002783 if (ELF_ST_TYPE(s->st_info) == STT_TLS) {
2784 DL_ERR("unsupported ELF TLS symbol \"%s\" referenced by \"%s\"",
2785 sym_name, get_realpath());
2786 return false;
2787 }
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07002788 sym_addr = lsi->resolve_symbol_address(s);
Dmitriy Ivanovec83a612015-07-26 07:37:09 -07002789#if !defined(__LP64__)
2790 if (protect_segments) {
2791 if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
2792 DL_ERR("can't unprotect loadable segments for \"%s\": %s",
2793 get_realpath(), strerror(errno));
2794 return false;
2795 }
2796 }
2797#endif
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002798 }
2799 count_relocation(kRelocSymbol);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002800 }
2801
2802 switch (type) {
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002803 case R_GENERIC_JUMP_SLOT:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002804 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002805 MARK(rel->r_offset);
2806 TRACE_TYPE(RELO, "RELO JMP_SLOT %16p <- %16p %s\n",
2807 reinterpret_cast<void*>(reloc),
2808 reinterpret_cast<void*>(sym_addr + addend), sym_name);
2809
2810 *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002811 break;
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002812 case R_GENERIC_GLOB_DAT:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002813 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002814 MARK(rel->r_offset);
2815 TRACE_TYPE(RELO, "RELO GLOB_DAT %16p <- %16p %s\n",
2816 reinterpret_cast<void*>(reloc),
2817 reinterpret_cast<void*>(sym_addr + addend), sym_name);
2818 *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002819 break;
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002820 case R_GENERIC_RELATIVE:
2821 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002822 MARK(rel->r_offset);
2823 TRACE_TYPE(RELO, "RELO RELATIVE %16p <- %16p\n",
2824 reinterpret_cast<void*>(reloc),
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002825 reinterpret_cast<void*>(load_bias + addend));
2826 *reinterpret_cast<ElfW(Addr)*>(reloc) = (load_bias + addend);
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002827 break;
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002828 case R_GENERIC_IRELATIVE:
2829 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002830 MARK(rel->r_offset);
2831 TRACE_TYPE(RELO, "RELO IRELATIVE %16p <- %16p\n",
2832 reinterpret_cast<void*>(reloc),
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002833 reinterpret_cast<void*>(load_bias + addend));
Dmitriy Ivanovec83a612015-07-26 07:37:09 -07002834 {
2835#if !defined(__LP64__)
2836 // When relocating dso with text_relocation .text segment is
2837 // not executable. We need to restore elf flags for this
2838 // particular call.
2839 if (has_text_relocations) {
2840 if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
2841 DL_ERR("can't protect segments for \"%s\": %s",
2842 get_realpath(), strerror(errno));
2843 return false;
2844 }
2845 }
2846#endif
2847 ElfW(Addr) ifunc_addr = call_ifunc_resolver(load_bias + addend);
2848#if !defined(__LP64__)
2849 // Unprotect it afterwards...
2850 if (has_text_relocations) {
2851 if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
2852 DL_ERR("can't unprotect loadable segments for \"%s\": %s",
2853 get_realpath(), strerror(errno));
2854 return false;
2855 }
2856 }
2857#endif
2858 *reinterpret_cast<ElfW(Addr)*>(reloc) = ifunc_addr;
2859 }
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002860 break;
2861
2862#if defined(__aarch64__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002863 case R_AARCH64_ABS64:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002864 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002865 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002866 TRACE_TYPE(RELO, "RELO ABS64 %16llx <- %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002867 reloc, sym_addr + addend, sym_name);
2868 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend;
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002869 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002870 case R_AARCH64_ABS32:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002871 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002872 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002873 TRACE_TYPE(RELO, "RELO ABS32 %16llx <- %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002874 reloc, sym_addr + addend, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002875 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002876 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT32_MIN);
2877 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT32_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002878 if ((min_value <= (sym_addr + addend)) &&
2879 ((sym_addr + addend) <= max_value)) {
2880 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend;
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002881 } else {
2882 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002883 sym_addr + addend, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002884 return false;
2885 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002886 }
2887 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002888 case R_AARCH64_ABS16:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002889 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002890 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002891 TRACE_TYPE(RELO, "RELO ABS16 %16llx <- %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002892 reloc, sym_addr + addend, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002893 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002894 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN);
2895 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT16_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002896 if ((min_value <= (sym_addr + addend)) &&
2897 ((sym_addr + addend) <= max_value)) {
2898 *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002899 } else {
2900 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002901 sym_addr + addend, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002902 return false;
2903 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002904 }
2905 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002906 case R_AARCH64_PREL64:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002907 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002908 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002909 TRACE_TYPE(RELO, "RELO REL64 %16llx <- %16llx - %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002910 reloc, sym_addr + addend, rel->r_offset, sym_name);
2911 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset;
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002912 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002913 case R_AARCH64_PREL32:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002914 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002915 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002916 TRACE_TYPE(RELO, "RELO REL32 %16llx <- %16llx - %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002917 reloc, sym_addr + addend, rel->r_offset, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002918 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002919 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT32_MIN);
2920 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT32_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002921 if ((min_value <= (sym_addr + addend - rel->r_offset)) &&
2922 ((sym_addr + addend - rel->r_offset) <= max_value)) {
2923 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset;
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002924 } else {
2925 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002926 sym_addr + addend - rel->r_offset, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002927 return false;
2928 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002929 }
2930 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002931 case R_AARCH64_PREL16:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002932 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002933 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002934 TRACE_TYPE(RELO, "RELO REL16 %16llx <- %16llx - %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002935 reloc, sym_addr + addend, rel->r_offset, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002936 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002937 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN);
2938 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT16_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002939 if ((min_value <= (sym_addr + addend - rel->r_offset)) &&
2940 ((sym_addr + addend - rel->r_offset) <= max_value)) {
2941 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset;
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002942 } else {
2943 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002944 sym_addr + addend - rel->r_offset, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002945 return false;
2946 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002947 }
2948 break;
2949
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002950 case R_AARCH64_COPY:
Nick Kralevich76e289c2014-07-03 12:04:31 -07002951 /*
2952 * ET_EXEC is not supported so this should not happen.
2953 *
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002954 * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0056b/IHI0056B_aaelf64.pdf
Nick Kralevich76e289c2014-07-03 12:04:31 -07002955 *
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002956 * Section 4.6.11 "Dynamic relocations"
Nick Kralevich76e289c2014-07-03 12:04:31 -07002957 * R_AARCH64_COPY may only appear in executable objects where e_type is
2958 * set to ET_EXEC.
2959 */
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002960 DL_ERR("%s R_AARCH64_COPY relocations are not supported", get_realpath());
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002961 return false;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002962 case R_AARCH64_TLS_TPREL64:
Elliott Hughes0266ae52014-02-10 17:46:57 -08002963 TRACE_TYPE(RELO, "RELO TLS_TPREL64 *** %16llx <- %16llx - %16llx\n",
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002964 reloc, (sym_addr + addend), rel->r_offset);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002965 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002966 case R_AARCH64_TLS_DTPREL32:
Elliott Hughes0266ae52014-02-10 17:46:57 -08002967 TRACE_TYPE(RELO, "RELO TLS_DTPREL32 *** %16llx <- %16llx - %16llx\n",
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002968 reloc, (sym_addr + addend), rel->r_offset);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002969 break;
2970#elif defined(__x86_64__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002971 case R_X86_64_32:
2972 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002973 MARK(rel->r_offset);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002974 TRACE_TYPE(RELO, "RELO R_X86_64_32 %08zx <- +%08zx %s", static_cast<size_t>(reloc),
2975 static_cast<size_t>(sym_addr), sym_name);
Junichi Uekawaff35b1e2015-11-18 10:18:59 +09002976 *reinterpret_cast<Elf32_Addr*>(reloc) = sym_addr + addend;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002977 break;
2978 case R_X86_64_64:
2979 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002980 MARK(rel->r_offset);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002981 TRACE_TYPE(RELO, "RELO R_X86_64_64 %08zx <- +%08zx %s", static_cast<size_t>(reloc),
2982 static_cast<size_t>(sym_addr), sym_name);
Junichi Uekawaff35b1e2015-11-18 10:18:59 +09002983 *reinterpret_cast<Elf64_Addr*>(reloc) = sym_addr + addend;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002984 break;
2985 case R_X86_64_PC32:
2986 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002987 MARK(rel->r_offset);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002988 TRACE_TYPE(RELO, "RELO R_X86_64_PC32 %08zx <- +%08zx (%08zx - %08zx) %s",
2989 static_cast<size_t>(reloc), static_cast<size_t>(sym_addr - reloc),
2990 static_cast<size_t>(sym_addr), static_cast<size_t>(reloc), sym_name);
Junichi Uekawaff35b1e2015-11-18 10:18:59 +09002991 *reinterpret_cast<Elf32_Addr*>(reloc) = sym_addr + addend - reloc;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002992 break;
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002993#elif defined(__arm__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002994 case R_ARM_ABS32:
2995 count_relocation(kRelocAbsolute);
2996 MARK(rel->r_offset);
2997 TRACE_TYPE(RELO, "RELO ABS %08x <- %08x %s", reloc, sym_addr, sym_name);
2998 *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
2999 break;
3000 case R_ARM_REL32:
3001 count_relocation(kRelocRelative);
3002 MARK(rel->r_offset);
3003 TRACE_TYPE(RELO, "RELO REL32 %08x <- %08x - %08x %s",
3004 reloc, sym_addr, rel->r_offset, sym_name);
3005 *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr - rel->r_offset;
3006 break;
3007 case R_ARM_COPY:
3008 /*
3009 * ET_EXEC is not supported so this should not happen.
3010 *
3011 * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044d/IHI0044D_aaelf.pdf
3012 *
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003013 * Section 4.6.1.10 "Dynamic relocations"
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003014 * R_ARM_COPY may only appear in executable objects where e_type is
3015 * set to ET_EXEC.
3016 */
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003017 DL_ERR("%s R_ARM_COPY relocations are not supported", get_realpath());
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08003018 return false;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003019#elif defined(__i386__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003020 case R_386_32:
3021 count_relocation(kRelocRelative);
3022 MARK(rel->r_offset);
3023 TRACE_TYPE(RELO, "RELO R_386_32 %08x <- +%08x %s", reloc, sym_addr, sym_name);
3024 *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
3025 break;
3026 case R_386_PC32:
3027 count_relocation(kRelocRelative);
3028 MARK(rel->r_offset);
3029 TRACE_TYPE(RELO, "RELO R_386_PC32 %08x <- +%08x (%08x - %08x) %s",
3030 reloc, (sym_addr - reloc), sym_addr, reloc, sym_name);
3031 *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr - reloc);
3032 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003033#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003034 default:
3035 DL_ERR("unknown reloc type %d @ %p (%zu)", type, rel, idx);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003036 return false;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003037 }
3038 }
3039 return true;
Raghu Gandhamd7daacb2012-07-31 12:07:22 -07003040}
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08003041#endif // !defined(__mips__)
Raghu Gandhamd7daacb2012-07-31 12:07:22 -07003042
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07003043// An empty list of soinfos
Dimitry Ivanovb943f302016-08-03 16:00:10 -07003044static soinfo_list_t g_empty_list;
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07003045
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003046bool soinfo::prelink_image() {
Ningsheng Jiane93be992014-09-16 15:22:10 +08003047 /* Extract dynamic section */
3048 ElfW(Word) dynamic_flags = 0;
3049 phdr_table_get_dynamic_section(phdr, phnum, load_bias, &dynamic, &dynamic_flags);
Dmitriy Ivanov498eb182014-09-05 14:57:59 -07003050
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003051 /* We can't log anything until the linker is relocated */
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08003052 bool relocating_linker = (flags_ & FLAG_LINKER) != 0;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003053 if (!relocating_linker) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07003054 INFO("[ Linking \"%s\" ]", get_realpath());
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08003055 DEBUG("si->base = %p si->flags = 0x%08x", reinterpret_cast<void*>(base), flags_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003056 }
3057
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003058 if (dynamic == nullptr) {
David 'Digit' Turnerb52e4382012-06-19 01:24:17 +02003059 if (!relocating_linker) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003060 DL_ERR("missing PT_DYNAMIC in \"%s\"", get_realpath());
David 'Digit' Turnerb52e4382012-06-19 01:24:17 +02003061 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003062 return false;
3063 } else {
3064 if (!relocating_linker) {
3065 DEBUG("dynamic = %p", dynamic);
David 'Digit' Turner63f99f42012-06-19 00:08:39 +02003066 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003067 }
David 'Digit' Turner63f99f42012-06-19 00:08:39 +02003068
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07003069#if defined(__arm__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003070 (void) phdr_table_get_arm_exidx(phdr, phnum, load_bias,
3071 &ARM_exidx, &ARM_exidx_count);
David 'Digit' Turner63f99f42012-06-19 00:08:39 +02003072#endif
3073
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003074 // Extract useful information from dynamic section.
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07003075 // Note that: "Except for the DT_NULL element at the end of the array,
3076 // and the relative order of DT_NEEDED elements, entries may appear in any order."
3077 //
3078 // source: http://www.sco.com/developers/gabi/1998-04-29/ch5.dynamic.html
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003079 uint32_t needed_count = 0;
3080 for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
3081 DEBUG("d = %p, d[0](tag) = %p d[1](val) = %p",
3082 d, reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
3083 switch (d->d_tag) {
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003084 case DT_SONAME:
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07003085 // this is parsed after we have strtab initialized (see below).
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003086 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003087
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003088 case DT_HASH:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003089 nbucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0];
3090 nchain_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
3091 bucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8);
3092 chain_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8 + nbucket_ * 4);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003093 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003094
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08003095 case DT_GNU_HASH:
Dmitriy Ivanov3597b802015-03-09 12:02:02 -07003096 gnu_nbucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0];
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08003097 // skip symndx
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003098 gnu_maskwords_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[2];
3099 gnu_shift2_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[3];
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08003100
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003101 gnu_bloom_filter_ = reinterpret_cast<ElfW(Addr)*>(load_bias + d->d_un.d_ptr + 16);
Dmitriy Ivanov3597b802015-03-09 12:02:02 -07003102 gnu_bucket_ = reinterpret_cast<uint32_t*>(gnu_bloom_filter_ + gnu_maskwords_);
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08003103 // amend chain for symndx = header[1]
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07003104 gnu_chain_ = gnu_bucket_ + gnu_nbucket_ -
3105 reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08003106
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003107 if (!powerof2(gnu_maskwords_)) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07003108 DL_ERR("invalid maskwords for gnu_hash = 0x%x, in \"%s\" expecting power to two",
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003109 gnu_maskwords_, get_realpath());
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08003110 return false;
3111 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003112 --gnu_maskwords_;
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08003113
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08003114 flags_ |= FLAG_GNU_HASH;
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08003115 break;
3116
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003117 case DT_STRTAB:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003118 strtab_ = reinterpret_cast<const char*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003119 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003120
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07003121 case DT_STRSZ:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003122 strtab_size_ = d->d_un.d_val;
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07003123 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003124
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003125 case DT_SYMTAB:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003126 symtab_ = reinterpret_cast<ElfW(Sym)*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003127 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003128
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003129 case DT_SYMENT:
3130 if (d->d_un.d_val != sizeof(ElfW(Sym))) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003131 DL_ERR("invalid DT_SYMENT: %zd in \"%s\"",
3132 static_cast<size_t>(d->d_un.d_val), get_realpath());
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003133 return false;
3134 }
3135 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003136
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003137 case DT_PLTREL:
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003138#if defined(USE_RELA)
3139 if (d->d_un.d_val != DT_RELA) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003140 DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_RELA", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003141 return false;
3142 }
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003143#else
3144 if (d->d_un.d_val != DT_REL) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003145 DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_REL", get_realpath());
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003146 return false;
3147 }
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07003148#endif
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003149 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003150
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003151 case DT_JMPREL:
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07003152#if defined(USE_RELA)
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003153 plt_rela_ = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07003154#else
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003155 plt_rel_ = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07003156#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003157 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003158
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003159 case DT_PLTRELSZ:
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07003160#if defined(USE_RELA)
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003161 plt_rela_count_ = d->d_un.d_val / sizeof(ElfW(Rela));
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07003162#else
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003163 plt_rel_count_ = d->d_un.d_val / sizeof(ElfW(Rel));
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07003164#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003165 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003166
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003167 case DT_PLTGOT:
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003168#if defined(__mips__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003169 // Used by mips and mips64.
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003170 plt_got_ = reinterpret_cast<ElfW(Addr)**>(load_bias + d->d_un.d_ptr);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07003171#endif
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003172 // Ignore for other platforms... (because RTLD_LAZY is not supported)
3173 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003174
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003175 case DT_DEBUG:
3176 // Set the DT_DEBUG entry to the address of _r_debug for GDB
3177 // if the dynamic table is writable
Chris Dearman99186652014-02-06 20:36:51 -08003178// FIXME: not working currently for N64
3179// The flags for the LOAD and DYNAMIC program headers do not agree.
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07003180// The LOAD section containing the dynamic table has been mapped as
Chris Dearman99186652014-02-06 20:36:51 -08003181// read-only, but the DYNAMIC header claims it is writable.
3182#if !(defined(__mips__) && defined(__LP64__))
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003183 if ((dynamic_flags & PF_W) != 0) {
3184 d->d_un.d_val = reinterpret_cast<uintptr_t>(&_r_debug);
3185 }
Chris Dearman99186652014-02-06 20:36:51 -08003186#endif
Dmitriy Ivanovc6292ea2015-02-13 16:29:50 -08003187 break;
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07003188#if defined(USE_RELA)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003189 case DT_RELA:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003190 rela_ = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003191 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003192
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003193 case DT_RELASZ:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003194 rela_count_ = d->d_un.d_val / sizeof(ElfW(Rela));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003195 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003196
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003197 case DT_ANDROID_RELA:
3198 android_relocs_ = reinterpret_cast<uint8_t*>(load_bias + d->d_un.d_ptr);
3199 break;
3200
3201 case DT_ANDROID_RELASZ:
3202 android_relocs_size_ = d->d_un.d_val;
3203 break;
3204
3205 case DT_ANDROID_REL:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003206 DL_ERR("unsupported DT_ANDROID_REL in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003207 return false;
3208
3209 case DT_ANDROID_RELSZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003210 DL_ERR("unsupported DT_ANDROID_RELSZ in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003211 return false;
3212
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003213 case DT_RELAENT:
3214 if (d->d_un.d_val != sizeof(ElfW(Rela))) {
Dmitriy Ivanovf240aa82014-09-16 23:34:20 -07003215 DL_ERR("invalid DT_RELAENT: %zd", static_cast<size_t>(d->d_un.d_val));
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003216 return false;
3217 }
3218 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003219
Rahul Chaudhryb7feec72017-12-19 15:25:23 -08003220 // Ignored (see DT_RELCOUNT comments for details).
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003221 case DT_RELACOUNT:
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003222 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003223
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003224 case DT_REL:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003225 DL_ERR("unsupported DT_REL in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003226 return false;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003227
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003228 case DT_RELSZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003229 DL_ERR("unsupported DT_RELSZ in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003230 return false;
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003231
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07003232#else
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003233 case DT_REL:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003234 rel_ = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003235 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003236
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003237 case DT_RELSZ:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003238 rel_count_ = d->d_un.d_val / sizeof(ElfW(Rel));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003239 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003240
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003241 case DT_RELENT:
3242 if (d->d_un.d_val != sizeof(ElfW(Rel))) {
Dmitriy Ivanovf240aa82014-09-16 23:34:20 -07003243 DL_ERR("invalid DT_RELENT: %zd", static_cast<size_t>(d->d_un.d_val));
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003244 return false;
3245 }
3246 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003247
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003248 case DT_ANDROID_REL:
3249 android_relocs_ = reinterpret_cast<uint8_t*>(load_bias + d->d_un.d_ptr);
3250 break;
3251
3252 case DT_ANDROID_RELSZ:
3253 android_relocs_size_ = d->d_un.d_val;
3254 break;
3255
3256 case DT_ANDROID_RELA:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003257 DL_ERR("unsupported DT_ANDROID_RELA in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003258 return false;
3259
3260 case DT_ANDROID_RELASZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003261 DL_ERR("unsupported DT_ANDROID_RELASZ in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003262 return false;
3263
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003264 // "Indicates that all RELATIVE relocations have been concatenated together,
3265 // and specifies the RELATIVE relocation count."
3266 //
3267 // TODO: Spec also mentions that this can be used to optimize relocation process;
3268 // Not currently used by bionic linker - ignored.
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003269 case DT_RELCOUNT:
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003270 break;
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003271
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003272 case DT_RELA:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003273 DL_ERR("unsupported DT_RELA in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003274 return false;
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003275
3276 case DT_RELASZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003277 DL_ERR("unsupported DT_RELASZ in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003278 return false;
3279
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07003280#endif
Rahul Chaudhryb7feec72017-12-19 15:25:23 -08003281 case DT_RELR:
3282 relr_ = reinterpret_cast<ElfW(Relr)*>(load_bias + d->d_un.d_ptr);
3283 break;
3284
3285 case DT_RELRSZ:
3286 relr_count_ = d->d_un.d_val / sizeof(ElfW(Relr));
3287 break;
3288
3289 case DT_RELRENT:
3290 if (d->d_un.d_val != sizeof(ElfW(Relr))) {
3291 DL_ERR("invalid DT_RELRENT: %zd", static_cast<size_t>(d->d_un.d_val));
3292 return false;
3293 }
3294 break;
3295
3296 // Ignored (see DT_RELCOUNT comments for details).
3297 case DT_RELRCOUNT:
3298 break;
3299
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003300 case DT_INIT:
Dimitry Ivanov55437462016-07-20 15:33:07 -07003301 init_func_ = reinterpret_cast<linker_ctor_function_t>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003302 DEBUG("%s constructors (DT_INIT) found at %p", get_realpath(), init_func_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003303 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003304
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003305 case DT_FINI:
Dimitry Ivanov55437462016-07-20 15:33:07 -07003306 fini_func_ = reinterpret_cast<linker_dtor_function_t>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003307 DEBUG("%s destructors (DT_FINI) found at %p", get_realpath(), fini_func_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003308 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003309
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003310 case DT_INIT_ARRAY:
Dimitry Ivanov55437462016-07-20 15:33:07 -07003311 init_array_ = reinterpret_cast<linker_ctor_function_t*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003312 DEBUG("%s constructors (DT_INIT_ARRAY) found at %p", get_realpath(), init_array_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003313 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003314
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003315 case DT_INIT_ARRAYSZ:
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -08003316 init_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003317 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003318
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003319 case DT_FINI_ARRAY:
Dimitry Ivanov55437462016-07-20 15:33:07 -07003320 fini_array_ = reinterpret_cast<linker_dtor_function_t*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003321 DEBUG("%s destructors (DT_FINI_ARRAY) found at %p", get_realpath(), fini_array_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003322 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003323
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003324 case DT_FINI_ARRAYSZ:
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -08003325 fini_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003326 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003327
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003328 case DT_PREINIT_ARRAY:
Dimitry Ivanov55437462016-07-20 15:33:07 -07003329 preinit_array_ = reinterpret_cast<linker_ctor_function_t*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003330 DEBUG("%s constructors (DT_PREINIT_ARRAY) found at %p", get_realpath(), preinit_array_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003331 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003332
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003333 case DT_PREINIT_ARRAYSZ:
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -08003334 preinit_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003335 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003336
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003337 case DT_TEXTREL:
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003338#if defined(__LP64__)
Dimitry Ivanov816676e2016-10-19 11:00:28 -07003339 DL_ERR("\"%s\" has text relocations", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003340 return false;
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003341#else
3342 has_text_relocations = true;
3343 break;
3344#endif
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003345
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003346 case DT_SYMBOLIC:
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -07003347 has_DT_SYMBOLIC = true;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003348 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003349
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003350 case DT_NEEDED:
3351 ++needed_count;
3352 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003353
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003354 case DT_FLAGS:
3355 if (d->d_un.d_val & DF_TEXTREL) {
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003356#if defined(__LP64__)
Dimitry Ivanov816676e2016-10-19 11:00:28 -07003357 DL_ERR("\"%s\" has text relocations", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003358 return false;
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003359#else
3360 has_text_relocations = true;
3361#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003362 }
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -07003363 if (d->d_un.d_val & DF_SYMBOLIC) {
3364 has_DT_SYMBOLIC = true;
3365 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003366 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003367
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07003368 case DT_FLAGS_1:
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07003369 set_dt_flags_1(d->d_un.d_val);
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -07003370
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07003371 if ((d->d_un.d_val & ~SUPPORTED_DT_FLAGS_1) != 0) {
Elliott Hughes9076b0c2018-02-28 11:29:45 -08003372 DL_WARN("Warning: \"%s\" has unsupported flags DT_FLAGS_1=%p "
3373 "(ignoring unsupported flags)",
3374 get_realpath(), reinterpret_cast<void*>(d->d_un.d_val));
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07003375 }
3376 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003377#if defined(__mips__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003378 case DT_MIPS_RLD_MAP:
3379 // Set the DT_MIPS_RLD_MAP entry to the address of _r_debug for GDB.
3380 {
3381 r_debug** dp = reinterpret_cast<r_debug**>(load_bias + d->d_un.d_ptr);
3382 *dp = &_r_debug;
3383 }
3384 break;
Lazar Trsic83b44a92016-04-06 13:39:17 +02003385 case DT_MIPS_RLD_MAP_REL:
3386 // Set the DT_MIPS_RLD_MAP_REL entry to the address of _r_debug for GDB.
Raghu Gandham68815722014-12-18 19:12:19 -08003387 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07003388 r_debug** dp = reinterpret_cast<r_debug**>(
3389 reinterpret_cast<ElfW(Addr)>(d) + d->d_un.d_val);
Raghu Gandham68815722014-12-18 19:12:19 -08003390 *dp = &_r_debug;
3391 }
3392 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003393
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003394 case DT_MIPS_RLD_VERSION:
3395 case DT_MIPS_FLAGS:
3396 case DT_MIPS_BASE_ADDRESS:
3397 case DT_MIPS_UNREFEXTNO:
3398 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003399
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003400 case DT_MIPS_SYMTABNO:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003401 mips_symtabno_ = d->d_un.d_val;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003402 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003403
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003404 case DT_MIPS_LOCAL_GOTNO:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003405 mips_local_gotno_ = d->d_un.d_val;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003406 break;
3407
3408 case DT_MIPS_GOTSYM:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003409 mips_gotsym_ = d->d_un.d_val;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003410 break;
3411#endif
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003412 // Ignored: "Its use has been superseded by the DF_BIND_NOW flag"
3413 case DT_BIND_NOW:
3414 break;
3415
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003416 case DT_VERSYM:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003417 versym_ = reinterpret_cast<ElfW(Versym)*>(load_bias + d->d_un.d_ptr);
3418 break;
3419
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003420 case DT_VERDEF:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003421 verdef_ptr_ = load_bias + d->d_un.d_ptr;
3422 break;
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003423 case DT_VERDEFNUM:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003424 verdef_cnt_ = d->d_un.d_val;
3425 break;
3426
Alexander Ivchenkoe8314332014-12-02 15:32:25 +03003427 case DT_VERNEED:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003428 verneed_ptr_ = load_bias + d->d_un.d_ptr;
3429 break;
3430
Alexander Ivchenkoe8314332014-12-02 15:32:25 +03003431 case DT_VERNEEDNUM:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003432 verneed_cnt_ = d->d_un.d_val;
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003433 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003434
Evgenii Stepanov68650822015-06-10 13:38:39 -07003435 case DT_RUNPATH:
3436 // this is parsed after we have strtab initialized (see below).
3437 break;
3438
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003439 default:
Dmitriy Ivanov8f61d992014-09-16 14:31:06 -07003440 if (!relocating_linker) {
Elliott Hughes9724e932018-03-23 18:46:07 -07003441 if (d->d_tag == DT_TLSDESC_GOT || d->d_tag == DT_TLSDESC_PLT) {
3442 DL_ERR("unsupported ELF TLS DT entry in \"%s\"", get_realpath());
3443 return false;
3444 }
3445
Elliott Hughes6eae4cc2017-08-30 09:02:33 -07003446 const char* tag_name;
3447 if (d->d_tag == DT_RPATH) {
3448 tag_name = "DT_RPATH";
3449 } else if (d->d_tag == DT_ENCODING) {
3450 tag_name = "DT_ENCODING";
3451 } else if (d->d_tag >= DT_LOOS && d->d_tag <= DT_HIOS) {
3452 tag_name = "unknown OS-specific";
3453 } else if (d->d_tag >= DT_LOPROC && d->d_tag <= DT_HIPROC) {
3454 tag_name = "unknown processor-specific";
3455 } else {
3456 tag_name = "unknown";
3457 }
Elliott Hughes9076b0c2018-02-28 11:29:45 -08003458 DL_WARN("Warning: \"%s\" unused DT entry: %s (type %p arg %p) (ignoring)",
Elliott Hughes6eae4cc2017-08-30 09:02:33 -07003459 get_realpath(),
3460 tag_name,
3461 reinterpret_cast<void*>(d->d_tag),
3462 reinterpret_cast<void*>(d->d_un.d_val));
Dmitriy Ivanov8f61d992014-09-16 14:31:06 -07003463 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003464 break;
Brian Carlstromd4ee82d2013-02-28 15:58:45 -08003465 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003466 }
3467
Duane Sandbc425c72015-06-01 16:29:14 -07003468#if defined(__mips__) && !defined(__LP64__)
3469 if (!mips_check_and_adjust_fp_modes()) {
3470 return false;
3471 }
3472#endif
3473
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003474 DEBUG("si->base = %p, si->strtab = %p, si->symtab = %p",
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003475 reinterpret_cast<void*>(base), strtab_, symtab_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003476
3477 // Sanity checks.
3478 if (relocating_linker && needed_count != 0) {
3479 DL_ERR("linker cannot have DT_NEEDED dependencies on other libraries");
3480 return false;
3481 }
Dmitriy Ivanov3597b802015-03-09 12:02:02 -07003482 if (nbucket_ == 0 && gnu_nbucket_ == 0) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003483 DL_ERR("empty/missing DT_HASH/DT_GNU_HASH in \"%s\" "
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003484 "(new hash type from the future?)", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003485 return false;
3486 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003487 if (strtab_ == 0) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003488 DL_ERR("empty/missing DT_STRTAB in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003489 return false;
3490 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003491 if (symtab_ == 0) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003492 DL_ERR("empty/missing DT_SYMTAB in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003493 return false;
3494 }
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003495
Dmitriy Ivanov624b8f12015-06-08 10:41:33 -07003496 // second pass - parse entries relying on strtab
3497 for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
Evgenii Stepanov68650822015-06-10 13:38:39 -07003498 switch (d->d_tag) {
3499 case DT_SONAME:
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07003500 set_soname(get_string(d->d_un.d_val));
Evgenii Stepanov68650822015-06-10 13:38:39 -07003501 break;
3502 case DT_RUNPATH:
Evgenii Stepanov68650822015-06-10 13:38:39 -07003503 set_dt_runpath(get_string(d->d_un.d_val));
3504 break;
Dmitriy Ivanov624b8f12015-06-08 10:41:33 -07003505 }
3506 }
3507
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003508 // Before M release linker was using basename in place of soname.
Dmitriy Ivanov19133522015-06-02 17:36:54 -07003509 // In the case when dt_soname is absent some apps stop working
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003510 // because they can't find dt_needed library by soname.
Elliott Hughes9076b0c2018-02-28 11:29:45 -08003511 // This workaround should keep them working. (Applies only
3512 // for apps targeting sdk version < M.) Make an exception for
3513 // the main executable and linker; they do not need to have dt_soname.
3514 // TODO: >= O the linker doesn't need this workaround.
Dimitry Ivanov3f660572016-09-09 10:00:39 -07003515 if (soname_ == nullptr &&
3516 this != solist_get_somain() &&
3517 (flags_ & FLAG_LINKER) == 0 &&
Elliott Hughes5bc78c82016-11-16 11:35:43 -08003518 get_application_target_sdk_version() < __ANDROID_API_M__) {
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003519 soname_ = basename(realpath_.c_str());
Elliott Hughes9076b0c2018-02-28 11:29:45 -08003520 DL_WARN_documented_change(__ANDROID_API_M__,
3521 "missing-soname-enforced-for-api-level-23",
3522 "\"%s\" has no DT_SONAME (will use %s instead)",
3523 get_realpath(), soname_);
3524
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07003525 // 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 -07003526 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003527 return true;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07003528}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003529
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003530bool soinfo::link_image(const soinfo_list_t& global_group, const soinfo_list_t& local_group,
3531 const android_dlextinfo* extinfo) {
dimitry965d06d2017-11-28 16:03:07 +01003532 if (is_image_linked()) {
3533 // already linked.
3534 return true;
3535 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003536
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08003537 local_group_root_ = local_group.front();
3538 if (local_group_root_ == nullptr) {
3539 local_group_root_ = this;
3540 }
3541
Dmitriy Ivanov19133522015-06-02 17:36:54 -07003542 if ((flags_ & FLAG_LINKER) == 0 && local_group_root_ == this) {
3543 target_sdk_version_ = get_application_target_sdk_version();
3544 }
3545
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003546 VersionTracker version_tracker;
3547
3548 if (!version_tracker.init(this)) {
3549 return false;
3550 }
3551
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003552#if !defined(__LP64__)
3553 if (has_text_relocations) {
Elliott Hughes5bc78c82016-11-16 11:35:43 -08003554 // Fail if app is targeting M or above.
Elliott Hughes9076b0c2018-02-28 11:29:45 -08003555 int app_target_api_level = get_application_target_sdk_version();
3556 if (app_target_api_level >= __ANDROID_API_M__) {
Elliott Hughes763f6e12017-04-10 09:52:33 -07003557 DL_ERR_AND_LOG("\"%s\" has text relocations (https://android.googlesource.com/platform/"
3558 "bionic/+/master/android-changes-for-ndk-developers.md#Text-Relocations-"
3559 "Enforced-for-API-level-23)", get_realpath());
Dmitriy Ivanove4ad91f2015-06-12 15:00:31 -07003560 return false;
3561 }
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003562 // Make segments writable to allow text relocations to work properly. We will later call
Dmitriy Ivanov7e039932015-10-01 14:02:19 -07003563 // phdr_table_protect_segments() after all of them are applied.
Elliott Hughes9076b0c2018-02-28 11:29:45 -08003564 DL_WARN_documented_change(__ANDROID_API_M__,
3565 "Text-Relocations-Enforced-for-API-level-23",
3566 "\"%s\" has text relocations",
3567 get_realpath());
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07003568 add_dlwarning(get_realpath(), "text relocations");
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003569 if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
Elliott Hughes9076b0c2018-02-28 11:29:45 -08003570 DL_ERR("can't unprotect loadable segments for \"%s\": %s", get_realpath(), strerror(errno));
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003571 return false;
3572 }
3573 }
3574#endif
3575
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003576 if (android_relocs_ != nullptr) {
3577 // check signature
3578 if (android_relocs_size_ > 3 &&
3579 android_relocs_[0] == 'A' &&
3580 android_relocs_[1] == 'P' &&
Dmitriy Ivanov18870d32015-04-22 13:10:04 -07003581 android_relocs_[2] == 'S' &&
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003582 android_relocs_[3] == '2') {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003583 DEBUG("[ android relocating %s ]", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003584
3585 bool relocated = false;
3586 const uint8_t* packed_relocs = android_relocs_ + 4;
3587 const size_t packed_relocs_size = android_relocs_size_ - 4;
3588
Dmitriy Ivanov18870d32015-04-22 13:10:04 -07003589 relocated = relocate(
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003590 version_tracker,
Dmitriy Ivanov18870d32015-04-22 13:10:04 -07003591 packed_reloc_iterator<sleb128_decoder>(
3592 sleb128_decoder(packed_relocs, packed_relocs_size)),
3593 global_group, local_group);
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003594
3595 if (!relocated) {
3596 return false;
3597 }
3598 } else {
3599 DL_ERR("bad android relocation header.");
3600 return false;
3601 }
3602 }
3603
Rahul Chaudhryb7feec72017-12-19 15:25:23 -08003604 if (relr_ != nullptr) {
3605 DEBUG("[ relocating %s relr ]", get_realpath());
3606 if (!relocate_relr()) {
3607 return false;
3608 }
3609 }
3610
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07003611#if defined(USE_RELA)
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003612 if (rela_ != nullptr) {
Rahul Chaudhryb7feec72017-12-19 15:25:23 -08003613 DEBUG("[ relocating %s rela ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003614 if (!relocate(version_tracker,
3615 plain_reloc_iterator(rela_, rela_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003616 return false;
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07003617 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003618 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003619 if (plt_rela_ != nullptr) {
Rahul Chaudhryb7feec72017-12-19 15:25:23 -08003620 DEBUG("[ relocating %s plt rela ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003621 if (!relocate(version_tracker,
3622 plain_reloc_iterator(plt_rela_, plt_rela_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003623 return false;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003624 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003625 }
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07003626#else
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003627 if (rel_ != nullptr) {
Rahul Chaudhryb7feec72017-12-19 15:25:23 -08003628 DEBUG("[ relocating %s rel ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003629 if (!relocate(version_tracker,
3630 plain_reloc_iterator(rel_, rel_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003631 return false;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003632 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003633 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003634 if (plt_rel_ != nullptr) {
Rahul Chaudhryb7feec72017-12-19 15:25:23 -08003635 DEBUG("[ relocating %s plt rel ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003636 if (!relocate(version_tracker,
3637 plain_reloc_iterator(plt_rel_, plt_rel_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003638 return false;
Brigid Smithc5a13ef2014-07-23 11:22:25 -07003639 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003640 }
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07003641#endif
Brigid Smithc5a13ef2014-07-23 11:22:25 -07003642
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07003643#if defined(__mips__)
Dmitriy Ivanovf39cb632015-04-30 20:17:03 -07003644 if (!mips_relocate_got(version_tracker, global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003645 return false;
3646 }
Raghu Gandhamd7daacb2012-07-31 12:07:22 -07003647#endif
3648
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003649 DEBUG("[ finished linking %s ]", get_realpath());
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003650
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003651#if !defined(__LP64__)
3652 if (has_text_relocations) {
3653 // All relocations are done, we can protect our segments back to read-only.
3654 if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
3655 DL_ERR("can't protect segments for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003656 get_realpath(), strerror(errno));
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003657 return false;
3658 }
3659 }
3660#endif
3661
Mingwei Shibe910522015-11-12 07:02:14 +00003662 // We can also turn on GNU RELRO protection if we're not linking the dynamic linker
3663 // itself --- it can't make system calls yet, and will have to call protect_relro later.
3664 if (!is_linker() && !protect_relro()) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003665 return false;
3666 }
Nick Kralevich9ec0f032012-02-28 10:40:00 -08003667
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003668 /* Handle serializing/sharing the RELRO segment */
3669 if (extinfo && (extinfo->flags & ANDROID_DLEXT_WRITE_RELRO)) {
3670 if (phdr_table_serialize_gnu_relro(phdr, phnum, load_bias,
3671 extinfo->relro_fd) < 0) {
3672 DL_ERR("failed serializing GNU RELRO section for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003673 get_realpath(), strerror(errno));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003674 return false;
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +00003675 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003676 } else if (extinfo && (extinfo->flags & ANDROID_DLEXT_USE_RELRO)) {
3677 if (phdr_table_map_gnu_relro(phdr, phnum, load_bias,
3678 extinfo->relro_fd) < 0) {
3679 DL_ERR("failed mapping GNU RELRO section for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003680 get_realpath(), strerror(errno));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003681 return false;
3682 }
3683 }
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +00003684
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003685 notify_gdb_of_load(this);
dimitry965d06d2017-11-28 16:03:07 +01003686 set_image_linked();
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003687 return true;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003688}
3689
Mingwei Shibe910522015-11-12 07:02:14 +00003690bool soinfo::protect_relro() {
3691 if (phdr_table_protect_gnu_relro(phdr, phnum, load_bias) < 0) {
3692 DL_ERR("can't enable GNU RELRO protection for \"%s\": %s",
3693 get_realpath(), strerror(errno));
3694 return false;
3695 }
3696 return true;
3697}
3698
Jiyong Park02586a22017-05-20 01:01:24 +09003699static std::vector<android_namespace_t*> init_default_namespace_no_config(bool is_asan) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003700 g_default_namespace.set_isolated(false);
Dimitry Ivanov77ad6422017-03-06 13:02:29 -08003701 auto default_ld_paths = is_asan ? kAsanDefaultLdPaths : kDefaultLdPaths;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003702
neo.chae2589f9d2016-10-04 11:00:27 +09003703 char real_path[PATH_MAX];
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003704 std::vector<std::string> ld_default_paths;
Dimitry Ivanov77ad6422017-03-06 13:02:29 -08003705 for (size_t i = 0; default_ld_paths[i] != nullptr; ++i) {
3706 if (realpath(default_ld_paths[i], real_path) != nullptr) {
neo.chae2589f9d2016-10-04 11:00:27 +09003707 ld_default_paths.push_back(real_path);
3708 } else {
Dimitry Ivanov77ad6422017-03-06 13:02:29 -08003709 ld_default_paths.push_back(default_ld_paths[i]);
neo.chae2589f9d2016-10-04 11:00:27 +09003710 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003711 }
3712
3713 g_default_namespace.set_default_library_paths(std::move(ld_default_paths));
Jiyong Park02586a22017-05-20 01:01:24 +09003714
3715 std::vector<android_namespace_t*> namespaces;
3716 namespaces.push_back(&g_default_namespace);
3717 return namespaces;
Dimitry Ivanov4cabfaa2017-03-07 11:19:05 -08003718}
3719
Jiyong Park02586a22017-05-20 01:01:24 +09003720std::vector<android_namespace_t*> init_default_namespaces(const char* executable_path) {
Dimitry Ivanov4cabfaa2017-03-07 11:19:05 -08003721 g_default_namespace.set_name("(default)");
3722
3723 soinfo* somain = solist_get_somain();
3724
3725 const char *interp = phdr_table_get_interpreter_name(somain->phdr, somain->phnum,
3726 somain->load_bias);
Dan Willemsen7ccc50d2017-09-18 21:28:14 -07003727 const char* bname = (interp != nullptr) ? basename(interp) : nullptr;
Dimitry Ivanov4cabfaa2017-03-07 11:19:05 -08003728
3729 g_is_asan = bname != nullptr &&
3730 (strcmp(bname, "linker_asan") == 0 ||
3731 strcmp(bname, "linker_asan64") == 0);
3732
3733 const Config* config = nullptr;
3734
3735 std::string error_msg;
3736
Justin Yun53ce7422017-11-27 16:28:07 +09003737 std::string ld_config_vndk = kLdConfigFilePath;
Elliott Hughes5cec3772018-01-19 15:45:23 -08003738 size_t insert_pos = ld_config_vndk.find_last_of('.');
Justin Yun53ce7422017-11-27 16:28:07 +09003739 if (insert_pos == std::string::npos) {
3740 insert_pos = ld_config_vndk.length();
3741 }
3742 ld_config_vndk.insert(insert_pos, Config::get_vndk_version_string('.'));
3743 const char* ld_config_txt = file_exists(ld_config_vndk.c_str()) ? ld_config_vndk.c_str() : kLdConfigFilePath;
3744 const char* config_file = file_exists(kLdConfigArchFilePath) ? kLdConfigArchFilePath : ld_config_txt;
Jiyong Park02586a22017-05-20 01:01:24 +09003745#ifdef USE_LD_CONFIG_FILE
3746 // This is a debugging/testing only feature. Must not be available on
3747 // production builds.
3748 const char* ld_config_file = getenv("LD_CONFIG_FILE");
3749 if (ld_config_file != nullptr && file_exists(ld_config_file)) {
3750 config_file = ld_config_file;
3751 }
3752#endif
3753
3754 if (!Config::read_binary_config(config_file,
Dimitry Ivanov4cabfaa2017-03-07 11:19:05 -08003755 executable_path,
3756 g_is_asan,
3757 &config,
3758 &error_msg)) {
3759 if (!error_msg.empty()) {
Elliott Hughes9076b0c2018-02-28 11:29:45 -08003760 DL_WARN("Warning: couldn't read \"%s\" for \"%s\" (using default configuration instead): %s",
Jiyong Park02586a22017-05-20 01:01:24 +09003761 config_file,
Dimitry Ivanov4cabfaa2017-03-07 11:19:05 -08003762 executable_path,
3763 error_msg.c_str());
3764 }
3765 config = nullptr;
3766 }
3767
3768 if (config == nullptr) {
Jiyong Park02586a22017-05-20 01:01:24 +09003769 return init_default_namespace_no_config(g_is_asan);
Dimitry Ivanov4cabfaa2017-03-07 11:19:05 -08003770 }
3771
3772 const auto& namespace_configs = config->namespace_configs();
3773 std::unordered_map<std::string, android_namespace_t*> namespaces;
3774
3775 // 1. Initialize default namespace
3776 const NamespaceConfig* default_ns_config = config->default_namespace_config();
3777
3778 g_default_namespace.set_isolated(default_ns_config->isolated());
3779 g_default_namespace.set_default_library_paths(default_ns_config->search_paths());
3780 g_default_namespace.set_permitted_paths(default_ns_config->permitted_paths());
3781
3782 namespaces[default_ns_config->name()] = &g_default_namespace;
Justin Yun90de9f02017-07-07 16:21:53 +09003783 if (default_ns_config->visible()) {
3784 g_exported_namespaces[default_ns_config->name()] = &g_default_namespace;
3785 }
Dimitry Ivanov4cabfaa2017-03-07 11:19:05 -08003786
3787 // 2. Initialize other namespaces
3788
3789 for (auto& ns_config : namespace_configs) {
3790 if (namespaces.find(ns_config->name()) != namespaces.end()) {
3791 continue;
3792 }
3793
3794 android_namespace_t* ns = new (g_namespace_allocator.alloc()) android_namespace_t();
3795 ns->set_name(ns_config->name());
3796 ns->set_isolated(ns_config->isolated());
3797 ns->set_default_library_paths(ns_config->search_paths());
3798 ns->set_permitted_paths(ns_config->permitted_paths());
3799
3800 namespaces[ns_config->name()] = ns;
Jiyong Park01de74e2017-04-03 23:10:37 +09003801 if (ns_config->visible()) {
3802 g_exported_namespaces[ns_config->name()] = ns;
3803 }
Dimitry Ivanov4cabfaa2017-03-07 11:19:05 -08003804 }
3805
3806 // 3. Establish links between namespaces
3807 for (auto& ns_config : namespace_configs) {
3808 auto it_from = namespaces.find(ns_config->name());
3809 CHECK(it_from != namespaces.end());
3810 android_namespace_t* namespace_from = it_from->second;
3811 for (const NamespaceLinkConfig& ns_link : ns_config->links()) {
3812 auto it_to = namespaces.find(ns_link.ns_name());
3813 CHECK(it_to != namespaces.end());
3814 android_namespace_t* namespace_to = it_to->second;
Logan Chien9ee45912018-01-18 12:05:09 +08003815 if (ns_link.allow_all_shared_libs()) {
3816 link_namespaces_all_libs(namespace_from, namespace_to);
3817 } else {
3818 link_namespaces(namespace_from, namespace_to, ns_link.shared_libs().c_str());
3819 }
Dimitry Ivanov4cabfaa2017-03-07 11:19:05 -08003820 }
3821 }
3822 // we can no longer rely on the fact that libdl.so is part of default namespace
3823 // this is why we want to add ld-android.so to all namespaces from ld.config.txt
3824 soinfo* ld_android_so = solist_get_head();
dimitry8b142562018-05-09 15:22:38 +02003825
3826 // we also need vdso to be available for all namespaces (if present)
3827 soinfo* vdso = solist_get_vdso();
Dimitry Ivanov4cabfaa2017-03-07 11:19:05 -08003828 for (auto it : namespaces) {
3829 it.second->add_soinfo(ld_android_so);
dimitry8b142562018-05-09 15:22:38 +02003830 if (vdso != nullptr) {
3831 it.second->add_soinfo(vdso);
3832 }
Jiyong Park02586a22017-05-20 01:01:24 +09003833 // somain and ld_preloads are added to these namespaces after LD_PRELOAD libs are linked
Dimitry Ivanov4cabfaa2017-03-07 11:19:05 -08003834 }
3835
3836 set_application_target_sdk_version(config->target_sdk_version());
Jiyong Park02586a22017-05-20 01:01:24 +09003837
3838 std::vector<android_namespace_t*> created_namespaces;
3839 created_namespaces.reserve(namespaces.size());
3840 for (auto kv : namespaces) {
3841 created_namespaces.push_back(kv.second);
3842 }
3843 return created_namespaces;
Dimitry Ivanov4cabfaa2017-03-07 11:19:05 -08003844}
Jiyong Park01de74e2017-04-03 23:10:37 +09003845
3846// This function finds a namespace exported in ld.config.txt by its name.
3847// A namespace can be exported by setting .visible property to true.
3848android_namespace_t* get_exported_namespace(const char* name) {
3849 if (name == nullptr) {
3850 return nullptr;
3851 }
3852 auto it = g_exported_namespaces.find(std::string(name));
3853 if (it == g_exported_namespaces.end()) {
3854 return nullptr;
3855 }
3856 return it->second;
3857}