blob: 80345baffcf0774e00e1dfbaf4840fe918648999 [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
Elliott Hughes939a7e02015-12-04 15:27:46 -080069#include "android-base/strings.h"
Dimitry Ivanovb996d602016-07-11 18:11:39 -070070#include "android-base/stringprintf.h"
Simon Baldwinaef71952015-01-16 13:22:54 +000071#include "ziparchive/zip_archive.h"
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080072
Elliott Hughes1801db32015-06-08 18:04:00 -070073// Override macros to use C++ style casts.
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -080074#undef ELF_ST_TYPE
75#define ELF_ST_TYPE(x) (static_cast<uint32_t>(x) & 0xf)
76
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -070077static android_namespace_t* g_anonymous_namespace = &g_default_namespace;
Jiyong Park01de74e2017-04-03 23:10:37 +090078static std::unordered_map<std::string, android_namespace_t*> g_exported_namespaces;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -070079
Dmitriy Ivanov600bc3c2015-03-10 15:43:50 -070080static LinkerTypeAllocator<soinfo> g_soinfo_allocator;
81static LinkerTypeAllocator<LinkedListEntry<soinfo>> g_soinfo_links_allocator;
Magnus Malmbornba98d922012-09-12 13:00:55 +020082
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -070083static LinkerTypeAllocator<android_namespace_t> g_namespace_allocator;
Dimitry Ivanovaca299a2016-04-11 12:42:58 -070084static LinkerTypeAllocator<LinkedListEntry<android_namespace_t>> g_namespace_list_allocator;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -070085
Dimitry Ivanov4cabfaa2017-03-07 11:19:05 -080086static const char* const kLdConfigFilePath = "/system/etc/ld.config.txt";
87
Elliott Hughes4eeb1f12013-10-25 17:38:02 -070088#if defined(__LP64__)
Dimitry Ivanova1446972017-03-17 00:08:23 +000089static const char* const kSystemLibDir = "/system/lib64";
90static const char* const kVendorLibDir = "/vendor/lib64";
Vishwath Mohan4113def2017-03-29 15:31:34 -070091static const char* const kAsanSystemLibDir = "/data/asan/system/lib64";
92static const char* const kAsanVendorLibDir = "/data/asan/vendor/lib64";
Elliott Hughes011bc0b2013-10-08 14:27:10 -070093#else
Dimitry Ivanova1446972017-03-17 00:08:23 +000094static const char* const kSystemLibDir = "/system/lib";
95static const char* const kVendorLibDir = "/vendor/lib";
Vishwath Mohan4113def2017-03-29 15:31:34 -070096static const char* const kAsanSystemLibDir = "/data/asan/system/lib";
97static const char* const kAsanVendorLibDir = "/data/asan/vendor/lib";
Elliott Hughes011bc0b2013-10-08 14:27:10 -070098#endif
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -070099
Vishwath Mohan4113def2017-03-29 15:31:34 -0700100static const char* const kAsanLibDirPrefix = "/data/asan";
101
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700102static const char* const kDefaultLdPaths[] = {
103 kSystemLibDir,
104 kVendorLibDir,
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700105 nullptr
Elliott Hughes124fae92012-10-31 14:20:03 -0700106};
David Bartleybc3a5c22009-06-02 18:27:28 -0700107
Evgenii Stepanovd640b222015-07-10 17:54:01 -0700108static const char* const kAsanDefaultLdPaths[] = {
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700109 kAsanSystemLibDir,
110 kSystemLibDir,
111 kAsanVendorLibDir,
112 kVendorLibDir,
Evgenii Stepanovd640b222015-07-10 17:54:01 -0700113 nullptr
114};
115
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700116// Is ASAN enabled?
117static bool g_is_asan = false;
118
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -0700119static CFIShadowWriter g_cfi_shadow;
120
121CFIShadowWriter* get_cfi_shadow() {
122 return &g_cfi_shadow;
123}
124
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700125static bool is_system_library(const std::string& realpath) {
126 for (const auto& dir : g_default_namespace.get_default_library_paths()) {
127 if (file_is_in_dir(realpath, dir)) {
128 return true;
129 }
130 }
131 return false;
132}
133
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700134// Checks if the file exists and not a directory.
135static bool file_exists(const char* path) {
Dimitry Ivanov4cf70242016-08-11 11:11:52 -0700136 struct stat s;
137
138 if (stat(path, &s) != 0) {
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700139 return false;
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700140 }
Dimitry Ivanov4cf70242016-08-11 11:11:52 -0700141
142 return S_ISREG(s.st_mode);
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700143}
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700144
Dimitry Ivanov35c8e3b2017-02-27 12:17:47 -0800145static std::string resolve_soname(const std::string& name) {
146 // We assume that soname equals to basename here
147
148 // TODO(dimitry): consider having honest absolute-path -> soname resolution
149 // note that since we might end up refusing to load this library because
150 // it is not in shared libs list we need to get the soname without actually loading
151 // the library.
152 //
153 // On the other hand there are several places where we already assume that
154 // soname == basename in particular for any not-loaded library mentioned
155 // in DT_NEEDED list.
156 return basename(name.c_str());
157}
158
159static bool maybe_accessible_via_namespace_links(android_namespace_t* ns, const char* name) {
160 std::string soname = resolve_soname(name);
161 for (auto& ns_link : ns->linked_namespaces()) {
162 if (ns_link.is_accessible(soname.c_str())) {
163 return true;
164 }
165 }
166
167 return false;
168}
169
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700170// TODO(dimitry): The grey-list is a workaround for http://b/26394120 ---
171// gradually remove libraries from this list until it is gone.
Dimitry Ivanov35c8e3b2017-02-27 12:17:47 -0800172static bool is_greylisted(android_namespace_t* ns, const char* name, const soinfo* needed_by) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700173 static const char* const kLibraryGreyList[] = {
174 "libandroid_runtime.so",
175 "libbinder.so",
176 "libcrypto.so",
177 "libcutils.so",
178 "libexpat.so",
179 "libgui.so",
180 "libmedia.so",
181 "libnativehelper.so",
182 "libskia.so",
183 "libssl.so",
184 "libstagefright.so",
185 "libsqlite.so",
186 "libui.so",
187 "libutils.so",
188 "libvorbisidec.so",
189 nullptr
190 };
191
Elliott Hughes5bc78c82016-11-16 11:35:43 -0800192 // If you're targeting N, you don't get the greylist.
Elliott Hughes9e27e582017-03-23 17:42:49 -0700193 if (g_greylist_disabled || get_application_target_sdk_version() >= __ANDROID_API_N__) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700194 return false;
195 }
196
197 // if the library needed by a system library - implicitly assume it
Dimitry Ivanov35c8e3b2017-02-27 12:17:47 -0800198 // is greylisted unless it is in the list of shared libraries for one or
199 // more linked namespaces
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700200 if (needed_by != nullptr && is_system_library(needed_by->get_realpath())) {
Dimitry Ivanov35c8e3b2017-02-27 12:17:47 -0800201 return !maybe_accessible_via_namespace_links(ns, name);
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700202 }
203
204 // if this is an absolute path - make sure it points to /system/lib(64)
205 if (name[0] == '/' && dirname(name) == kSystemLibDir) {
206 // and reduce the path to basename
207 name = basename(name);
208 }
209
210 for (size_t i = 0; kLibraryGreyList[i] != nullptr; ++i) {
211 if (strcmp(name, kLibraryGreyList[i]) == 0) {
212 return true;
213 }
214 }
215
216 return false;
217}
218// END OF WORKAROUND
219
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700220static std::vector<std::string> g_ld_preload_names;
Elliott Hughesa4aafd12014-01-13 16:37:47 -0800221
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800222static bool g_anonymous_namespace_initialized;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700223
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800224#if STATS
Elliott Hughesbedfe382012-08-14 14:07:59 -0700225struct linker_stats_t {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700226 int count[kRelocMax];
Elliott Hughesbedfe382012-08-14 14:07:59 -0700227};
228
229static linker_stats_t linker_stats;
230
Dmitriy Ivanov114ff692015-01-14 11:36:38 -0800231void count_relocation(RelocationKind kind) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700232 ++linker_stats.count[kind];
Elliott Hughesbedfe382012-08-14 14:07:59 -0700233}
234#else
Dmitriy Ivanov114ff692015-01-14 11:36:38 -0800235void count_relocation(RelocationKind) {
Elliott Hughesbedfe382012-08-14 14:07:59 -0700236}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800237#endif
238
239#if COUNT_PAGES
Dmitriy Ivanov114ff692015-01-14 11:36:38 -0800240uint32_t bitmask[4096];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800241#endif
242
Elliott Hughesbedfe382012-08-14 14:07:59 -0700243static void notify_gdb_of_load(soinfo* info) {
Dimitry Ivanove97d8ed2016-03-01 15:55:56 -0800244 if (info->is_linker() || info->is_main_executable()) {
245 // gdb already knows about the linker and the main executable.
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700246 return;
247 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800248
Dimitry Ivanov6b788ee2016-02-17 16:08:03 -0800249 link_map* map = &(info->link_map_head);
Nicolas Geoffray0fa54102016-02-18 09:31:24 +0000250
Dimitry Ivanov6b788ee2016-02-17 16:08:03 -0800251 map->l_addr = info->load_bias;
252 // link_map l_name field is not const.
253 map->l_name = const_cast<char*>(info->get_realpath());
254 map->l_ld = info->dynamic;
Nicolas Geoffray0fa54102016-02-18 09:31:24 +0000255
Dimitry Ivanove97d8ed2016-03-01 15:55:56 -0800256 CHECK(map->l_name != nullptr);
257 CHECK(map->l_name[0] != '\0');
258
Dimitry Ivanov6b788ee2016-02-17 16:08:03 -0800259 notify_gdb_of_load(map);
Iliyan Malchev5e12d7e2009-03-24 19:02:00 -0700260}
261
Elliott Hughesbedfe382012-08-14 14:07:59 -0700262static void notify_gdb_of_unload(soinfo* info) {
Dimitry Ivanov6b788ee2016-02-17 16:08:03 -0800263 notify_gdb_of_unload(&(info->link_map_head));
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800264}
265
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -0700266LinkedListEntry<soinfo>* SoinfoListAllocator::alloc() {
267 return g_soinfo_links_allocator.alloc();
268}
269
270void SoinfoListAllocator::free(LinkedListEntry<soinfo>* entry) {
271 g_soinfo_links_allocator.free(entry);
272}
273
Dimitry Ivanovaca299a2016-04-11 12:42:58 -0700274LinkedListEntry<android_namespace_t>* NamespaceListAllocator::alloc() {
275 return g_namespace_list_allocator.alloc();
276}
277
278void NamespaceListAllocator::free(LinkedListEntry<android_namespace_t>* entry) {
279 g_namespace_list_allocator.free(entry);
280}
281
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700282soinfo* soinfo_alloc(android_namespace_t* ns, const char* name,
283 struct stat* file_stat, off64_t file_offset,
284 uint32_t rtld_flags) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700285 if (strlen(name) >= PATH_MAX) {
Magnus Malmbornba98d922012-09-12 13:00:55 +0200286 DL_ERR("library name \"%s\" too long", name);
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700287 return nullptr;
Magnus Malmbornba98d922012-09-12 13:00:55 +0200288 }
289
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700290 TRACE("name %s: allocating soinfo for ns=%p", name, ns);
291
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700292 soinfo* si = new (g_soinfo_allocator.alloc()) soinfo(ns, name, file_stat,
293 file_offset, rtld_flags);
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -0700294
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700295 solist_add_soinfo(si);
Magnus Malmbornba98d922012-09-12 13:00:55 +0200296
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -0700297 si->generate_handle();
298 ns->add_soinfo(si);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700299
Elliott Hughesca0c11b2013-03-12 10:40:45 -0700300 TRACE("name %s: allocated soinfo @ %p", name, si);
Magnus Malmbornba98d922012-09-12 13:00:55 +0200301 return si;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800302}
303
Elliott Hughesfaf05ba2014-02-11 16:59:37 -0800304static void soinfo_free(soinfo* si) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700305 if (si == nullptr) {
306 return;
307 }
308
309 if (si->base != 0 && si->size != 0) {
Dimitry Ivanovf45b0e92016-01-15 11:13:35 -0800310 if (!si->is_mapped_by_caller()) {
311 munmap(reinterpret_cast<void*>(si->base), si->size);
312 } else {
313 // remap the region as PROT_NONE, MAP_ANONYMOUS | MAP_NORESERVE
314 mmap(reinterpret_cast<void*>(si->base), si->size, PROT_NONE,
315 MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
316 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700317 }
318
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700319 TRACE("name %s: freeing soinfo @ %p", si->get_realpath(), si);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700320
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700321 if (!solist_remove_soinfo(si)) {
322 // TODO (dimitry): revisit this - for now preserving the logic
323 // but it does not look right, abort if soinfo is not in the list instead?
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700324 return;
325 }
Elliott Hughes46882792012-08-03 16:49:39 -0700326
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700327 // clear links to/from si
328 si->remove_all_links();
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -0700329
Dmitriy Ivanov609f11b2015-07-08 15:26:46 -0700330 si->~soinfo();
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700331 g_soinfo_allocator.free(si);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800332}
333
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700334static void parse_path(const char* path, const char* delimiters,
335 std::vector<std::string>* resolved_paths) {
336 std::vector<std::string> paths;
337 split_path(path, delimiters, &paths);
338 resolve_paths(paths, resolved_paths);
339}
340
Elliott Hughescade4c32012-12-20 14:42:14 -0800341static void parse_LD_LIBRARY_PATH(const char* path) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700342 std::vector<std::string> ld_libary_paths;
343 parse_path(path, ":", &ld_libary_paths);
344 g_default_namespace.set_ld_library_paths(std::move(ld_libary_paths));
Elliott Hughescade4c32012-12-20 14:42:14 -0800345}
346
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700347static bool realpath_fd(int fd, std::string* realpath) {
348 std::vector<char> buf(PATH_MAX), proc_self_fd(PATH_MAX);
Christopher Ferris7a3681e2017-04-24 17:48:32 -0700349 async_safe_format_buffer(&proc_self_fd[0], proc_self_fd.size(), "/proc/self/fd/%d", fd);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700350 if (readlink(&proc_self_fd[0], &buf[0], buf.size()) == -1) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700351 PRINT("readlink(\"%s\") failed: %s [fd=%d]", &proc_self_fd[0], strerror(errno), fd);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700352 return false;
353 }
354
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700355 *realpath = &buf[0];
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700356 return true;
357}
358
Elliott Hughes4eeb1f12013-10-25 17:38:02 -0700359#if defined(__arm__)
Elliott Hughes46882792012-08-03 16:49:39 -0700360
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700361// For a given PC, find the .so that it belongs to.
362// Returns the base address of the .ARM.exidx section
363// for that .so, and the number of 8-byte entries
364// in that section (via *pcount).
365//
366// Intended to be called by libc's __gnu_Unwind_Find_exidx().
Dimitry Ivanovd9e427c2016-11-22 16:55:25 -0800367_Unwind_Ptr do_dl_unwind_find_exidx(_Unwind_Ptr pc, int* pcount) {
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700368 for (soinfo* si = solist_get_head(); si != 0; si = si->next) {
Elliott Hughesf2c6ad62017-04-21 10:25:56 -0700369 if ((pc >= si->base) && (pc < (si->base + si->size))) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700370 *pcount = si->ARM_exidx_count;
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -0800371 return reinterpret_cast<_Unwind_Ptr>(si->ARM_exidx);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800372 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700373 }
374 *pcount = 0;
Elliott Hughesf2c6ad62017-04-21 10:25:56 -0700375 return 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800376}
Elliott Hughes46882792012-08-03 16:49:39 -0700377
Christopher Ferris24053a42013-08-19 17:45:09 -0700378#endif
Elliott Hughes46882792012-08-03 16:49:39 -0700379
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700380// Here, we only have to provide a callback to iterate across all the
381// loaded libraries. gcc_eh does the rest.
Dmitriy Ivanov7271caf2015-06-29 14:48:25 -0700382int do_dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void* data) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700383 int rv = 0;
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700384 for (soinfo* si = solist_get_head(); si != nullptr; si = si->next) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700385 dl_phdr_info dl_info;
386 dl_info.dlpi_addr = si->link_map_head.l_addr;
387 dl_info.dlpi_name = si->link_map_head.l_name;
388 dl_info.dlpi_phdr = si->phdr;
389 dl_info.dlpi_phnum = si->phnum;
390 rv = cb(&dl_info, sizeof(dl_phdr_info), data);
391 if (rv != 0) {
392 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800393 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700394 }
395 return rv;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800396}
Elliott Hughes46882792012-08-03 16:49:39 -0700397
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800398
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700399bool soinfo_do_lookup(soinfo* si_from, const char* name, const version_info* vi,
Dimitry Ivanovb943f302016-08-03 16:00:10 -0700400 soinfo** si_found_in, const soinfo_list_t& global_group,
401 const soinfo_list_t& local_group, const ElfW(Sym)** symbol) {
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800402 SymbolName symbol_name(name);
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700403 const ElfW(Sym)* s = nullptr;
Iliyan Malchev6ed80c82009-09-28 19:38:04 -0700404
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -0700405 /* "This element's presence in a shared object library alters the dynamic linker's
406 * symbol resolution algorithm for references within the library. Instead of starting
407 * a symbol search with the executable file, the dynamic linker starts from the shared
408 * object itself. If the shared object fails to supply the referenced symbol, the
409 * dynamic linker then searches the executable file and other shared objects as usual."
410 *
411 * http://www.sco.com/developers/gabi/2012-12-31/ch5.dynamic.html
412 *
413 * Note that this is unlikely since static linker avoids generating
414 * relocations for -Bsymbolic linked dynamic executables.
415 */
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700416 if (si_from->has_DT_SYMBOLIC) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700417 DEBUG("%s: looking up %s in local scope (DT_SYMBOLIC)", si_from->get_realpath(), name);
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700418 if (!si_from->find_symbol_by_name(symbol_name, vi, &s)) {
419 return false;
420 }
421
Dmitriy Ivanov8f61d992014-09-16 14:31:06 -0700422 if (s != nullptr) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700423 *si_found_in = si_from;
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -0700424 }
425 }
426
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700427 // 1. Look for it in global_group
428 if (s == nullptr) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700429 bool error = false;
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700430 global_group.visit([&](soinfo* global_si) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700431 DEBUG("%s: looking up %s in %s (from global group)",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700432 si_from->get_realpath(), name, global_si->get_realpath());
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700433 if (!global_si->find_symbol_by_name(symbol_name, vi, &s)) {
434 error = true;
435 return false;
436 }
437
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -0700438 if (s != nullptr) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700439 *si_found_in = global_si;
440 return false;
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -0700441 }
Dmitriy Ivanovc2048942014-08-29 10:15:25 -0700442
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700443 return true;
444 });
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700445
446 if (error) {
447 return false;
448 }
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -0700449 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700450
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700451 // 2. Look for it in the local group
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700452 if (s == nullptr) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700453 bool error = false;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700454 local_group.visit([&](soinfo* local_si) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700455 if (local_si == si_from && si_from->has_DT_SYMBOLIC) {
Dmitriy Ivanove47b3f82014-10-23 14:19:07 -0700456 // we already did this - skip
457 return true;
458 }
459
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700460 DEBUG("%s: looking up %s in %s (from local group)",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700461 si_from->get_realpath(), name, local_si->get_realpath());
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700462 if (!local_si->find_symbol_by_name(symbol_name, vi, &s)) {
463 error = true;
464 return false;
465 }
466
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700467 if (s != nullptr) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700468 *si_found_in = local_si;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700469 return false;
470 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700471
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700472 return true;
473 });
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700474
475 if (error) {
476 return false;
477 }
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700478 }
479
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700480 if (s != nullptr) {
481 TRACE_TYPE(LOOKUP, "si %s sym %s s->st_value = %p, "
482 "found in %s, base = %p, load bias = %p",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700483 si_from->get_realpath(), name, reinterpret_cast<void*>(s->st_value),
484 (*si_found_in)->get_realpath(), reinterpret_cast<void*>((*si_found_in)->base),
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700485 reinterpret_cast<void*>((*si_found_in)->load_bias));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700486 }
Iliyan Malchev6ed80c82009-09-28 19:38:04 -0700487
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700488 *symbol = s;
489 return true;
Iliyan Malchev6ed80c82009-09-28 19:38:04 -0700490}
491
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700492ProtectedDataGuard::ProtectedDataGuard() {
493 if (ref_count_++ == 0) {
494 protect_data(PROT_READ | PROT_WRITE);
495 }
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700496
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700497 if (ref_count_ == 0) { // overflow
Christopher Ferris7a3681e2017-04-24 17:48:32 -0700498 async_safe_fatal("Too many nested calls to dlopen()");
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -0800499 }
Dimitry Ivanov68e6c032017-02-01 12:55:11 -0800500}
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -0800501
Dimitry Ivanov68e6c032017-02-01 12:55:11 -0800502ProtectedDataGuard::~ProtectedDataGuard() {
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700503 if (--ref_count_ == 0) {
504 protect_data(PROT_READ);
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -0800505 }
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700506}
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -0800507
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700508void ProtectedDataGuard::protect_data(int protection) {
509 g_soinfo_allocator.protect_all(protection);
510 g_soinfo_links_allocator.protect_all(protection);
511 g_namespace_allocator.protect_all(protection);
512 g_namespace_list_allocator.protect_all(protection);
513}
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -0800514
515size_t ProtectedDataGuard::ref_count_ = 0;
516
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700517// Each size has it's own allocator.
518template<size_t size>
519class SizeBasedAllocator {
520 public:
521 static void* alloc() {
522 return allocator_.alloc();
523 }
Dmitriy Ivanov4bea4982014-08-29 14:01:48 -0700524
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700525 static void free(void* ptr) {
526 allocator_.free(ptr);
527 }
Dmitriy Ivanov4bea4982014-08-29 14:01:48 -0700528
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700529 private:
530 static LinkerBlockAllocator allocator_;
531};
532
533template<size_t size>
534LinkerBlockAllocator SizeBasedAllocator<size>::allocator_(size);
535
536template<typename T>
537class TypeBasedAllocator {
538 public:
539 static T* alloc() {
540 return reinterpret_cast<T*>(SizeBasedAllocator<sizeof(T)>::alloc());
541 }
542
543 static void free(T* ptr) {
544 SizeBasedAllocator<sizeof(T)>::free(ptr);
545 }
546};
547
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700548class LoadTask {
549 public:
550 struct deleter_t {
551 void operator()(LoadTask* t) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700552 t->~LoadTask();
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700553 TypeBasedAllocator<LoadTask>::free(t);
554 }
555 };
556
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700557 static deleter_t deleter;
558
Dimitry Ivanov7d429d32017-02-01 15:28:52 -0800559 static LoadTask* create(const char* name,
560 soinfo* needed_by,
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700561 std::unordered_map<const soinfo*, ElfReader>* readers_map) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700562 LoadTask* ptr = TypeBasedAllocator<LoadTask>::alloc();
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700563 return new (ptr) LoadTask(name, needed_by, readers_map);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700564 }
565
566 const char* get_name() const {
567 return name_;
568 }
569
570 soinfo* get_needed_by() const {
571 return needed_by_;
572 }
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700573
574 soinfo* get_soinfo() const {
575 return si_;
576 }
577
578 void set_soinfo(soinfo* si) {
579 si_ = si;
580 }
581
582 off64_t get_file_offset() const {
583 return file_offset_;
584 }
585
586 void set_file_offset(off64_t offset) {
587 file_offset_ = offset;
588 }
589
590 int get_fd() const {
591 return fd_;
592 }
593
594 void set_fd(int fd, bool assume_ownership) {
595 fd_ = fd;
596 close_fd_ = assume_ownership;
597 }
598
599 const android_dlextinfo* get_extinfo() const {
600 return extinfo_;
601 }
602
603 void set_extinfo(const android_dlextinfo* extinfo) {
604 extinfo_ = extinfo;
605 }
606
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700607 bool is_dt_needed() const {
608 return is_dt_needed_;
609 }
610
611 void set_dt_needed(bool is_dt_needed) {
612 is_dt_needed_ = is_dt_needed;
613 }
614
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700615 const ElfReader& get_elf_reader() const {
616 CHECK(si_ != nullptr);
617 return (*elf_readers_map_)[si_];
618 }
619
620 ElfReader& get_elf_reader() {
621 CHECK(si_ != nullptr);
622 return (*elf_readers_map_)[si_];
623 }
624
625 std::unordered_map<const soinfo*, ElfReader>* get_readers_map() {
626 return elf_readers_map_;
627 }
628
629 bool read(const char* realpath, off64_t file_size) {
630 ElfReader& elf_reader = get_elf_reader();
631 return elf_reader.Read(realpath, fd_, file_offset_, file_size);
632 }
633
634 bool load() {
635 ElfReader& elf_reader = get_elf_reader();
636 if (!elf_reader.Load(extinfo_)) {
637 return false;
638 }
639
640 si_->base = elf_reader.load_start();
641 si_->size = elf_reader.load_size();
Dimitry Ivanovf45b0e92016-01-15 11:13:35 -0800642 si_->set_mapped_by_caller(elf_reader.is_mapped_by_caller());
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700643 si_->load_bias = elf_reader.load_bias();
644 si_->phnum = elf_reader.phdr_count();
645 si_->phdr = elf_reader.loaded_phdr();
646
647 return true;
648 }
649
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700650 private:
Dimitry Ivanov7d429d32017-02-01 15:28:52 -0800651 LoadTask(const char* name,
652 soinfo* needed_by,
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700653 std::unordered_map<const soinfo*, ElfReader>* readers_map)
654 : name_(name), needed_by_(needed_by), si_(nullptr),
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700655 fd_(-1), close_fd_(false), file_offset_(0), elf_readers_map_(readers_map),
656 is_dt_needed_(false) {}
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700657
658 ~LoadTask() {
659 if (fd_ != -1 && close_fd_) {
660 close(fd_);
661 }
662 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700663
664 const char* name_;
665 soinfo* needed_by_;
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700666 soinfo* si_;
667 const android_dlextinfo* extinfo_;
668 int fd_;
669 bool close_fd_;
670 off64_t file_offset_;
671 std::unordered_map<const soinfo*, ElfReader>* elf_readers_map_;
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700672 // TODO(dimitry): needed by workaround for http://b/26394120 (the grey-list)
673 bool is_dt_needed_;
674 // END OF WORKAROUND
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700675
676 DISALLOW_IMPLICIT_CONSTRUCTORS(LoadTask);
677};
678
Ningsheng Jiane93be992014-09-16 15:22:10 +0800679LoadTask::deleter_t LoadTask::deleter;
680
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700681template <typename T>
682using linked_list_t = LinkedList<T, TypeBasedAllocator<LinkedListEntry<T>>>;
683
684typedef linked_list_t<soinfo> SoinfoLinkedList;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700685typedef linked_list_t<const char> StringLinkedList;
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700686typedef std::vector<LoadTask*> LoadTaskList;
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700687
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800688enum walk_action_result_t : uint32_t {
689 kWalkStop = 0,
690 kWalkContinue = 1,
691 kWalkSkip = 2
692};
Dmitriy Ivanovaa0f2bd2014-07-28 17:32:20 -0700693
Adrian DCc6927502017-04-08 22:40:01 +0200694static soinfo* find_library(android_namespace_t* ns,
695 const char* name, int rtld_flags,
696 const android_dlextinfo* extinfo,
697 soinfo* needed_by);
698
699// g_ld_all_shim_libs maintains the references to memory as it used
700// in the soinfo structures and in the g_active_shim_libs list.
701
702typedef std::pair<std::string, std::string> ShimDescriptor;
703static std::vector<ShimDescriptor> g_ld_all_shim_libs;
704
705// g_active_shim_libs are all shim libs that are still eligible
706// to be loaded. We must remove a shim lib from the list before
707// we load the library to avoid recursive loops (load shim libA
708// for libB where libA also links against libB).
709
710static linked_list_t<const ShimDescriptor> g_active_shim_libs;
711
712static void reset_g_active_shim_libs(void) {
713 g_active_shim_libs.clear();
714 for (const auto& pair : g_ld_all_shim_libs) {
715 g_active_shim_libs.push_back(&pair);
716 }
717}
718
719void parse_LD_SHIM_LIBS(const char* path) {
720 g_ld_all_shim_libs.clear();
721 if (path != nullptr) {
722 // We have historically supported ':' as well as ' ' in LD_SHIM_LIBS.
723 for (const auto& pair : android::base::Split(path, " :")) {
724 size_t pos = pair.find('|');
725 if (pos > 0 && pos < pair.length() - 1) {
726 auto desc = std::pair<std::string, std::string>(pair.substr(0, pos), pair.substr(pos + 1));
727 g_ld_all_shim_libs.push_back(desc);
728 }
729 }
730 }
731 reset_g_active_shim_libs();
732}
733
734template<typename F>
735static void for_each_matching_shim(const char *const path, F action) {
736 if (path == nullptr) return;
737 INFO("Finding shim libs for \"%s\"\n", path);
738 std::vector<const ShimDescriptor *> matched;
739
740 g_active_shim_libs.for_each([&](const ShimDescriptor *a_pair) {
741 if (a_pair->first == path) {
742 matched.push_back(a_pair);
743 }
744 });
745
746 g_active_shim_libs.remove_if([&](const ShimDescriptor *a_pair) {
747 return a_pair->first == path;
748 });
749
750 for (const auto& one_pair : matched) {
751 INFO("Injecting shim lib \"%s\" as needed for %s", one_pair->second.c_str(), path);
752 action(one_pair->second.c_str());
753 }
754}
755
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700756// This function walks down the tree of soinfo dependencies
757// in breadth-first order and
758// * calls action(soinfo* si) for each node, and
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800759// * terminates walk if action returns kWalkStop
760// * skips children of the node if action
761// return kWalkSkip
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700762//
763// walk_dependencies_tree returns false if walk was terminated
764// by the action and true otherwise.
765template<typename F>
766static bool walk_dependencies_tree(soinfo* root_soinfos[], size_t root_soinfos_size, F action) {
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700767 SoinfoLinkedList visit_list;
768 SoinfoLinkedList visited;
769
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700770 for (size_t i = 0; i < root_soinfos_size; ++i) {
771 visit_list.push_back(root_soinfos[i]);
772 }
773
774 soinfo* si;
775 while ((si = visit_list.pop_front()) != nullptr) {
776 if (visited.contains(si)) {
Dmitriy Ivanov042426b2014-08-12 21:02:13 -0700777 continue;
778 }
779
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800780 walk_action_result_t result = action(si);
781
782 if (result == kWalkStop) {
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700783 return false;
Dmitriy Ivanovaa0f2bd2014-07-28 17:32:20 -0700784 }
785
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700786 visited.push_back(si);
787
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800788 if (result != kWalkSkip) {
789 si->get_children().for_each([&](soinfo* child) {
790 visit_list.push_back(child);
791 });
792 }
Dmitriy Ivanovaa0f2bd2014-07-28 17:32:20 -0700793 }
794
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700795 return true;
796}
797
798
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800799static const ElfW(Sym)* dlsym_handle_lookup(android_namespace_t* ns,
800 soinfo* root,
801 soinfo* skip_until,
802 soinfo** found,
803 SymbolName& symbol_name,
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800804 const version_info* vi) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700805 const ElfW(Sym)* result = nullptr;
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700806 bool skip_lookup = skip_until != nullptr;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700807
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700808 walk_dependencies_tree(&root, 1, [&](soinfo* current_soinfo) {
809 if (skip_lookup) {
810 skip_lookup = current_soinfo != skip_until;
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800811 return kWalkContinue;
812 }
813
814 if (!ns->is_accessible(current_soinfo)) {
815 return kWalkSkip;
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700816 }
817
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800818 if (!current_soinfo->find_symbol_by_name(symbol_name, vi, &result)) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700819 result = nullptr;
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800820 return kWalkStop;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700821 }
822
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700823 if (result != nullptr) {
824 *found = current_soinfo;
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800825 return kWalkStop;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700826 }
827
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800828 return kWalkContinue;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700829 });
830
831 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800832}
833
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800834static const ElfW(Sym)* dlsym_linear_lookup(android_namespace_t* ns,
835 const char* name,
836 const version_info* vi,
837 soinfo** found,
838 soinfo* caller,
839 void* handle);
840
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700841// This is used by dlsym(3). It performs symbol lookup only within the
842// specified soinfo object and its dependencies in breadth first order.
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800843static const ElfW(Sym)* dlsym_handle_lookup(soinfo* si,
844 soinfo** found,
845 const char* name,
846 const version_info* vi) {
Dmitriy Ivanovf439b5a2015-05-30 13:04:39 -0700847 // According to man dlopen(3) and posix docs in the case when si is handle
848 // of the main executable we need to search not only in the executable and its
849 // dependencies but also in all libraries loaded with RTLD_GLOBAL.
850 //
851 // Since RTLD_GLOBAL is always set for the main executable and all dt_needed shared
852 // libraries and they are loaded in breath-first (correct) order we can just execute
853 // dlsym(RTLD_DEFAULT, ...); instead of doing two stage lookup.
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700854 if (si == solist_get_somain()) {
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800855 return dlsym_linear_lookup(&g_default_namespace, name, vi, found, nullptr, RTLD_DEFAULT);
Dmitriy Ivanovf439b5a2015-05-30 13:04:39 -0700856 }
857
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700858 SymbolName symbol_name(name);
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800859 // note that the namespace is not the namespace associated with caller_addr
860 // we use ns associated with root si intentionally here. Using caller_ns
861 // causes problems when user uses dlopen_ext to open a library in the separate
862 // namespace and then calls dlsym() on the handle.
863 return dlsym_handle_lookup(si->get_primary_namespace(), si, nullptr, found, symbol_name, vi);
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700864}
865
Brian Carlstromd4ee82d2013-02-28 15:58:45 -0800866/* This is used by dlsym(3) to performs a global symbol lookup. If the
867 start value is null (for RTLD_DEFAULT), the search starts at the
868 beginning of the global solist. Otherwise the search starts at the
869 specified soinfo (for RTLD_NEXT).
Iliyan Malchev6ed80c82009-09-28 19:38:04 -0700870 */
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800871static const ElfW(Sym)* dlsym_linear_lookup(android_namespace_t* ns,
872 const char* name,
873 const version_info* vi,
874 soinfo** found,
875 soinfo* caller,
876 void* handle) {
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800877 SymbolName symbol_name(name);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800878
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -0700879 auto& soinfo_list = ns->soinfo_list();
880 auto start = soinfo_list.begin();
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -0700881
882 if (handle == RTLD_NEXT) {
Dmitriy Ivanovb96ac412015-05-22 12:34:42 -0700883 if (caller == nullptr) {
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -0700884 return nullptr;
885 } else {
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -0700886 auto it = soinfo_list.find(caller);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700887 CHECK (it != soinfo_list.end());
888 start = ++it;
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -0700889 }
Elliott Hughescade4c32012-12-20 14:42:14 -0800890 }
891
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700892 const ElfW(Sym)* s = nullptr;
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -0700893 for (auto it = start, end = soinfo_list.end(); it != end; ++it) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700894 soinfo* si = *it;
Dmitriy Ivanov19133522015-06-02 17:36:54 -0700895 // Do not skip RTLD_LOCAL libraries in dlsym(RTLD_DEFAULT, ...)
Elliott Hughes5bc78c82016-11-16 11:35:43 -0800896 // if the library is opened by application with target api level < M.
Dmitriy Ivanov19133522015-06-02 17:36:54 -0700897 // See http://b/21565766
Elliott Hughes5bc78c82016-11-16 11:35:43 -0800898 if ((si->get_rtld_flags() & RTLD_GLOBAL) == 0 &&
899 si->get_target_sdk_version() >= __ANDROID_API_M__) {
Dmitriy Ivanove8ba50f2014-09-15 17:00:10 -0700900 continue;
901 }
902
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800903 if (!si->find_symbol_by_name(symbol_name, vi, &s)) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700904 return nullptr;
905 }
906
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700907 if (s != nullptr) {
Elliott Hughescade4c32012-12-20 14:42:14 -0800908 *found = si;
909 break;
Matt Fischer1698d9e2009-12-31 12:17:56 -0600910 }
Elliott Hughescade4c32012-12-20 14:42:14 -0800911 }
Matt Fischer1698d9e2009-12-31 12:17:56 -0600912
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700913 // If not found - use dlsym_handle_lookup for caller's
914 // local_group unless it is part of the global group in which
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -0700915 // case we already did it.
916 if (s == nullptr && caller != nullptr &&
917 (caller->get_rtld_flags() & RTLD_GLOBAL) == 0) {
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800918 soinfo* local_group_root = caller->get_local_group_root();
919
920 return dlsym_handle_lookup(local_group_root->get_primary_namespace(),
921 local_group_root,
922 (handle == RTLD_NEXT) ? caller : nullptr,
923 found,
924 symbol_name,
925 vi);
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -0700926 }
927
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700928 if (s != nullptr) {
Elliott Hughesc00f2cb2013-10-04 17:01:33 -0700929 TRACE_TYPE(LOOKUP, "%s s->st_value = %p, found->base = %p",
930 name, reinterpret_cast<void*>(s->st_value), reinterpret_cast<void*>((*found)->base));
Elliott Hughescade4c32012-12-20 14:42:14 -0800931 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800932
Elliott Hughescade4c32012-12-20 14:42:14 -0800933 return s;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800934}
935
Kito Chengfa8c05d2013-03-12 14:58:06 +0800936soinfo* find_containing_library(const void* p) {
Elliott Hughes0266ae52014-02-10 17:46:57 -0800937 ElfW(Addr) address = reinterpret_cast<ElfW(Addr)>(p);
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700938 for (soinfo* si = solist_get_head(); si != nullptr; si = si->next) {
Kito Chengfa8c05d2013-03-12 14:58:06 +0800939 if (address >= si->base && address - si->base < si->size) {
940 return si;
Matt Fischere2a8b1f2009-12-31 12:17:40 -0600941 }
Kito Chengfa8c05d2013-03-12 14:58:06 +0800942 }
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700943 return nullptr;
Matt Fischere2a8b1f2009-12-31 12:17:40 -0600944}
945
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700946class ZipArchiveCache {
947 public:
948 ZipArchiveCache() {}
949 ~ZipArchiveCache();
950
951 bool get_or_open(const char* zip_path, ZipArchiveHandle* handle);
952 private:
953 DISALLOW_COPY_AND_ASSIGN(ZipArchiveCache);
954
955 std::unordered_map<std::string, ZipArchiveHandle> cache_;
956};
957
958bool ZipArchiveCache::get_or_open(const char* zip_path, ZipArchiveHandle* handle) {
959 std::string key(zip_path);
960
961 auto it = cache_.find(key);
962 if (it != cache_.end()) {
963 *handle = it->second;
964 return true;
965 }
966
967 int fd = TEMP_FAILURE_RETRY(open(zip_path, O_RDONLY | O_CLOEXEC));
968 if (fd == -1) {
969 return false;
970 }
971
972 if (OpenArchiveFd(fd, "", handle) != 0) {
973 // invalid zip-file (?)
Yabin Cui722072d2016-03-21 17:10:12 -0700974 CloseArchive(handle);
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700975 close(fd);
976 return false;
977 }
978
979 cache_[key] = *handle;
980 return true;
981}
982
983ZipArchiveCache::~ZipArchiveCache() {
Dmitriy Ivanov5dce8942015-10-13 12:14:16 -0700984 for (const auto& it : cache_) {
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700985 CloseArchive(it.second);
986 }
987}
988
989static int open_library_in_zipfile(ZipArchiveCache* zip_archive_cache,
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700990 const char* const input_path,
991 off64_t* file_offset, std::string* realpath) {
992 std::string normalized_path;
993 if (!normalize_path(input_path, &normalized_path)) {
994 return -1;
995 }
996
997 const char* const path = normalized_path.c_str();
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700998 TRACE("Trying zip file open from path \"%s\" -> normalized \"%s\"", input_path, path);
Simon Baldwinaef71952015-01-16 13:22:54 +0000999
Dmitriy Ivanov402a7502015-06-09 13:46:51 -07001000 // Treat an '!/' separator inside a path as the separator between the name
Simon Baldwinaef71952015-01-16 13:22:54 +00001001 // of the zip file on disk and the subdirectory to search within it.
Dmitriy Ivanov402a7502015-06-09 13:46:51 -07001002 // For example, if path is "foo.zip!/bar/bas/x.so", then we search for
Simon Baldwinaef71952015-01-16 13:22:54 +00001003 // "bar/bas/x.so" within "foo.zip".
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001004 const char* const separator = strstr(path, kZipFileSeparator);
Simon Baldwinaef71952015-01-16 13:22:54 +00001005 if (separator == nullptr) {
1006 return -1;
Elliott Hughes124fae92012-10-31 14:20:03 -07001007 }
Simon Baldwinaef71952015-01-16 13:22:54 +00001008
1009 char buf[512];
1010 if (strlcpy(buf, path, sizeof(buf)) >= sizeof(buf)) {
1011 PRINT("Warning: ignoring very long library path: %s", path);
1012 return -1;
1013 }
1014
1015 buf[separator - path] = '\0';
1016
1017 const char* zip_path = buf;
Dmitriy Ivanov402a7502015-06-09 13:46:51 -07001018 const char* file_path = &buf[separator - path + 2];
Simon Baldwinaef71952015-01-16 13:22:54 +00001019 int fd = TEMP_FAILURE_RETRY(open(zip_path, O_RDONLY | O_CLOEXEC));
1020 if (fd == -1) {
1021 return -1;
1022 }
1023
1024 ZipArchiveHandle handle;
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001025 if (!zip_archive_cache->get_or_open(zip_path, &handle)) {
Simon Baldwinaef71952015-01-16 13:22:54 +00001026 // invalid zip-file (?)
1027 close(fd);
1028 return -1;
1029 }
1030
Simon Baldwinaef71952015-01-16 13:22:54 +00001031 ZipEntry entry;
1032
Yusuke Sato56f40fb2015-06-25 14:56:07 -07001033 if (FindEntry(handle, ZipString(file_path), &entry) != 0) {
Simon Baldwinaef71952015-01-16 13:22:54 +00001034 // Entry was not found.
1035 close(fd);
1036 return -1;
1037 }
1038
1039 // Check if it is properly stored
1040 if (entry.method != kCompressStored || (entry.offset % PAGE_SIZE) != 0) {
1041 close(fd);
1042 return -1;
1043 }
1044
1045 *file_offset = entry.offset;
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001046
1047 if (realpath_fd(fd, realpath)) {
1048 *realpath += separator;
1049 } else {
1050 PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.",
1051 normalized_path.c_str());
1052 *realpath = normalized_path;
1053 }
1054
Simon Baldwinaef71952015-01-16 13:22:54 +00001055 return fd;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001056}
1057
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07001058static bool format_path(char* buf, size_t buf_size, const char* path, const char* name) {
Christopher Ferris7a3681e2017-04-24 17:48:32 -07001059 int n = async_safe_format_buffer(buf, buf_size, "%s/%s", path, name);
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07001060 if (n < 0 || n >= static_cast<int>(buf_size)) {
1061 PRINT("Warning: ignoring very long library path: %s/%s", path, name);
1062 return false;
1063 }
Simon Baldwinaef71952015-01-16 13:22:54 +00001064
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07001065 return true;
1066}
1067
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001068static int open_library_on_paths(ZipArchiveCache* zip_archive_cache,
1069 const char* name, off64_t* file_offset,
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001070 const std::vector<std::string>& paths,
1071 std::string* realpath) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001072 for (const auto& path : paths) {
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07001073 char buf[512];
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001074 if (!format_path(buf, sizeof(buf), path.c_str(), name)) {
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07001075 continue;
1076 }
1077
1078 int fd = -1;
Dmitriy Ivanov730ed9d2015-07-16 04:52:06 -07001079 if (strstr(buf, kZipFileSeparator) != nullptr) {
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001080 fd = open_library_in_zipfile(zip_archive_cache, buf, file_offset, realpath);
Simon Baldwinaef71952015-01-16 13:22:54 +00001081 }
1082
1083 if (fd == -1) {
1084 fd = TEMP_FAILURE_RETRY(open(buf, O_RDONLY | O_CLOEXEC));
1085 if (fd != -1) {
1086 *file_offset = 0;
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001087 if (!realpath_fd(fd, realpath)) {
1088 PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.", buf);
1089 *realpath = buf;
1090 }
Simon Baldwinaef71952015-01-16 13:22:54 +00001091 }
1092 }
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07001093
1094 if (fd != -1) {
1095 return fd;
1096 }
Simon Baldwinaef71952015-01-16 13:22:54 +00001097 }
1098
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07001099 return -1;
Simon Baldwinaef71952015-01-16 13:22:54 +00001100}
1101
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001102static int open_library(android_namespace_t* ns,
1103 ZipArchiveCache* zip_archive_cache,
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001104 const char* name, soinfo *needed_by,
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001105 off64_t* file_offset, std::string* realpath) {
Elliott Hughesca0c11b2013-03-12 10:40:45 -07001106 TRACE("[ opening %s ]", name);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001107
Elliott Hughes124fae92012-10-31 14:20:03 -07001108 // 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 -07001109 if (strchr(name, '/') != nullptr) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001110 int fd = -1;
1111
Dmitriy Ivanov730ed9d2015-07-16 04:52:06 -07001112 if (strstr(name, kZipFileSeparator) != nullptr) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001113 fd = open_library_in_zipfile(zip_archive_cache, name, file_offset, realpath);
1114 }
1115
1116 if (fd == -1) {
1117 fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_CLOEXEC));
Simon Baldwinaef71952015-01-16 13:22:54 +00001118 if (fd != -1) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001119 *file_offset = 0;
1120 if (!realpath_fd(fd, realpath)) {
1121 PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.", name);
1122 *realpath = name;
1123 }
Simon Baldwinaef71952015-01-16 13:22:54 +00001124 }
1125 }
1126
Dmitriy Ivanove44fffd2015-03-17 17:12:18 -07001127 return fd;
Elliott Hughes124fae92012-10-31 14:20:03 -07001128 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001129
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001130 // Otherwise we try LD_LIBRARY_PATH first, and fall back to the default library path
1131 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 -07001132 if (fd == -1 && needed_by != nullptr) {
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001133 fd = open_library_on_paths(zip_archive_cache, name, file_offset, needed_by->get_dt_runpath(), realpath);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001134 // Check if the library is accessible
1135 if (fd != -1 && !ns->is_accessible(*realpath)) {
1136 fd = -1;
1137 }
Evgenii Stepanov68650822015-06-10 13:38:39 -07001138 }
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001139
Elliott Hughes124fae92012-10-31 14:20:03 -07001140 if (fd == -1) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001141 fd = open_library_on_paths(zip_archive_cache, name, file_offset, ns->get_default_library_paths(), realpath);
Elliott Hughes124fae92012-10-31 14:20:03 -07001142 }
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001143
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001144 // TODO(dimitry): workaround for http://b/26394120 (the grey-list)
Jiyong Park37b91af2017-05-05 22:07:05 +09001145 if (fd == -1 && ns->is_greylist_enabled() && is_greylisted(ns, name, needed_by)) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001146 // try searching for it on default_namespace default_library_path
1147 fd = open_library_on_paths(zip_archive_cache, name, file_offset,
1148 g_default_namespace.get_default_library_paths(), realpath);
1149 }
1150 // END OF WORKAROUND
1151
Elliott Hughes124fae92012-10-31 14:20:03 -07001152 return fd;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001153}
1154
Dimitry Ivanov3f660572016-09-09 10:00:39 -07001155const char* fix_dt_needed(const char* dt_needed, const char* sopath __unused) {
Dmitriy Ivanovd974e882015-05-27 18:29:41 -07001156#if !defined(__LP64__)
1157 // Work around incorrect DT_NEEDED entries for old apps: http://b/21364029
Elliott Hughes5bc78c82016-11-16 11:35:43 -08001158 if (get_application_target_sdk_version() < __ANDROID_API_M__) {
Dmitriy Ivanovd974e882015-05-27 18:29:41 -07001159 const char* bname = basename(dt_needed);
1160 if (bname != dt_needed) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001161 DL_WARN("library \"%s\" has invalid DT_NEEDED entry \"%s\"", sopath, dt_needed);
1162 add_dlwarning(sopath, "invalid DT_NEEDED entry", dt_needed);
Dmitriy Ivanovd974e882015-05-27 18:29:41 -07001163 }
1164
1165 return bname;
1166 }
1167#endif
1168 return dt_needed;
1169}
1170
LuK13375daa70f2017-09-07 14:09:07 +02001171static const char* get_executable_path() {
1172 static std::string executable_path;
1173 if (executable_path.empty()) {
1174 char path[PATH_MAX];
1175 ssize_t path_len = readlink("/proc/self/exe", path, sizeof(path));
1176 if (path_len == -1 || path_len >= static_cast<ssize_t>(sizeof(path))) {
LuK1337053fc0e2017-09-07 11:28:32 +02001177 async_safe_fatal("readlink('/proc/self/exe') failed: %s", strerror(errno));
LuK13375daa70f2017-09-07 14:09:07 +02001178 }
1179 executable_path = std::string(path, path_len);
1180 }
1181
1182 return executable_path.c_str();
1183}
1184
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001185template<typename F>
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001186static void for_each_dt_needed(const ElfReader& elf_reader, F action) {
LuK13375daa70f2017-09-07 14:09:07 +02001187 for_each_matching_shim(get_executable_path(), action);
Adrian DCc6927502017-04-08 22:40:01 +02001188 for_each_matching_shim(elf_reader.name(), action);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001189 for (const ElfW(Dyn)* d = elf_reader.dynamic(); d->d_tag != DT_NULL; ++d) {
1190 if (d->d_tag == DT_NEEDED) {
1191 action(fix_dt_needed(elf_reader.get_string(d->d_un.d_val), elf_reader.name()));
1192 }
1193 }
1194}
1195
Dimitry Ivanovd3e7d082017-03-27 14:11:02 -07001196static bool find_loaded_library_by_inode(android_namespace_t* ns,
1197 const struct stat& file_stat,
1198 off64_t file_offset,
1199 bool search_linked_namespaces,
1200 soinfo** candidate) {
1201
1202 auto predicate = [&](soinfo* si) {
1203 return si->get_st_dev() != 0 &&
1204 si->get_st_ino() != 0 &&
1205 si->get_st_dev() == file_stat.st_dev &&
1206 si->get_st_ino() == file_stat.st_ino &&
1207 si->get_file_offset() == file_offset;
1208 };
1209
1210 *candidate = ns->soinfo_list().find_if(predicate);
1211
1212 if (*candidate == nullptr && search_linked_namespaces) {
1213 for (auto& link : ns->linked_namespaces()) {
1214 android_namespace_t* linked_ns = link.linked_namespace();
1215 soinfo* si = linked_ns->soinfo_list().find_if(predicate);
1216
1217 if (si != nullptr && link.is_accessible(si->get_soname())) {
1218 *candidate = si;
1219 return true;
1220 }
1221 }
1222 }
1223
1224 return *candidate != nullptr;
1225}
1226
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001227static bool load_library(android_namespace_t* ns,
1228 LoadTask* task,
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001229 LoadTaskList* load_tasks,
1230 int rtld_flags,
Dimitry Ivanovd3e7d082017-03-27 14:11:02 -07001231 const std::string& realpath,
1232 bool search_linked_namespaces) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001233 off64_t file_offset = task->get_file_offset();
1234 const char* name = task->get_name();
1235 const android_dlextinfo* extinfo = task->get_extinfo();
1236
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001237 if ((file_offset % PAGE_SIZE) != 0) {
Dmitriy Ivanova6c12792014-10-21 12:09:18 -07001238 DL_ERR("file offset for the library \"%s\" is not page-aligned: %" PRId64, name, file_offset);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001239 return false;
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001240 }
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001241 if (file_offset < 0) {
1242 DL_ERR("file offset for the library \"%s\" is negative: %" PRId64, name, file_offset);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001243 return false;
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001244 }
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001245
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001246 struct stat file_stat;
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001247 if (TEMP_FAILURE_RETRY(fstat(task->get_fd(), &file_stat)) != 0) {
Dmitriy Ivanova6c12792014-10-21 12:09:18 -07001248 DL_ERR("unable to stat file for the library \"%s\": %s", name, strerror(errno));
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001249 return false;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001250 }
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001251 if (file_offset >= file_stat.st_size) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07001252 DL_ERR("file offset for the library \"%s\" >= file size: %" PRId64 " >= %" PRId64,
1253 name, file_offset, file_stat.st_size);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001254 return false;
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001255 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001256
1257 // Check for symlink and other situations where
Dmitriy Ivanov9b821362015-04-02 16:03:56 -07001258 // file can have different names, unless ANDROID_DLEXT_FORCE_LOAD is set
1259 if (extinfo == nullptr || (extinfo->flags & ANDROID_DLEXT_FORCE_LOAD) == 0) {
Dimitry Ivanovd3e7d082017-03-27 14:11:02 -07001260 soinfo* si = nullptr;
1261 if (find_loaded_library_by_inode(ns, file_stat, file_offset, search_linked_namespaces, &si)) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001262 TRACE("library \"%s\" is already loaded under different name/path \"%s\" - "
1263 "will return existing soinfo", name, si->get_realpath());
1264 task->set_soinfo(si);
1265 return true;
1266 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001267 }
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07001268
Dmitriy Ivanove8ba50f2014-09-15 17:00:10 -07001269 if ((rtld_flags & RTLD_NOLOAD) != 0) {
Dmitriy Ivanova6ac54a2014-09-09 10:21:42 -07001270 DL_ERR("library \"%s\" wasn't loaded and RTLD_NOLOAD prevented it", name);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001271 return false;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001272 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001273
Dimitry Ivanovbf34ba32017-04-21 13:12:05 -07001274 struct statfs fs_stat;
1275 if (TEMP_FAILURE_RETRY(fstatfs(task->get_fd(), &fs_stat)) != 0) {
1276 DL_ERR("unable to fstatfs file for the library \"%s\": %s", name, strerror(errno));
1277 return false;
1278 }
1279
1280 // do not check accessibility using realpath if fd is located on tmpfs
1281 // this enables use of memfd_create() for apps
1282 if ((fs_stat.f_type != TMPFS_MAGIC) && (!ns->is_accessible(realpath))) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001283 // TODO(dimitry): workaround for http://b/26394120 - the grey-list
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001284
1285 // TODO(dimitry) before O release: add a namespace attribute to have this enabled
1286 // only for classloader-namespaces
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001287 const soinfo* needed_by = task->is_dt_needed() ? task->get_needed_by() : nullptr;
Dimitry Ivanov35c8e3b2017-02-27 12:17:47 -08001288 if (is_greylisted(ns, name, needed_by)) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001289 // print warning only if needed by non-system library
1290 if (needed_by == nullptr || !is_system_library(needed_by->get_realpath())) {
1291 const soinfo* needed_or_dlopened_by = task->get_needed_by();
1292 const char* sopath = needed_or_dlopened_by == nullptr ? "(unknown)" :
1293 needed_or_dlopened_by->get_realpath();
1294 DL_WARN("library \"%s\" (\"%s\") needed or dlopened by \"%s\" is not accessible for the namespace \"%s\""
1295 " - the access is temporarily granted as a workaround for http://b/26394120, note that the access"
1296 " will be removed in future releases of Android.",
1297 name, realpath.c_str(), sopath, ns->get_name());
1298 add_dlwarning(sopath, "unauthorized access to", name);
1299 }
1300 } else {
1301 // do not load libraries if they are not accessible for the specified namespace.
1302 const char* needed_or_dlopened_by = task->get_needed_by() == nullptr ?
1303 "(unknown)" :
1304 task->get_needed_by()->get_realpath();
Dimitry Ivanovd17a3772016-03-01 13:11:28 -08001305
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001306 DL_ERR("library \"%s\" needed or dlopened by \"%s\" is not accessible for the namespace \"%s\"",
1307 name, needed_or_dlopened_by, ns->get_name());
Dimitry Ivanovd17a3772016-03-01 13:11:28 -08001308
Dimitry Ivanov35c8e3b2017-02-27 12:17:47 -08001309 // do not print this if a library is in the list of shared libraries for linked namespaces
1310 if (!maybe_accessible_via_namespace_links(ns, name)) {
1311 PRINT("library \"%s\" (\"%s\") needed or dlopened by \"%s\" is not accessible for the"
1312 " namespace: [name=\"%s\", ld_library_paths=\"%s\", default_library_paths=\"%s\","
1313 " permitted_paths=\"%s\"]",
1314 name, realpath.c_str(),
1315 needed_or_dlopened_by,
1316 ns->get_name(),
1317 android::base::Join(ns->get_ld_library_paths(), ':').c_str(),
1318 android::base::Join(ns->get_default_library_paths(), ':').c_str(),
1319 android::base::Join(ns->get_permitted_paths(), ':').c_str());
1320 }
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001321 return false;
1322 }
Dimitry Ivanov22840aa2015-12-04 18:28:49 -08001323 }
1324
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001325 soinfo* si = soinfo_alloc(ns, realpath.c_str(), &file_stat, file_offset, rtld_flags);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001326 if (si == nullptr) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001327 return false;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001328 }
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07001329
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001330 task->set_soinfo(si);
1331
1332 // Read the ELF header and some of the segments.
1333 if (!task->read(realpath.c_str(), file_stat.st_size)) {
Dmitriy Ivanovfd7a91e2015-11-06 10:44:37 -08001334 soinfo_free(si);
1335 task->set_soinfo(nullptr);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001336 return false;
1337 }
1338
1339 // find and set DT_RUNPATH and dt_soname
1340 // Note that these field values are temporary and are
1341 // going to be overwritten on soinfo::prelink_image
1342 // with values from PT_LOAD segments.
1343 const ElfReader& elf_reader = task->get_elf_reader();
1344 for (const ElfW(Dyn)* d = elf_reader.dynamic(); d->d_tag != DT_NULL; ++d) {
1345 if (d->d_tag == DT_RUNPATH) {
1346 si->set_dt_runpath(elf_reader.get_string(d->d_un.d_val));
1347 }
1348 if (d->d_tag == DT_SONAME) {
1349 si->set_soname(elf_reader.get_string(d->d_un.d_val));
1350 }
1351 }
1352
1353 for_each_dt_needed(task->get_elf_reader(), [&](const char* name) {
1354 load_tasks->push_back(LoadTask::create(name, si, task->get_readers_map()));
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001355 });
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07001356
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001357 return true;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001358}
1359
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001360static bool load_library(android_namespace_t* ns,
1361 LoadTask* task,
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001362 ZipArchiveCache* zip_archive_cache,
1363 LoadTaskList* load_tasks,
Dimitry Ivanovd3e7d082017-03-27 14:11:02 -07001364 int rtld_flags,
1365 bool search_linked_namespaces) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001366 const char* name = task->get_name();
1367 soinfo* needed_by = task->get_needed_by();
1368 const android_dlextinfo* extinfo = task->get_extinfo();
1369
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001370 off64_t file_offset;
1371 std::string realpath;
Spencer Low0346ad72015-04-22 18:06:51 -07001372 if (extinfo != nullptr && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) {
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001373 file_offset = 0;
Spencer Low0346ad72015-04-22 18:06:51 -07001374 if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
1375 file_offset = extinfo->library_fd_offset;
1376 }
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001377
1378 if (!realpath_fd(extinfo->library_fd, &realpath)) {
1379 PRINT("warning: unable to get realpath for the library \"%s\" by extinfo->library_fd. "
1380 "Will use given name.", name);
1381 realpath = name;
1382 }
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001383
1384 task->set_fd(extinfo->library_fd, false);
1385 task->set_file_offset(file_offset);
Dimitry Ivanovd3e7d082017-03-27 14:11:02 -07001386 return load_library(ns, task, load_tasks, rtld_flags, realpath, search_linked_namespaces);
Spencer Low0346ad72015-04-22 18:06:51 -07001387 }
1388
1389 // Open the file.
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001390 int fd = open_library(ns, zip_archive_cache, name, needed_by, &file_offset, &realpath);
Spencer Low0346ad72015-04-22 18:06:51 -07001391 if (fd == -1) {
1392 DL_ERR("library \"%s\" not found", name);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001393 return false;
Spencer Low0346ad72015-04-22 18:06:51 -07001394 }
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001395
1396 task->set_fd(fd, true);
1397 task->set_file_offset(file_offset);
1398
Dimitry Ivanovd3e7d082017-03-27 14:11:02 -07001399 return load_library(ns, task, load_tasks, rtld_flags, realpath, search_linked_namespaces);
Spencer Low0346ad72015-04-22 18:06:51 -07001400}
1401
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001402static bool find_loaded_library_by_soname(android_namespace_t* ns,
Dimitry Ivanovd3e7d082017-03-27 14:11:02 -07001403 const char* name,
1404 soinfo** candidate) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001405 return !ns->soinfo_list().visit([&](soinfo* si) {
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07001406 const char* soname = si->get_soname();
1407 if (soname != nullptr && (strcmp(name, soname) == 0)) {
Dimitry Ivanov3bd90612017-02-01 08:54:43 -08001408 *candidate = si;
1409 return false;
Ard Biesheuvel12c78bb2012-08-14 12:30:09 +02001410 }
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001411
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001412 return true;
1413 });
Ard Biesheuvel12c78bb2012-08-14 12:30:09 +02001414}
1415
Dimitry Ivanovd3e7d082017-03-27 14:11:02 -07001416// Returns true if library was found and false otherwise
1417static bool find_loaded_library_by_soname(android_namespace_t* ns,
1418 const char* name,
1419 bool search_linked_namespaces,
1420 soinfo** candidate) {
1421 *candidate = nullptr;
1422
1423 // Ignore filename with path.
1424 if (strchr(name, '/') != nullptr) {
1425 return false;
1426 }
1427
1428 bool found = find_loaded_library_by_soname(ns, name, candidate);
1429
1430 if (!found && search_linked_namespaces) {
1431 // if a library was not found - look into linked namespaces
1432 for (auto& link : ns->linked_namespaces()) {
1433 if (!link.is_accessible(name)) {
1434 continue;
1435 }
1436
1437 android_namespace_t* linked_ns = link.linked_namespace();
1438
1439 if (find_loaded_library_by_soname(linked_ns, name, candidate)) {
1440 return true;
1441 }
1442 }
1443 }
1444
1445 return found;
1446}
1447
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001448static bool find_library_in_linked_namespace(const android_namespace_link_t& namespace_link,
1449 LoadTask* task,
1450 int rtld_flags) {
1451 android_namespace_t* ns = namespace_link.linked_namespace();
1452
1453 soinfo* candidate;
1454 bool loaded = false;
1455
1456 std::string soname;
Dimitry Ivanovd3e7d082017-03-27 14:11:02 -07001457 if (find_loaded_library_by_soname(ns, task->get_name(), false, &candidate)) {
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001458 loaded = true;
1459 soname = candidate->get_soname();
1460 } else {
1461 soname = resolve_soname(task->get_name());
1462 }
1463
1464 if (!namespace_link.is_accessible(soname.c_str())) {
1465 // the library is not accessible via namespace_link
1466 return false;
1467 }
1468
1469 // if library is already loaded - return it
1470 if (loaded) {
1471 task->set_soinfo(candidate);
1472 return true;
1473 }
1474
1475 // try to load the library - once namespace boundary is crossed
1476 // we need to load a library within separate load_group
1477 // to avoid using symbols from foreign namespace while.
1478 //
1479 // All symbols during relocation should be resolved within a
1480 // namespace to preserve library locality to a namespace.
1481 const char* name = task->get_name();
1482 if (find_libraries(ns,
1483 task->get_needed_by(),
1484 &name,
1485 1,
1486 &candidate,
1487 nullptr /* ld_preloads */,
1488 0 /* ld_preload_count*/,
1489 rtld_flags,
1490 nullptr /* extinfo*/,
1491 false /* add_as_children */,
1492 false /* search_linked_namespaces */)) {
1493 task->set_soinfo(candidate);
1494 return true;
1495 }
1496
1497 return false;
1498}
1499
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001500static bool find_library_internal(android_namespace_t* ns,
1501 LoadTask* task,
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001502 ZipArchiveCache* zip_archive_cache,
1503 LoadTaskList* load_tasks,
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001504 int rtld_flags,
1505 bool search_linked_namespaces) {
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001506 soinfo* candidate;
1507
Dimitry Ivanovd3e7d082017-03-27 14:11:02 -07001508 if (find_loaded_library_by_soname(ns, task->get_name(), search_linked_namespaces, &candidate)) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001509 task->set_soinfo(candidate);
1510 return true;
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001511 }
Dmitriy Ivanovb648a8a2014-05-19 15:06:58 -07001512
1513 // Library might still be loaded, the accurate detection
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001514 // of this fact is done by load_library.
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001515 TRACE("[ \"%s\" find_loaded_library_by_soname failed (*candidate=%s@%p). Trying harder...]",
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001516 task->get_name(), candidate == nullptr ? "n/a" : candidate->get_realpath(), candidate);
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001517
Dimitry Ivanovd3e7d082017-03-27 14:11:02 -07001518 if (load_library(ns, task, zip_archive_cache, load_tasks, rtld_flags, search_linked_namespaces)) {
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001519 return true;
1520 }
1521
1522 if (search_linked_namespaces) {
1523 // if a library was not found - look into linked namespaces
1524 for (auto& linked_namespace : ns->linked_namespaces()) {
1525 if (find_library_in_linked_namespace(linked_namespace,
1526 task,
1527 rtld_flags)) {
1528 return true;
1529 }
1530 }
1531 }
1532
1533 return false;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001534}
1535
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001536static void soinfo_unload(soinfo* si);
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001537static void soinfo_unload(soinfo* soinfos[], size_t count);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001538
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001539// TODO: this is slightly unusual way to construct
1540// the global group for relocation. Not every RTLD_GLOBAL
1541// library is included in this group for backwards-compatibility
1542// reasons.
1543//
1544// This group consists of the main executable, LD_PRELOADs
1545// and libraries with the DF_1_GLOBAL flag set.
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001546static soinfo_list_t make_global_group(android_namespace_t* ns) {
1547 soinfo_list_t global_group;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001548 ns->soinfo_list().for_each([&](soinfo* si) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001549 if ((si->get_dt_flags_1() & DF_1_GLOBAL) != 0) {
1550 global_group.push_back(si);
1551 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001552 });
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001553
1554 return global_group;
1555}
1556
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07001557// This function provides a list of libraries to be shared
1558// by the namespace. For the default namespace this is the global
1559// group (see make_global_group). For all others this is a group
1560// of RTLD_GLOBAL libraries (which includes the global group from
1561// the default namespace).
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001562static soinfo_list_t get_shared_group(android_namespace_t* ns) {
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07001563 if (ns == &g_default_namespace) {
1564 return make_global_group(ns);
1565 }
1566
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001567 soinfo_list_t shared_group;
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07001568 ns->soinfo_list().for_each([&](soinfo* si) {
1569 if ((si->get_rtld_flags() & RTLD_GLOBAL) != 0) {
1570 shared_group.push_back(si);
1571 }
1572 });
1573
1574 return shared_group;
1575}
1576
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001577static void shuffle(std::vector<LoadTask*>* v) {
1578 for (size_t i = 0, size = v->size(); i < size; ++i) {
1579 size_t n = size - i;
1580 size_t r = arc4random_uniform(n);
1581 std::swap((*v)[n-1], (*v)[r]);
1582 }
1583}
1584
Evgenii Stepanov0cdef7e2015-07-06 17:56:31 -07001585// add_as_children - add first-level loaded libraries (i.e. library_names[], but
1586// not their transitive dependencies) as children of the start_with library.
1587// This is false when find_libraries is called for dlopen(), when newly loaded
1588// libraries must form a disjoint tree.
Dimitry Ivanov3f660572016-09-09 10:00:39 -07001589bool find_libraries(android_namespace_t* ns,
1590 soinfo* start_with,
1591 const char* const library_names[],
1592 size_t library_names_count,
1593 soinfo* soinfos[],
1594 std::vector<soinfo*>* ld_preloads,
1595 size_t ld_preloads_count,
1596 int rtld_flags,
1597 const android_dlextinfo* extinfo,
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001598 bool add_as_children,
1599 bool search_linked_namespaces) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001600 // Step 0: prepare.
1601 LoadTaskList load_tasks;
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001602 std::unordered_map<const soinfo*, ElfReader> readers_map;
1603
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001604 for (size_t i = 0; i < library_names_count; ++i) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001605 const char* name = library_names[i];
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001606 load_tasks.push_back(LoadTask::create(name, start_with, &readers_map));
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001607 }
1608
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001609 // Construct global_group.
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001610 soinfo_list_t global_group = make_global_group(ns);
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001611
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001612 // If soinfos array is null allocate one on stack.
1613 // The array is needed in case of failure; for example
1614 // when library_names[] = {libone.so, libtwo.so} and libone.so
1615 // is loaded correctly but libtwo.so failed for some reason.
1616 // In this case libone.so should be unloaded on return.
1617 // See also implementation of failure_guard below.
1618
1619 if (soinfos == nullptr) {
1620 size_t soinfos_size = sizeof(soinfo*)*library_names_count;
1621 soinfos = reinterpret_cast<soinfo**>(alloca(soinfos_size));
1622 memset(soinfos, 0, soinfos_size);
1623 }
1624
1625 // list of libraries to link - see step 2.
1626 size_t soinfos_count = 0;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001627
Tom Cherryb8ab6182017-04-05 16:20:29 -07001628 auto scope_guard = android::base::make_scope_guard([&]() {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001629 for (LoadTask* t : load_tasks) {
1630 LoadTask::deleter(t);
1631 }
1632 });
1633
Tom Cherryb8ab6182017-04-05 16:20:29 -07001634 auto failure_guard = android::base::make_scope_guard([&]() {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001635 // Housekeeping
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001636 soinfo_unload(soinfos, soinfos_count);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001637 });
1638
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001639 ZipArchiveCache zip_archive_cache;
1640
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001641 // Step 1: expand the list of load_tasks to include
1642 // all DT_NEEDED libraries (do not load them just yet)
1643 for (size_t i = 0; i<load_tasks.size(); ++i) {
1644 LoadTask* task = load_tasks[i];
Evgenii Stepanov68650822015-06-10 13:38:39 -07001645 soinfo* needed_by = task->get_needed_by();
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001646
Dmitriy Ivanovedfc9f62015-09-02 16:32:02 -07001647 bool is_dt_needed = needed_by != nullptr && (needed_by != start_with || add_as_children);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001648 task->set_extinfo(is_dt_needed ? nullptr : extinfo);
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001649 task->set_dt_needed(is_dt_needed);
Dmitriy Ivanovedfc9f62015-09-02 16:32:02 -07001650
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001651 if (!find_library_internal(ns,
1652 task,
1653 &zip_archive_cache,
1654 &load_tasks,
1655 rtld_flags,
1656 search_linked_namespaces || is_dt_needed)) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001657 return false;
1658 }
1659
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001660 soinfo* si = task->get_soinfo();
1661
Dmitriy Ivanovedfc9f62015-09-02 16:32:02 -07001662 if (is_dt_needed) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001663 needed_by->add_child(si);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001664
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001665 if (si->is_linked()) {
1666 si->increment_ref_count();
1667 }
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001668 }
1669
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001670 // When ld_preloads is not null, the first
1671 // ld_preloads_count libs are in fact ld_preloads.
1672 if (ld_preloads != nullptr && soinfos_count < ld_preloads_count) {
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07001673 ld_preloads->push_back(si);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001674 }
1675
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001676 if (soinfos_count < library_names_count) {
1677 soinfos[soinfos_count++] = si;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001678 }
1679 }
1680
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001681 // Step 2: Load libraries in random order (see b/24047022)
1682 LoadTaskList load_list;
1683 for (auto&& task : load_tasks) {
1684 soinfo* si = task->get_soinfo();
1685 auto pred = [&](const LoadTask* t) {
1686 return t->get_soinfo() == si;
1687 };
1688
1689 if (!si->is_linked() &&
1690 std::find_if(load_list.begin(), load_list.end(), pred) == load_list.end() ) {
1691 load_list.push_back(task);
1692 }
1693 }
1694 shuffle(&load_list);
1695
1696 for (auto&& task : load_list) {
1697 if (!task->load()) {
1698 return false;
1699 }
1700 }
1701
1702 // Step 3: pre-link all DT_NEEDED libraries in breadth first order.
1703 for (auto&& task : load_tasks) {
1704 soinfo* si = task->get_soinfo();
1705 if (!si->is_linked() && !si->prelink_image()) {
1706 return false;
1707 }
1708 }
1709
1710 // Step 4: Add LD_PRELOADed libraries to the global group for
1711 // future runs. There is no need to explicitly add them to
1712 // the global group for this run because they are going to
1713 // appear in the local group in the correct order.
1714 if (ld_preloads != nullptr) {
1715 for (auto&& si : *ld_preloads) {
1716 si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL);
1717 }
1718 }
1719
1720
1721 // Step 5: link libraries.
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001722 soinfo_list_t local_group;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001723 walk_dependencies_tree(
Evgenii Stepanov0cdef7e2015-07-06 17:56:31 -07001724 (start_with != nullptr && add_as_children) ? &start_with : soinfos,
1725 (start_with != nullptr && add_as_children) ? 1 : soinfos_count,
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001726 [&] (soinfo* si) {
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -08001727 if (ns->is_accessible(si)) {
1728 local_group.push_back(si);
1729 return kWalkContinue;
1730 } else {
1731 return kWalkSkip;
1732 }
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001733 });
1734
1735 bool linked = local_group.visit([&](soinfo* si) {
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001736 if (!si->is_linked()) {
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -07001737 if (!si->link_image(global_group, local_group, extinfo) ||
1738 !get_cfi_shadow()->AfterLoad(si, solist_get_head())) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001739 return false;
1740 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001741 }
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001742
1743 return true;
1744 });
1745
1746 if (linked) {
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001747 local_group.for_each([](soinfo* si) {
1748 if (!si->is_linked()) {
1749 si->set_linked();
1750 }
1751 });
1752
Tom Cherryb8ab6182017-04-05 16:20:29 -07001753 failure_guard.Disable();
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001754 }
1755
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001756 return linked;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001757}
1758
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001759static soinfo* find_library(android_namespace_t* ns,
1760 const char* name, int rtld_flags,
Evgenii Stepanov0cdef7e2015-07-06 17:56:31 -07001761 const android_dlextinfo* extinfo,
1762 soinfo* needed_by) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001763 soinfo* si;
1764
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001765 if (name == nullptr) {
Dimitry Ivanov3f660572016-09-09 10:00:39 -07001766 si = solist_get_somain();
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001767 } else if (!find_libraries(ns,
1768 needed_by,
1769 &name,
1770 1,
1771 &si,
1772 nullptr,
1773 0,
1774 rtld_flags,
1775 extinfo,
1776 false /* add_as_children */,
1777 true /* search_linked_namespaces */)) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001778 return nullptr;
1779 }
1780
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001781 si->increment_ref_count();
1782
Elliott Hughesd23736e2012-11-01 15:16:56 -07001783 return si;
1784}
Elliott Hughesbedfe382012-08-14 14:07:59 -07001785
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001786static void soinfo_unload(soinfo* root) {
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001787 if (root->is_linked()) {
1788 root = root->get_local_group_root();
1789 }
1790
Dimitry Ivanov6705e8c2017-03-21 10:29:06 -07001791 ScopedTrace trace((std::string("unload ") + root->get_realpath()).c_str());
1792
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001793 if (!root->can_unload()) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001794 TRACE("not unloading \"%s\" - the binary is flagged with NODELETE", root->get_realpath());
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -07001795 return;
1796 }
1797
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001798 soinfo_unload(&root, 1);
1799}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001800
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001801static void soinfo_unload(soinfo* soinfos[], size_t count) {
1802 // Note that the library can be loaded but not linked;
1803 // in which case there is no root but we still need
1804 // to walk the tree and unload soinfos involved.
1805 //
1806 // This happens on unsuccessful dlopen, when one of
1807 // the DT_NEEDED libraries could not be linked/found.
1808 if (count == 0) {
1809 return;
1810 }
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001811
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001812 soinfo_list_t unload_list;
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001813 for (size_t i = 0; i < count; ++i) {
1814 soinfo* si = soinfos[i];
Dmitriy Ivanov5ae82cb2014-12-02 17:08:42 -08001815
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001816 if (si->can_unload()) {
1817 size_t ref_count = si->is_linked() ? si->decrement_ref_count() : 0;
1818 if (ref_count == 0) {
1819 unload_list.push_back(si);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001820 } else {
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001821 TRACE("not unloading '%s' group, decrementing ref_count to %zd",
1822 si->get_realpath(), ref_count);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001823 }
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001824 } else {
1825 TRACE("not unloading '%s' - the binary is flagged with NODELETE", si->get_realpath());
1826 return;
1827 }
1828 }
1829
1830 // This is used to identify soinfos outside of the load-group
1831 // note that we cannot have > 1 in the array and have any of them
1832 // linked. This is why we can safely use the first one.
1833 soinfo* root = soinfos[0];
1834
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001835 soinfo_list_t local_unload_list;
1836 soinfo_list_t external_unload_list;
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001837 soinfo* si = nullptr;
1838
1839 while ((si = unload_list.pop_front()) != nullptr) {
1840 if (local_unload_list.contains(si)) {
1841 continue;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001842 }
Elliott Hughesd23736e2012-11-01 15:16:56 -07001843
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001844 local_unload_list.push_back(si);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001845
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001846 if (si->has_min_version(0)) {
1847 soinfo* child = nullptr;
1848 while ((child = si->get_children().pop_front()) != nullptr) {
1849 TRACE("%s@%p needs to unload %s@%p", si->get_realpath(), si,
1850 child->get_realpath(), child);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001851
Dimitry Ivanovec90e242017-02-10 11:04:20 -08001852 child->get_parents().remove(si);
1853
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001854 if (local_unload_list.contains(child)) {
1855 continue;
1856 } else if (child->is_linked() && child->get_local_group_root() != root) {
1857 external_unload_list.push_back(child);
Dimitry Ivanovec90e242017-02-10 11:04:20 -08001858 } else if (child->get_parents().empty()) {
1859 unload_list.push_back(child);
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001860 }
1861 }
1862 } else {
1863#if !defined(__work_around_b_24465209__)
Christopher Ferris7a3681e2017-04-24 17:48:32 -07001864 async_safe_fatal("soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001865#else
1866 PRINT("warning: soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
1867 for_each_dt_needed(si, [&] (const char* library_name) {
1868 TRACE("deprecated (old format of soinfo): %s needs to unload %s",
1869 si->get_realpath(), library_name);
1870
1871 soinfo* needed = find_library(si->get_primary_namespace(),
1872 library_name, RTLD_NOLOAD, nullptr, nullptr);
1873
1874 if (needed != nullptr) {
1875 // Not found: for example if symlink was deleted between dlopen and dlclose
1876 // Since we cannot really handle errors at this point - print and continue.
1877 PRINT("warning: couldn't find %s needed by %s on unload.",
1878 library_name, si->get_realpath());
1879 return;
1880 } else if (local_unload_list.contains(needed)) {
1881 // already visited
1882 return;
1883 } else if (needed->is_linked() && needed->get_local_group_root() != root) {
1884 // external group
1885 external_unload_list.push_back(needed);
1886 } else {
1887 // local group
1888 unload_list.push_front(needed);
1889 }
1890 });
1891#endif
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001892 }
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001893 }
1894
1895 local_unload_list.for_each([](soinfo* si) {
1896 si->call_destructors();
1897 });
1898
1899 while ((si = local_unload_list.pop_front()) != nullptr) {
1900 notify_gdb_of_unload(si);
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -07001901 get_cfi_shadow()->BeforeUnload(si);
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001902 soinfo_free(si);
1903 }
1904
1905 while ((si = external_unload_list.pop_front()) != nullptr) {
1906 soinfo_unload(si);
Dmitriy Ivanova2547052014-11-18 12:03:09 -08001907 }
1908}
1909
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001910static std::string symbol_display_name(const char* sym_name, const char* sym_ver) {
1911 if (sym_ver == nullptr) {
1912 return sym_name;
1913 }
1914
Dimitry Ivanov9cf99cb2015-12-11 14:22:24 -08001915 return std::string(sym_name) + ", version " + sym_ver;
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001916}
1917
Dimitry Ivanovaca299a2016-04-11 12:42:58 -07001918static android_namespace_t* get_caller_namespace(soinfo* caller) {
1919 return caller != nullptr ? caller->get_primary_namespace() : g_anonymous_namespace;
1920}
1921
Elliott Hughesa4aafd12014-01-13 16:37:47 -08001922void do_android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size) {
Christopher Ferris052fa3a2014-08-26 20:48:11 -07001923 // Use basic string manipulation calls to avoid snprintf.
1924 // snprintf indirectly calls pthread_getspecific to get the size of a buffer.
1925 // When debug malloc is enabled, this call returns 0. This in turn causes
1926 // snprintf to do nothing, which causes libraries to fail to load.
1927 // See b/17302493 for further details.
1928 // Once the above bug is fixed, this code can be modified to use
1929 // snprintf again.
Dimitry Ivanov77ad6422017-03-06 13:02:29 -08001930 const auto& default_ld_paths = g_default_namespace.get_default_library_paths();
1931
1932 size_t required_size = 0;
1933 for (const auto& path : default_ld_paths) {
1934 required_size += path.size() + 1;
Evgenii Stepanovd640b222015-07-10 17:54:01 -07001935 }
Dimitry Ivanov77ad6422017-03-06 13:02:29 -08001936
1937 if (buffer_size < required_size) {
Christopher Ferris7a3681e2017-04-24 17:48:32 -07001938 async_safe_fatal("android_get_LD_LIBRARY_PATH failed, buffer too small: "
1939 "buffer len %zu, required len %zu", buffer_size, required_size);
Christopher Ferris052fa3a2014-08-26 20:48:11 -07001940 }
Dimitry Ivanov77ad6422017-03-06 13:02:29 -08001941
Evgenii Stepanovd640b222015-07-10 17:54:01 -07001942 char* end = buffer;
Dimitry Ivanov77ad6422017-03-06 13:02:29 -08001943 for (size_t i = 0; i < default_ld_paths.size(); ++i) {
Evgenii Stepanovd640b222015-07-10 17:54:01 -07001944 if (i > 0) *end++ = ':';
Dimitry Ivanov77ad6422017-03-06 13:02:29 -08001945 end = stpcpy(end, default_ld_paths[i].c_str());
Evgenii Stepanovd640b222015-07-10 17:54:01 -07001946 }
Elliott Hughesa4aafd12014-01-13 16:37:47 -08001947}
1948
Elliott Hughescade4c32012-12-20 14:42:14 -08001949void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path) {
Nick Kralevich6bb01b62015-03-07 13:37:05 -08001950 parse_LD_LIBRARY_PATH(ld_library_path);
Elliott Hughescade4c32012-12-20 14:42:14 -08001951}
1952
Dimitry Ivanovb996d602016-07-11 18:11:39 -07001953static std::string android_dlextinfo_to_string(const android_dlextinfo* info) {
1954 if (info == nullptr) {
1955 return "(null)";
1956 }
1957
1958 return android::base::StringPrintf("[flags=0x%" PRIx64 ","
1959 " reserved_addr=%p,"
1960 " reserved_size=0x%zx,"
1961 " relro_fd=%d,"
1962 " library_fd=%d,"
1963 " library_fd_offset=0x%" PRIx64 ","
1964 " library_namespace=%s@%p]",
1965 info->flags,
1966 info->reserved_addr,
1967 info->reserved_size,
1968 info->relro_fd,
1969 info->library_fd,
1970 info->library_fd_offset,
1971 (info->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0 ?
1972 (info->library_namespace != nullptr ?
1973 info->library_namespace->get_name() : "(null)") : "(n/a)",
1974 (info->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0 ?
1975 info->library_namespace : nullptr);
1976}
1977
Dimitry Ivanovd9e427c2016-11-22 16:55:25 -08001978void* do_dlopen(const char* name, int flags,
1979 const android_dlextinfo* extinfo,
1980 const void* caller_addr) {
Dimitry Ivanov5c4a5802017-03-17 16:41:34 -07001981 std::string trace_prefix = std::string("dlopen: ") + (name == nullptr ? "(nullptr)" : name);
1982 ScopedTrace trace(trace_prefix.c_str());
1983 ScopedTrace loading_trace((trace_prefix + " - loading and linking").c_str());
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001984 soinfo* const caller = find_containing_library(caller_addr);
Dimitry Ivanovb996d602016-07-11 18:11:39 -07001985 android_namespace_t* ns = get_caller_namespace(caller);
1986
1987 LD_LOG(kLogDlopen,
1988 "dlopen(name=\"%s\", flags=0x%x, extinfo=%s, caller=\"%s\", caller_ns=%s@%p) ...",
1989 name,
1990 flags,
1991 android_dlextinfo_to_string(extinfo).c_str(),
1992 caller == nullptr ? "(null)" : caller->get_realpath(),
1993 ns == nullptr ? "(null)" : ns->get_name(),
1994 ns);
1995
Tom Cherryb8ab6182017-04-05 16:20:29 -07001996 auto failure_guard = android::base::make_scope_guard(
1997 [&]() { LD_LOG(kLogDlopen, "... dlopen failed: %s", linker_get_error_buffer()); });
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001998
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -07001999 if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL|RTLD_NODELETE|RTLD_NOLOAD)) != 0) {
Elliott Hughese66190d2012-12-18 15:57:55 -08002000 DL_ERR("invalid flags to dlopen: %x", flags);
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07002001 return nullptr;
Elliott Hughese66190d2012-12-18 15:57:55 -08002002 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002003
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07002004 if (extinfo != nullptr) {
2005 if ((extinfo->flags & ~(ANDROID_DLEXT_VALID_FLAG_BITS)) != 0) {
2006 DL_ERR("invalid extended flags to android_dlopen_ext: 0x%" PRIx64, extinfo->flags);
2007 return nullptr;
2008 }
Dmitriy Ivanov126af752015-10-07 16:34:20 -07002009
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07002010 if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) == 0 &&
Dmitriy Ivanova6c12792014-10-21 12:09:18 -07002011 (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002012 DL_ERR("invalid extended flag combination (ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET without "
2013 "ANDROID_DLEXT_USE_LIBRARY_FD): 0x%" PRIx64, extinfo->flags);
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07002014 return nullptr;
2015 }
Dmitriy Ivanov126af752015-10-07 16:34:20 -07002016
2017 if ((extinfo->flags & ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS) != 0 &&
2018 (extinfo->flags & (ANDROID_DLEXT_RESERVED_ADDRESS | ANDROID_DLEXT_RESERVED_ADDRESS_HINT)) != 0) {
2019 DL_ERR("invalid extended flag combination: ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS is not "
2020 "compatible with ANDROID_DLEXT_RESERVED_ADDRESS/ANDROID_DLEXT_RESERVED_ADDRESS_HINT");
2021 return nullptr;
2022 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002023
2024 if ((extinfo->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0) {
2025 if (extinfo->library_namespace == nullptr) {
2026 DL_ERR("ANDROID_DLEXT_USE_NAMESPACE is set but extinfo->library_namespace is null");
2027 return nullptr;
2028 }
2029 ns = extinfo->library_namespace;
2030 }
Torne (Richard Coles)012cb452014-02-06 14:34:21 +00002031 }
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -08002032
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -07002033 std::string asan_name_holder;
2034
2035 const char* translated_name = name;
Dimitry Ivanov6c14f862016-12-05 13:35:47 -08002036 if (g_is_asan && translated_name != nullptr && translated_name[0] == '/') {
2037 char translated_path[PATH_MAX];
2038 if (realpath(translated_name, translated_path) != nullptr) {
Vishwath Mohan4113def2017-03-29 15:31:34 -07002039 asan_name_holder = std::string(kAsanLibDirPrefix) + translated_path;
2040 if (file_exists(asan_name_holder.c_str())) {
2041 translated_name = asan_name_holder.c_str();
2042 PRINT("linker_asan dlopen translating \"%s\" -> \"%s\"", name, translated_name);
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -07002043 }
2044 }
2045 }
2046
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -08002047 ProtectedDataGuard guard;
Adrian DCc6927502017-04-08 22:40:01 +02002048 reset_g_active_shim_libs();
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -07002049 soinfo* si = find_library(ns, translated_name, flags, extinfo, caller);
Dimitry Ivanov5c4a5802017-03-17 16:41:34 -07002050 loading_trace.End();
2051
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07002052 if (si != nullptr) {
Dimitry Ivanovb996d602016-07-11 18:11:39 -07002053 void* handle = si->to_handle();
2054 LD_LOG(kLogDlopen,
Dimitry Ivanovae4a0c12016-11-21 10:44:35 -08002055 "... dlopen calling constructors: realpath=\"%s\", soname=\"%s\", handle=%p",
2056 si->get_realpath(), si->get_soname(), handle);
2057 si->call_constructors();
Tom Cherryb8ab6182017-04-05 16:20:29 -07002058 failure_guard.Disable();
Dimitry Ivanovae4a0c12016-11-21 10:44:35 -08002059 LD_LOG(kLogDlopen,
Dimitry Ivanovb996d602016-07-11 18:11:39 -07002060 "... dlopen successful: realpath=\"%s\", soname=\"%s\", handle=%p",
2061 si->get_realpath(), si->get_soname(), handle);
2062 return handle;
Elliott Hughesd23736e2012-11-01 15:16:56 -07002063 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002064
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07002065 return nullptr;
Elliott Hughesd23736e2012-11-01 15:16:56 -07002066}
2067
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08002068int do_dladdr(const void* addr, Dl_info* info) {
2069 // Determine if this address can be found in any library currently mapped.
2070 soinfo* si = find_containing_library(addr);
2071 if (si == nullptr) {
2072 return 0;
2073 }
2074
2075 memset(info, 0, sizeof(Dl_info));
2076
2077 info->dli_fname = si->get_realpath();
2078 // Address at which the shared object is loaded.
2079 info->dli_fbase = reinterpret_cast<void*>(si->base);
2080
2081 // Determine if any symbol in the library contains the specified address.
2082 ElfW(Sym)* sym = si->find_symbol_by_address(addr);
2083 if (sym != nullptr) {
2084 info->dli_sname = si->get_string(sym->st_name);
2085 info->dli_saddr = reinterpret_cast<void*>(si->resolve_symbol_address(sym));
2086 }
2087
2088 return 1;
2089}
2090
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07002091static soinfo* soinfo_from_handle(void* handle) {
2092 if ((reinterpret_cast<uintptr_t>(handle) & 1) != 0) {
2093 auto it = g_soinfo_handles_map.find(reinterpret_cast<uintptr_t>(handle));
2094 if (it == g_soinfo_handles_map.end()) {
2095 return nullptr;
2096 } else {
2097 return it->second;
2098 }
2099 }
2100
2101 return static_cast<soinfo*>(handle);
2102}
2103
Dimitry Ivanovd9e427c2016-11-22 16:55:25 -08002104bool do_dlsym(void* handle,
2105 const char* sym_name,
2106 const char* sym_ver,
2107 const void* caller_addr,
2108 void** symbol) {
Dimitry Ivanov6705e8c2017-03-21 10:29:06 -07002109 ScopedTrace trace("dlsym");
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08002110#if !defined(__LP64__)
2111 if (handle == nullptr) {
2112 DL_ERR("dlsym failed: library handle is null");
2113 return false;
2114 }
2115#endif
2116
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08002117 soinfo* found = nullptr;
2118 const ElfW(Sym)* sym = nullptr;
2119 soinfo* caller = find_containing_library(caller_addr);
Dimitry Ivanovaca299a2016-04-11 12:42:58 -07002120 android_namespace_t* ns = get_caller_namespace(caller);
Dimitry Ivanov4742abd2016-12-12 16:30:15 -08002121 soinfo* si = nullptr;
2122 if (handle != RTLD_DEFAULT && handle != RTLD_NEXT) {
2123 si = soinfo_from_handle(handle);
2124 }
2125
2126 LD_LOG(kLogDlsym,
2127 "dlsym(handle=%p(\"%s\"), sym_name=\"%s\", sym_ver=\"%s\", caller=\"%s\", caller_ns=%s@%p) ...",
2128 handle,
2129 si != nullptr ? si->get_realpath() : "n/a",
2130 sym_name,
2131 sym_ver,
2132 caller == nullptr ? "(null)" : caller->get_realpath(),
2133 ns == nullptr ? "(null)" : ns->get_name(),
2134 ns);
2135
Tom Cherryb8ab6182017-04-05 16:20:29 -07002136 auto failure_guard = android::base::make_scope_guard(
2137 [&]() { LD_LOG(kLogDlsym, "... dlsym failed: %s", linker_get_error_buffer()); });
Dimitry Ivanov4742abd2016-12-12 16:30:15 -08002138
2139 if (sym_name == nullptr) {
2140 DL_ERR("dlsym failed: symbol name is null");
2141 return false;
2142 }
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08002143
2144 version_info vi_instance;
2145 version_info* vi = nullptr;
2146
2147 if (sym_ver != nullptr) {
Dimitry Ivanov9cf99cb2015-12-11 14:22:24 -08002148 vi_instance.name = sym_ver;
2149 vi_instance.elf_hash = calculate_elf_hash(sym_ver);
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08002150 vi = &vi_instance;
2151 }
2152
2153 if (handle == RTLD_DEFAULT || handle == RTLD_NEXT) {
2154 sym = dlsym_linear_lookup(ns, sym_name, vi, &found, caller, handle);
2155 } else {
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07002156 if (si == nullptr) {
2157 DL_ERR("dlsym failed: invalid handle: %p", handle);
2158 return false;
2159 }
2160 sym = dlsym_handle_lookup(si, &found, sym_name, vi);
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08002161 }
2162
2163 if (sym != nullptr) {
2164 uint32_t bind = ELF_ST_BIND(sym->st_info);
2165
2166 if ((bind == STB_GLOBAL || bind == STB_WEAK) && sym->st_shndx != 0) {
2167 *symbol = reinterpret_cast<void*>(found->resolve_symbol_address(sym));
Tom Cherryb8ab6182017-04-05 16:20:29 -07002168 failure_guard.Disable();
Dimitry Ivanov4742abd2016-12-12 16:30:15 -08002169 LD_LOG(kLogDlsym,
2170 "... dlsym successful: sym_name=\"%s\", sym_ver=\"%s\", found in=\"%s\", address=%p",
2171 sym_name, sym_ver, found->get_soname(), *symbol);
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08002172 return true;
2173 }
2174
2175 DL_ERR("symbol \"%s\" found but not global", symbol_display_name(sym_name, sym_ver).c_str());
2176 return false;
2177 }
2178
2179 DL_ERR("undefined symbol: %s", symbol_display_name(sym_name, sym_ver).c_str());
2180 return false;
2181}
2182
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07002183int do_dlclose(void* handle) {
Dimitry Ivanov6705e8c2017-03-21 10:29:06 -07002184 ScopedTrace trace("dlclose");
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -08002185 ProtectedDataGuard guard;
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07002186 soinfo* si = soinfo_from_handle(handle);
2187 if (si == nullptr) {
2188 DL_ERR("invalid handle: %p", handle);
2189 return -1;
2190 }
2191
Dmitriy Ivanovb648a8a2014-05-19 15:06:58 -07002192 soinfo_unload(si);
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07002193 return 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002194}
2195
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -08002196bool init_anonymous_namespace(const char* shared_lib_sonames, const char* library_search_path) {
2197 if (g_anonymous_namespace_initialized) {
2198 DL_ERR("anonymous namespace has already been initialized.");
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002199 return false;
2200 }
2201
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002202 ProtectedDataGuard guard;
2203
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002204 // create anonymous namespace
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002205 // When the caller is nullptr - create_namespace will take global group
2206 // from the anonymous namespace, which is fine because anonymous namespace
2207 // is still pointing to the default one.
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002208 android_namespace_t* anon_ns =
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -08002209 create_namespace(nullptr,
2210 "(anonymous)",
2211 nullptr,
2212 library_search_path,
Dimitry Ivanovc9dced22017-03-27 15:42:17 -07002213 ANDROID_NAMESPACE_TYPE_ISOLATED,
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -08002214 nullptr,
2215 &g_default_namespace);
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002216
2217 if (anon_ns == nullptr) {
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -08002218 return false;
2219 }
2220
2221 if (!link_namespaces(anon_ns, &g_default_namespace, shared_lib_sonames)) {
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002222 return false;
2223 }
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08002224
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002225 g_anonymous_namespace = anon_ns;
Dimitry Ivanov3e0821d2017-03-07 11:02:10 -08002226 g_anonymous_namespace_initialized = true;
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -08002227
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002228 return true;
2229}
2230
Dimitry Ivanovb943f302016-08-03 16:00:10 -07002231static void add_soinfos_to_namespace(const soinfo_list_t& soinfos, android_namespace_t* ns) {
2232 ns->add_soinfos(soinfos);
2233 for (auto si : soinfos) {
2234 si->add_secondary_namespace(ns);
2235 }
2236}
2237
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002238android_namespace_t* create_namespace(const void* caller_addr,
2239 const char* name,
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002240 const char* ld_library_path,
2241 const char* default_library_path,
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002242 uint64_t type,
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002243 const char* permitted_when_isolated_path,
2244 android_namespace_t* parent_namespace) {
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002245 if (parent_namespace == nullptr) {
Dimitry Ivanov52408632016-05-23 10:31:11 -07002246 // if parent_namespace is nullptr -> set it to the caller namespace
2247 soinfo* caller_soinfo = find_containing_library(caller_addr);
2248
2249 parent_namespace = caller_soinfo != nullptr ?
2250 caller_soinfo->get_primary_namespace() :
2251 g_anonymous_namespace;
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002252 }
2253
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002254 ProtectedDataGuard guard;
2255 std::vector<std::string> ld_library_paths;
2256 std::vector<std::string> default_library_paths;
Dimitry Ivanov284ae352015-12-08 10:47:13 -08002257 std::vector<std::string> permitted_paths;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002258
2259 parse_path(ld_library_path, ":", &ld_library_paths);
2260 parse_path(default_library_path, ":", &default_library_paths);
Dimitry Ivanov284ae352015-12-08 10:47:13 -08002261 parse_path(permitted_when_isolated_path, ":", &permitted_paths);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002262
2263 android_namespace_t* ns = new (g_namespace_allocator.alloc()) android_namespace_t();
2264 ns->set_name(name);
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002265 ns->set_isolated((type & ANDROID_NAMESPACE_TYPE_ISOLATED) != 0);
Jiyong Park37b91af2017-05-05 22:07:05 +09002266 ns->set_greylist_enabled((type & ANDROID_NAMESPACE_TYPE_GREYLIST_ENABLED) != 0);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002267
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002268 if ((type & ANDROID_NAMESPACE_TYPE_SHARED) != 0) {
Dimitry Ivanovf1cb6692017-05-01 17:45:38 -07002269 // append parent namespace paths.
2270 std::copy(parent_namespace->get_ld_library_paths().begin(),
2271 parent_namespace->get_ld_library_paths().end(),
2272 back_inserter(ld_library_paths));
2273
2274 std::copy(parent_namespace->get_default_library_paths().begin(),
2275 parent_namespace->get_default_library_paths().end(),
2276 back_inserter(default_library_paths));
2277
2278 std::copy(parent_namespace->get_permitted_paths().begin(),
2279 parent_namespace->get_permitted_paths().end(),
2280 back_inserter(permitted_paths));
2281
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002282 // If shared - clone the parent namespace
Dimitry Ivanovb943f302016-08-03 16:00:10 -07002283 add_soinfos_to_namespace(parent_namespace->soinfo_list(), ns);
Dimitry Ivanovf1cb6692017-05-01 17:45:38 -07002284 // and copy parent namespace links
2285 for (auto& link : parent_namespace->linked_namespaces()) {
2286 ns->add_linked_namespace(link.linked_namespace(), link.shared_lib_sonames());
2287 }
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002288 } else {
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002289 // If not shared - copy only the shared group
Dimitry Ivanovb943f302016-08-03 16:00:10 -07002290 add_soinfos_to_namespace(get_shared_group(parent_namespace), ns);
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002291 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002292
Dimitry Ivanovf1cb6692017-05-01 17:45:38 -07002293 ns->set_ld_library_paths(std::move(ld_library_paths));
2294 ns->set_default_library_paths(std::move(default_library_paths));
2295 ns->set_permitted_paths(std::move(permitted_paths));
2296
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002297 return ns;
2298}
2299
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -08002300bool link_namespaces(android_namespace_t* namespace_from,
2301 android_namespace_t* namespace_to,
2302 const char* shared_lib_sonames) {
2303 if (namespace_to == nullptr) {
2304 namespace_to = &g_default_namespace;
2305 }
2306
2307 if (namespace_from == nullptr) {
2308 DL_ERR("error linking namespaces: namespace_from is null.");
2309 return false;
2310 }
2311
2312 if (shared_lib_sonames == nullptr || shared_lib_sonames[0] == '\0') {
2313 DL_ERR("error linking namespaces \"%s\"->\"%s\": the list of shared libraries is empty.",
2314 namespace_from->get_name(), namespace_to->get_name());
2315 return false;
2316 }
2317
2318 auto sonames = android::base::Split(shared_lib_sonames, ":");
2319 std::unordered_set<std::string> sonames_set(sonames.begin(), sonames.end());
2320
2321 ProtectedDataGuard guard;
2322 namespace_from->add_linked_namespace(namespace_to, sonames_set);
2323
2324 return true;
2325}
2326
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002327ElfW(Addr) call_ifunc_resolver(ElfW(Addr) resolver_addr) {
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07002328 typedef ElfW(Addr) (*ifunc_resolver_t)(void);
2329 ifunc_resolver_t ifunc_resolver = reinterpret_cast<ifunc_resolver_t>(resolver_addr);
2330 ElfW(Addr) ifunc_addr = ifunc_resolver();
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002331 TRACE_TYPE(RELO, "Called ifunc_resolver@%p. The result is %p",
2332 ifunc_resolver, reinterpret_cast<void*>(ifunc_addr));
Brigid Smithc5a13ef2014-07-23 11:22:25 -07002333
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07002334 return ifunc_addr;
Brigid Smithc5a13ef2014-07-23 11:22:25 -07002335}
Brigid Smithc5a13ef2014-07-23 11:22:25 -07002336
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002337const version_info* VersionTracker::get_version_info(ElfW(Versym) source_symver) const {
2338 if (source_symver < 2 ||
2339 source_symver >= version_infos.size() ||
2340 version_infos[source_symver].name == nullptr) {
2341 return nullptr;
2342 }
2343
2344 return &version_infos[source_symver];
2345}
2346
2347void VersionTracker::add_version_info(size_t source_index,
2348 ElfW(Word) elf_hash,
2349 const char* ver_name,
2350 const soinfo* target_si) {
2351 if (source_index >= version_infos.size()) {
2352 version_infos.resize(source_index+1);
2353 }
2354
2355 version_infos[source_index].elf_hash = elf_hash;
2356 version_infos[source_index].name = ver_name;
2357 version_infos[source_index].target_si = target_si;
2358}
2359
2360bool VersionTracker::init_verneed(const soinfo* si_from) {
2361 uintptr_t verneed_ptr = si_from->get_verneed_ptr();
2362
2363 if (verneed_ptr == 0) {
2364 return true;
2365 }
2366
2367 size_t verneed_cnt = si_from->get_verneed_cnt();
2368
2369 for (size_t i = 0, offset = 0; i<verneed_cnt; ++i) {
2370 const ElfW(Verneed)* verneed = reinterpret_cast<ElfW(Verneed)*>(verneed_ptr + offset);
2371 size_t vernaux_offset = offset + verneed->vn_aux;
2372 offset += verneed->vn_next;
2373
2374 if (verneed->vn_version != 1) {
2375 DL_ERR("unsupported verneed[%zd] vn_version: %d (expected 1)", i, verneed->vn_version);
2376 return false;
2377 }
2378
2379 const char* target_soname = si_from->get_string(verneed->vn_file);
2380 // find it in dependencies
2381 soinfo* target_si = si_from->get_children().find_if([&](const soinfo* si) {
Dmitriy Ivanov406d9962015-05-06 11:05:27 -07002382 return si->get_soname() != nullptr && strcmp(si->get_soname(), target_soname) == 0;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002383 });
2384
2385 if (target_si == nullptr) {
2386 DL_ERR("cannot find \"%s\" from verneed[%zd] in DT_NEEDED list for \"%s\"",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002387 target_soname, i, si_from->get_realpath());
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002388 return false;
2389 }
2390
2391 for (size_t j = 0; j<verneed->vn_cnt; ++j) {
2392 const ElfW(Vernaux)* vernaux = reinterpret_cast<ElfW(Vernaux)*>(verneed_ptr + vernaux_offset);
2393 vernaux_offset += vernaux->vna_next;
2394
2395 const ElfW(Word) elf_hash = vernaux->vna_hash;
2396 const char* ver_name = si_from->get_string(vernaux->vna_name);
2397 ElfW(Half) source_index = vernaux->vna_other;
2398
2399 add_version_info(source_index, elf_hash, ver_name, target_si);
2400 }
2401 }
2402
2403 return true;
2404}
2405
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002406template <typename F>
2407static bool for_each_verdef(const soinfo* si, F functor) {
2408 if (!si->has_min_version(2)) {
2409 return true;
2410 }
2411
2412 uintptr_t verdef_ptr = si->get_verdef_ptr();
2413 if (verdef_ptr == 0) {
2414 return true;
2415 }
2416
2417 size_t offset = 0;
2418
2419 size_t verdef_cnt = si->get_verdef_cnt();
2420 for (size_t i = 0; i<verdef_cnt; ++i) {
2421 const ElfW(Verdef)* verdef = reinterpret_cast<ElfW(Verdef)*>(verdef_ptr + offset);
2422 size_t verdaux_offset = offset + verdef->vd_aux;
2423 offset += verdef->vd_next;
2424
2425 if (verdef->vd_version != 1) {
2426 DL_ERR("unsupported verdef[%zd] vd_version: %d (expected 1) library: %s",
2427 i, verdef->vd_version, si->get_realpath());
2428 return false;
2429 }
2430
2431 if ((verdef->vd_flags & VER_FLG_BASE) != 0) {
2432 // "this is the version of the file itself. It must not be used for
2433 // matching a symbol. It can be used to match references."
2434 //
2435 // http://www.akkadia.org/drepper/symbol-versioning
2436 continue;
2437 }
2438
2439 if (verdef->vd_cnt == 0) {
2440 DL_ERR("invalid verdef[%zd] vd_cnt == 0 (version without a name)", i);
2441 return false;
2442 }
2443
2444 const ElfW(Verdaux)* verdaux = reinterpret_cast<ElfW(Verdaux)*>(verdef_ptr + verdaux_offset);
2445
2446 if (functor(i, verdef, verdaux) == true) {
2447 break;
2448 }
2449 }
2450
2451 return true;
2452}
2453
2454bool find_verdef_version_index(const soinfo* si, const version_info* vi, ElfW(Versym)* versym) {
2455 if (vi == nullptr) {
2456 *versym = kVersymNotNeeded;
2457 return true;
2458 }
2459
2460 *versym = kVersymGlobal;
2461
2462 return for_each_verdef(si,
2463 [&](size_t, const ElfW(Verdef)* verdef, const ElfW(Verdaux)* verdaux) {
2464 if (verdef->vd_hash == vi->elf_hash &&
2465 strcmp(vi->name, si->get_string(verdaux->vda_name)) == 0) {
2466 *versym = verdef->vd_ndx;
2467 return true;
2468 }
2469
2470 return false;
2471 }
2472 );
2473}
2474
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002475bool VersionTracker::init_verdef(const soinfo* si_from) {
2476 return for_each_verdef(si_from,
2477 [&](size_t, const ElfW(Verdef)* verdef, const ElfW(Verdaux)* verdaux) {
2478 add_version_info(verdef->vd_ndx, verdef->vd_hash,
2479 si_from->get_string(verdaux->vda_name), si_from);
2480 return false;
2481 }
2482 );
2483}
2484
2485bool VersionTracker::init(const soinfo* si_from) {
2486 if (!si_from->has_min_version(2)) {
2487 return true;
2488 }
2489
2490 return init_verneed(si_from) && init_verdef(si_from);
2491}
2492
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002493// TODO (dimitry): Methods below need to be moved out of soinfo
2494// and in more isolated file in order minimize dependencies on
2495// unnecessary object in the linker binary. Consider making them
2496// independent from soinfo (?).
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002497bool soinfo::lookup_version_info(const VersionTracker& version_tracker, ElfW(Word) sym,
2498 const char* sym_name, const version_info** vi) {
2499 const ElfW(Versym)* sym_ver_ptr = get_versym(sym);
2500 ElfW(Versym) sym_ver = sym_ver_ptr == nullptr ? 0 : *sym_ver_ptr;
2501
2502 if (sym_ver != VER_NDX_LOCAL && sym_ver != VER_NDX_GLOBAL) {
2503 *vi = version_tracker.get_version_info(sym_ver);
2504
2505 if (*vi == nullptr) {
2506 DL_ERR("cannot find verneed/verdef for version index=%d "
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002507 "referenced by symbol \"%s\" at \"%s\"", sym_ver, sym_name, get_realpath());
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002508 return false;
2509 }
2510 } else {
2511 // there is no version info
2512 *vi = nullptr;
2513 }
2514
2515 return true;
2516}
2517
Dimitry Ivanov576a3752016-08-09 06:58:55 -07002518#if !defined(__mips__)
2519#if defined(USE_RELA)
2520static ElfW(Addr) get_addend(ElfW(Rela)* rela, ElfW(Addr) reloc_addr __unused) {
2521 return rela->r_addend;
2522}
2523#else
2524static ElfW(Addr) get_addend(ElfW(Rel)* rel, ElfW(Addr) reloc_addr) {
2525 if (ELFW(R_TYPE)(rel->r_info) == R_GENERIC_RELATIVE ||
2526 ELFW(R_TYPE)(rel->r_info) == R_GENERIC_IRELATIVE) {
2527 return *reinterpret_cast<ElfW(Addr)*>(reloc_addr);
2528 }
2529 return 0;
2530}
2531#endif
2532
Dmitriy Ivanovfa26eee2015-02-03 16:06:47 -08002533template<typename ElfRelIteratorT>
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07002534bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& rel_iterator,
2535 const soinfo_list_t& global_group, const soinfo_list_t& local_group) {
Dmitriy Ivanovfa26eee2015-02-03 16:06:47 -08002536 for (size_t idx = 0; rel_iterator.has_next(); ++idx) {
2537 const auto rel = rel_iterator.next();
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002538 if (rel == nullptr) {
2539 return false;
2540 }
2541
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002542 ElfW(Word) type = ELFW(R_TYPE)(rel->r_info);
2543 ElfW(Word) sym = ELFW(R_SYM)(rel->r_info);
2544
2545 ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rel->r_offset + load_bias);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002546 ElfW(Addr) sym_addr = 0;
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07002547 const char* sym_name = nullptr;
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002548 ElfW(Addr) addend = get_addend(rel, reloc);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002549
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07002550 DEBUG("Processing \"%s\" relocation at index %zd", get_realpath(), idx);
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002551 if (type == R_GENERIC_NONE) {
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002552 continue;
2553 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002554
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002555 const ElfW(Sym)* s = nullptr;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002556 soinfo* lsi = nullptr;
2557
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002558 if (sym != 0) {
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002559 sym_name = get_string(symtab_[sym].st_name);
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002560 const version_info* vi = nullptr;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002561
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002562 if (!lookup_version_info(version_tracker, sym, sym_name, &vi)) {
2563 return false;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002564 }
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002565
2566 if (!soinfo_do_lookup(this, sym_name, vi, &lsi, global_group, local_group, &s)) {
2567 return false;
2568 }
2569
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07002570 if (s == nullptr) {
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002571 // We only allow an undefined symbol if this is a weak reference...
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002572 s = &symtab_[sym];
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002573 if (ELF_ST_BIND(s->st_info) != STB_WEAK) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002574 DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, get_realpath());
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002575 return false;
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002576 }
2577
2578 /* IHI0044C AAELF 4.5.1.1:
2579
2580 Libraries are not searched to resolve weak references.
2581 It is not an error for a weak reference to remain unsatisfied.
2582
2583 During linking, the value of an undefined weak reference is:
2584 - Zero if the relocation type is absolute
2585 - The address of the place if the relocation is pc-relative
2586 - The address of nominal base address if the relocation
2587 type is base-relative.
2588 */
2589
2590 switch (type) {
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002591 case R_GENERIC_JUMP_SLOT:
2592 case R_GENERIC_GLOB_DAT:
2593 case R_GENERIC_RELATIVE:
2594 case R_GENERIC_IRELATIVE:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002595#if defined(__aarch64__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002596 case R_AARCH64_ABS64:
2597 case R_AARCH64_ABS32:
2598 case R_AARCH64_ABS16:
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002599#elif defined(__x86_64__)
2600 case R_X86_64_32:
2601 case R_X86_64_64:
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002602#elif defined(__arm__)
2603 case R_ARM_ABS32:
2604#elif defined(__i386__)
2605 case R_386_32:
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002606#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002607 /*
2608 * The sym_addr was initialized to be zero above, or the relocation
2609 * code below does not care about value of sym_addr.
2610 * No need to do anything.
2611 */
2612 break;
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002613#if defined(__x86_64__)
Dimitry Ivanovd338aac2015-01-13 22:31:54 +00002614 case R_X86_64_PC32:
2615 sym_addr = reloc;
2616 break;
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002617#elif defined(__i386__)
2618 case R_386_PC32:
2619 sym_addr = reloc;
2620 break;
2621#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002622 default:
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002623 DL_ERR("unknown weak reloc type %d @ %p (%zu)", type, rel, idx);
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002624 return false;
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002625 }
Dmitriy Ivanovec83a612015-07-26 07:37:09 -07002626 } else { // We got a definition.
2627#if !defined(__LP64__)
2628 // When relocating dso with text_relocation .text segment is
2629 // not executable. We need to restore elf flags before resolving
2630 // STT_GNU_IFUNC symbol.
2631 bool protect_segments = has_text_relocations &&
2632 lsi == this &&
2633 ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC;
2634 if (protect_segments) {
2635 if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
2636 DL_ERR("can't protect segments for \"%s\": %s",
2637 get_realpath(), strerror(errno));
2638 return false;
2639 }
2640 }
2641#endif
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07002642 sym_addr = lsi->resolve_symbol_address(s);
Dmitriy Ivanovec83a612015-07-26 07:37:09 -07002643#if !defined(__LP64__)
2644 if (protect_segments) {
2645 if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
2646 DL_ERR("can't unprotect loadable segments for \"%s\": %s",
2647 get_realpath(), strerror(errno));
2648 return false;
2649 }
2650 }
2651#endif
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002652 }
2653 count_relocation(kRelocSymbol);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002654 }
2655
2656 switch (type) {
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002657 case R_GENERIC_JUMP_SLOT:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002658 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002659 MARK(rel->r_offset);
2660 TRACE_TYPE(RELO, "RELO JMP_SLOT %16p <- %16p %s\n",
2661 reinterpret_cast<void*>(reloc),
2662 reinterpret_cast<void*>(sym_addr + addend), sym_name);
2663
2664 *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002665 break;
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002666 case R_GENERIC_GLOB_DAT:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002667 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002668 MARK(rel->r_offset);
2669 TRACE_TYPE(RELO, "RELO GLOB_DAT %16p <- %16p %s\n",
2670 reinterpret_cast<void*>(reloc),
2671 reinterpret_cast<void*>(sym_addr + addend), sym_name);
2672 *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002673 break;
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002674 case R_GENERIC_RELATIVE:
2675 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002676 MARK(rel->r_offset);
2677 TRACE_TYPE(RELO, "RELO RELATIVE %16p <- %16p\n",
2678 reinterpret_cast<void*>(reloc),
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002679 reinterpret_cast<void*>(load_bias + addend));
2680 *reinterpret_cast<ElfW(Addr)*>(reloc) = (load_bias + addend);
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002681 break;
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002682 case R_GENERIC_IRELATIVE:
2683 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002684 MARK(rel->r_offset);
2685 TRACE_TYPE(RELO, "RELO IRELATIVE %16p <- %16p\n",
2686 reinterpret_cast<void*>(reloc),
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002687 reinterpret_cast<void*>(load_bias + addend));
Dmitriy Ivanovec83a612015-07-26 07:37:09 -07002688 {
2689#if !defined(__LP64__)
2690 // When relocating dso with text_relocation .text segment is
2691 // not executable. We need to restore elf flags for this
2692 // particular call.
2693 if (has_text_relocations) {
2694 if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
2695 DL_ERR("can't protect segments for \"%s\": %s",
2696 get_realpath(), strerror(errno));
2697 return false;
2698 }
2699 }
2700#endif
2701 ElfW(Addr) ifunc_addr = call_ifunc_resolver(load_bias + addend);
2702#if !defined(__LP64__)
2703 // Unprotect it afterwards...
2704 if (has_text_relocations) {
2705 if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
2706 DL_ERR("can't unprotect loadable segments for \"%s\": %s",
2707 get_realpath(), strerror(errno));
2708 return false;
2709 }
2710 }
2711#endif
2712 *reinterpret_cast<ElfW(Addr)*>(reloc) = ifunc_addr;
2713 }
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002714 break;
2715
2716#if defined(__aarch64__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002717 case R_AARCH64_ABS64:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002718 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002719 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002720 TRACE_TYPE(RELO, "RELO ABS64 %16llx <- %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002721 reloc, sym_addr + addend, sym_name);
2722 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend;
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002723 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002724 case R_AARCH64_ABS32:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002725 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002726 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002727 TRACE_TYPE(RELO, "RELO ABS32 %16llx <- %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002728 reloc, sym_addr + addend, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002729 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002730 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT32_MIN);
2731 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT32_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002732 if ((min_value <= (sym_addr + addend)) &&
2733 ((sym_addr + addend) <= max_value)) {
2734 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend;
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002735 } else {
2736 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002737 sym_addr + addend, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002738 return false;
2739 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002740 }
2741 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002742 case R_AARCH64_ABS16:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002743 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002744 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002745 TRACE_TYPE(RELO, "RELO ABS16 %16llx <- %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002746 reloc, sym_addr + addend, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002747 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002748 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN);
2749 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT16_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002750 if ((min_value <= (sym_addr + addend)) &&
2751 ((sym_addr + addend) <= max_value)) {
2752 *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002753 } else {
2754 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002755 sym_addr + addend, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002756 return false;
2757 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002758 }
2759 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002760 case R_AARCH64_PREL64:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002761 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002762 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002763 TRACE_TYPE(RELO, "RELO REL64 %16llx <- %16llx - %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002764 reloc, sym_addr + addend, rel->r_offset, sym_name);
2765 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset;
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002766 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002767 case R_AARCH64_PREL32:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002768 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002769 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002770 TRACE_TYPE(RELO, "RELO REL32 %16llx <- %16llx - %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002771 reloc, sym_addr + addend, rel->r_offset, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002772 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002773 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT32_MIN);
2774 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT32_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002775 if ((min_value <= (sym_addr + addend - rel->r_offset)) &&
2776 ((sym_addr + addend - rel->r_offset) <= max_value)) {
2777 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset;
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002778 } else {
2779 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002780 sym_addr + addend - rel->r_offset, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002781 return false;
2782 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002783 }
2784 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002785 case R_AARCH64_PREL16:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002786 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002787 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002788 TRACE_TYPE(RELO, "RELO REL16 %16llx <- %16llx - %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002789 reloc, sym_addr + addend, rel->r_offset, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002790 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002791 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN);
2792 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT16_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002793 if ((min_value <= (sym_addr + addend - rel->r_offset)) &&
2794 ((sym_addr + addend - rel->r_offset) <= max_value)) {
2795 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset;
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002796 } else {
2797 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002798 sym_addr + addend - rel->r_offset, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002799 return false;
2800 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002801 }
2802 break;
2803
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002804 case R_AARCH64_COPY:
Nick Kralevich76e289c2014-07-03 12:04:31 -07002805 /*
2806 * ET_EXEC is not supported so this should not happen.
2807 *
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002808 * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0056b/IHI0056B_aaelf64.pdf
Nick Kralevich76e289c2014-07-03 12:04:31 -07002809 *
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002810 * Section 4.6.11 "Dynamic relocations"
Nick Kralevich76e289c2014-07-03 12:04:31 -07002811 * R_AARCH64_COPY may only appear in executable objects where e_type is
2812 * set to ET_EXEC.
2813 */
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002814 DL_ERR("%s R_AARCH64_COPY relocations are not supported", get_realpath());
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002815 return false;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002816 case R_AARCH64_TLS_TPREL64:
Elliott Hughes0266ae52014-02-10 17:46:57 -08002817 TRACE_TYPE(RELO, "RELO TLS_TPREL64 *** %16llx <- %16llx - %16llx\n",
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002818 reloc, (sym_addr + addend), rel->r_offset);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002819 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002820 case R_AARCH64_TLS_DTPREL32:
Elliott Hughes0266ae52014-02-10 17:46:57 -08002821 TRACE_TYPE(RELO, "RELO TLS_DTPREL32 *** %16llx <- %16llx - %16llx\n",
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002822 reloc, (sym_addr + addend), rel->r_offset);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002823 break;
2824#elif defined(__x86_64__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002825 case R_X86_64_32:
2826 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002827 MARK(rel->r_offset);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002828 TRACE_TYPE(RELO, "RELO R_X86_64_32 %08zx <- +%08zx %s", static_cast<size_t>(reloc),
2829 static_cast<size_t>(sym_addr), sym_name);
Junichi Uekawaff35b1e2015-11-18 10:18:59 +09002830 *reinterpret_cast<Elf32_Addr*>(reloc) = sym_addr + addend;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002831 break;
2832 case R_X86_64_64:
2833 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002834 MARK(rel->r_offset);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002835 TRACE_TYPE(RELO, "RELO R_X86_64_64 %08zx <- +%08zx %s", static_cast<size_t>(reloc),
2836 static_cast<size_t>(sym_addr), sym_name);
Junichi Uekawaff35b1e2015-11-18 10:18:59 +09002837 *reinterpret_cast<Elf64_Addr*>(reloc) = sym_addr + addend;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002838 break;
2839 case R_X86_64_PC32:
2840 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002841 MARK(rel->r_offset);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002842 TRACE_TYPE(RELO, "RELO R_X86_64_PC32 %08zx <- +%08zx (%08zx - %08zx) %s",
2843 static_cast<size_t>(reloc), static_cast<size_t>(sym_addr - reloc),
2844 static_cast<size_t>(sym_addr), static_cast<size_t>(reloc), sym_name);
Junichi Uekawaff35b1e2015-11-18 10:18:59 +09002845 *reinterpret_cast<Elf32_Addr*>(reloc) = sym_addr + addend - reloc;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002846 break;
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002847#elif defined(__arm__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002848 case R_ARM_ABS32:
2849 count_relocation(kRelocAbsolute);
2850 MARK(rel->r_offset);
2851 TRACE_TYPE(RELO, "RELO ABS %08x <- %08x %s", reloc, sym_addr, sym_name);
2852 *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
2853 break;
2854 case R_ARM_REL32:
2855 count_relocation(kRelocRelative);
2856 MARK(rel->r_offset);
2857 TRACE_TYPE(RELO, "RELO REL32 %08x <- %08x - %08x %s",
2858 reloc, sym_addr, rel->r_offset, sym_name);
2859 *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr - rel->r_offset;
2860 break;
2861 case R_ARM_COPY:
2862 /*
2863 * ET_EXEC is not supported so this should not happen.
2864 *
2865 * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044d/IHI0044D_aaelf.pdf
2866 *
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002867 * Section 4.6.1.10 "Dynamic relocations"
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002868 * R_ARM_COPY may only appear in executable objects where e_type is
2869 * set to ET_EXEC.
2870 */
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002871 DL_ERR("%s R_ARM_COPY relocations are not supported", get_realpath());
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002872 return false;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002873#elif defined(__i386__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002874 case R_386_32:
2875 count_relocation(kRelocRelative);
2876 MARK(rel->r_offset);
2877 TRACE_TYPE(RELO, "RELO R_386_32 %08x <- +%08x %s", reloc, sym_addr, sym_name);
2878 *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
2879 break;
2880 case R_386_PC32:
2881 count_relocation(kRelocRelative);
2882 MARK(rel->r_offset);
2883 TRACE_TYPE(RELO, "RELO R_386_PC32 %08x <- +%08x (%08x - %08x) %s",
2884 reloc, (sym_addr - reloc), sym_addr, reloc, sym_name);
2885 *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr - reloc);
2886 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002887#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002888 default:
2889 DL_ERR("unknown reloc type %d @ %p (%zu)", type, rel, idx);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002890 return false;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002891 }
2892 }
2893 return true;
Raghu Gandhamd7daacb2012-07-31 12:07:22 -07002894}
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002895#endif // !defined(__mips__)
Raghu Gandhamd7daacb2012-07-31 12:07:22 -07002896
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002897// An empty list of soinfos
Dimitry Ivanovb943f302016-08-03 16:00:10 -07002898static soinfo_list_t g_empty_list;
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07002899
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002900bool soinfo::prelink_image() {
Ningsheng Jiane93be992014-09-16 15:22:10 +08002901 /* Extract dynamic section */
2902 ElfW(Word) dynamic_flags = 0;
2903 phdr_table_get_dynamic_section(phdr, phnum, load_bias, &dynamic, &dynamic_flags);
Dmitriy Ivanov498eb182014-09-05 14:57:59 -07002904
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002905 /* We can't log anything until the linker is relocated */
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002906 bool relocating_linker = (flags_ & FLAG_LINKER) != 0;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002907 if (!relocating_linker) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07002908 INFO("[ Linking \"%s\" ]", get_realpath());
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002909 DEBUG("si->base = %p si->flags = 0x%08x", reinterpret_cast<void*>(base), flags_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002910 }
2911
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002912 if (dynamic == nullptr) {
David 'Digit' Turnerb52e4382012-06-19 01:24:17 +02002913 if (!relocating_linker) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002914 DL_ERR("missing PT_DYNAMIC in \"%s\"", get_realpath());
David 'Digit' Turnerb52e4382012-06-19 01:24:17 +02002915 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002916 return false;
2917 } else {
2918 if (!relocating_linker) {
2919 DEBUG("dynamic = %p", dynamic);
David 'Digit' Turner63f99f42012-06-19 00:08:39 +02002920 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002921 }
David 'Digit' Turner63f99f42012-06-19 00:08:39 +02002922
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07002923#if defined(__arm__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002924 (void) phdr_table_get_arm_exidx(phdr, phnum, load_bias,
2925 &ARM_exidx, &ARM_exidx_count);
David 'Digit' Turner63f99f42012-06-19 00:08:39 +02002926#endif
2927
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002928 // Extract useful information from dynamic section.
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07002929 // Note that: "Except for the DT_NULL element at the end of the array,
2930 // and the relative order of DT_NEEDED elements, entries may appear in any order."
2931 //
2932 // source: http://www.sco.com/developers/gabi/1998-04-29/ch5.dynamic.html
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002933 uint32_t needed_count = 0;
2934 for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
2935 DEBUG("d = %p, d[0](tag) = %p d[1](val) = %p",
2936 d, reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
2937 switch (d->d_tag) {
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002938 case DT_SONAME:
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07002939 // this is parsed after we have strtab initialized (see below).
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002940 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002941
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002942 case DT_HASH:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002943 nbucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0];
2944 nchain_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
2945 bucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8);
2946 chain_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8 + nbucket_ * 4);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002947 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002948
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002949 case DT_GNU_HASH:
Dmitriy Ivanov3597b802015-03-09 12:02:02 -07002950 gnu_nbucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0];
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002951 // skip symndx
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002952 gnu_maskwords_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[2];
2953 gnu_shift2_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[3];
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002954
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002955 gnu_bloom_filter_ = reinterpret_cast<ElfW(Addr)*>(load_bias + d->d_un.d_ptr + 16);
Dmitriy Ivanov3597b802015-03-09 12:02:02 -07002956 gnu_bucket_ = reinterpret_cast<uint32_t*>(gnu_bloom_filter_ + gnu_maskwords_);
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002957 // amend chain for symndx = header[1]
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002958 gnu_chain_ = gnu_bucket_ + gnu_nbucket_ -
2959 reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002960
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002961 if (!powerof2(gnu_maskwords_)) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002962 DL_ERR("invalid maskwords for gnu_hash = 0x%x, in \"%s\" expecting power to two",
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002963 gnu_maskwords_, get_realpath());
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002964 return false;
2965 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002966 --gnu_maskwords_;
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002967
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002968 flags_ |= FLAG_GNU_HASH;
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08002969 break;
2970
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002971 case DT_STRTAB:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002972 strtab_ = reinterpret_cast<const char*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002973 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002974
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07002975 case DT_STRSZ:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002976 strtab_size_ = d->d_un.d_val;
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07002977 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002978
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002979 case DT_SYMTAB:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002980 symtab_ = reinterpret_cast<ElfW(Sym)*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002981 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002982
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002983 case DT_SYMENT:
2984 if (d->d_un.d_val != sizeof(ElfW(Sym))) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002985 DL_ERR("invalid DT_SYMENT: %zd in \"%s\"",
2986 static_cast<size_t>(d->d_un.d_val), get_realpath());
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07002987 return false;
2988 }
2989 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07002990
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002991 case DT_PLTREL:
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002992#if defined(USE_RELA)
2993 if (d->d_un.d_val != DT_RELA) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002994 DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_RELA", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002995 return false;
2996 }
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07002997#else
2998 if (d->d_un.d_val != DT_REL) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002999 DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_REL", get_realpath());
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003000 return false;
3001 }
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07003002#endif
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003003 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003004
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003005 case DT_JMPREL:
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07003006#if defined(USE_RELA)
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003007 plt_rela_ = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07003008#else
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003009 plt_rel_ = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07003010#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003011 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003012
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003013 case DT_PLTRELSZ:
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07003014#if defined(USE_RELA)
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003015 plt_rela_count_ = d->d_un.d_val / sizeof(ElfW(Rela));
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07003016#else
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003017 plt_rel_count_ = d->d_un.d_val / sizeof(ElfW(Rel));
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07003018#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003019 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003020
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003021 case DT_PLTGOT:
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003022#if defined(__mips__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003023 // Used by mips and mips64.
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003024 plt_got_ = reinterpret_cast<ElfW(Addr)**>(load_bias + d->d_un.d_ptr);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07003025#endif
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003026 // Ignore for other platforms... (because RTLD_LAZY is not supported)
3027 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003028
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003029 case DT_DEBUG:
3030 // Set the DT_DEBUG entry to the address of _r_debug for GDB
3031 // if the dynamic table is writable
Chris Dearman99186652014-02-06 20:36:51 -08003032// FIXME: not working currently for N64
3033// The flags for the LOAD and DYNAMIC program headers do not agree.
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07003034// The LOAD section containing the dynamic table has been mapped as
Chris Dearman99186652014-02-06 20:36:51 -08003035// read-only, but the DYNAMIC header claims it is writable.
3036#if !(defined(__mips__) && defined(__LP64__))
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003037 if ((dynamic_flags & PF_W) != 0) {
3038 d->d_un.d_val = reinterpret_cast<uintptr_t>(&_r_debug);
3039 }
Chris Dearman99186652014-02-06 20:36:51 -08003040#endif
Dmitriy Ivanovc6292ea2015-02-13 16:29:50 -08003041 break;
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07003042#if defined(USE_RELA)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003043 case DT_RELA:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003044 rela_ = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003045 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003046
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003047 case DT_RELASZ:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003048 rela_count_ = d->d_un.d_val / sizeof(ElfW(Rela));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003049 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003050
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003051 case DT_ANDROID_RELA:
3052 android_relocs_ = reinterpret_cast<uint8_t*>(load_bias + d->d_un.d_ptr);
3053 break;
3054
3055 case DT_ANDROID_RELASZ:
3056 android_relocs_size_ = d->d_un.d_val;
3057 break;
3058
3059 case DT_ANDROID_REL:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003060 DL_ERR("unsupported DT_ANDROID_REL in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003061 return false;
3062
3063 case DT_ANDROID_RELSZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003064 DL_ERR("unsupported DT_ANDROID_RELSZ in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003065 return false;
3066
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003067 case DT_RELAENT:
3068 if (d->d_un.d_val != sizeof(ElfW(Rela))) {
Dmitriy Ivanovf240aa82014-09-16 23:34:20 -07003069 DL_ERR("invalid DT_RELAENT: %zd", static_cast<size_t>(d->d_un.d_val));
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003070 return false;
3071 }
3072 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003073
3074 // ignored (see DT_RELCOUNT comments for details)
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003075 case DT_RELACOUNT:
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003076 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003077
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003078 case DT_REL:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003079 DL_ERR("unsupported DT_REL in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003080 return false;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003081
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003082 case DT_RELSZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003083 DL_ERR("unsupported DT_RELSZ in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003084 return false;
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003085
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07003086#else
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003087 case DT_REL:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003088 rel_ = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003089 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003090
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003091 case DT_RELSZ:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003092 rel_count_ = d->d_un.d_val / sizeof(ElfW(Rel));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003093 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003094
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003095 case DT_RELENT:
3096 if (d->d_un.d_val != sizeof(ElfW(Rel))) {
Dmitriy Ivanovf240aa82014-09-16 23:34:20 -07003097 DL_ERR("invalid DT_RELENT: %zd", static_cast<size_t>(d->d_un.d_val));
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003098 return false;
3099 }
3100 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003101
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003102 case DT_ANDROID_REL:
3103 android_relocs_ = reinterpret_cast<uint8_t*>(load_bias + d->d_un.d_ptr);
3104 break;
3105
3106 case DT_ANDROID_RELSZ:
3107 android_relocs_size_ = d->d_un.d_val;
3108 break;
3109
3110 case DT_ANDROID_RELA:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003111 DL_ERR("unsupported DT_ANDROID_RELA in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003112 return false;
3113
3114 case DT_ANDROID_RELASZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003115 DL_ERR("unsupported DT_ANDROID_RELASZ in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003116 return false;
3117
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003118 // "Indicates that all RELATIVE relocations have been concatenated together,
3119 // and specifies the RELATIVE relocation count."
3120 //
3121 // TODO: Spec also mentions that this can be used to optimize relocation process;
3122 // Not currently used by bionic linker - ignored.
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003123 case DT_RELCOUNT:
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003124 break;
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003125
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003126 case DT_RELA:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003127 DL_ERR("unsupported DT_RELA in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003128 return false;
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003129
3130 case DT_RELASZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003131 DL_ERR("unsupported DT_RELASZ in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003132 return false;
3133
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07003134#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003135 case DT_INIT:
Dimitry Ivanov55437462016-07-20 15:33:07 -07003136 init_func_ = reinterpret_cast<linker_ctor_function_t>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003137 DEBUG("%s constructors (DT_INIT) found at %p", get_realpath(), init_func_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003138 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003139
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003140 case DT_FINI:
Dimitry Ivanov55437462016-07-20 15:33:07 -07003141 fini_func_ = reinterpret_cast<linker_dtor_function_t>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003142 DEBUG("%s destructors (DT_FINI) found at %p", get_realpath(), fini_func_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003143 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003144
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003145 case DT_INIT_ARRAY:
Dimitry Ivanov55437462016-07-20 15:33:07 -07003146 init_array_ = reinterpret_cast<linker_ctor_function_t*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003147 DEBUG("%s constructors (DT_INIT_ARRAY) found at %p", get_realpath(), init_array_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003148 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003149
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003150 case DT_INIT_ARRAYSZ:
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -08003151 init_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003152 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003153
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003154 case DT_FINI_ARRAY:
Dimitry Ivanov55437462016-07-20 15:33:07 -07003155 fini_array_ = reinterpret_cast<linker_dtor_function_t*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003156 DEBUG("%s destructors (DT_FINI_ARRAY) found at %p", get_realpath(), fini_array_);
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_FINI_ARRAYSZ:
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -08003160 fini_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003161 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003162
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003163 case DT_PREINIT_ARRAY:
Dimitry Ivanov55437462016-07-20 15:33:07 -07003164 preinit_array_ = reinterpret_cast<linker_ctor_function_t*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003165 DEBUG("%s constructors (DT_PREINIT_ARRAY) found at %p", get_realpath(), preinit_array_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003166 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003167
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003168 case DT_PREINIT_ARRAYSZ:
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -08003169 preinit_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003170 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003171
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003172 case DT_TEXTREL:
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003173#if defined(__LP64__)
Dimitry Ivanov816676e2016-10-19 11:00:28 -07003174 DL_ERR("\"%s\" has text relocations", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003175 return false;
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003176#else
3177 has_text_relocations = true;
3178 break;
3179#endif
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003180
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003181 case DT_SYMBOLIC:
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -07003182 has_DT_SYMBOLIC = true;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003183 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003184
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003185 case DT_NEEDED:
3186 ++needed_count;
3187 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003188
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003189 case DT_FLAGS:
3190 if (d->d_un.d_val & DF_TEXTREL) {
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003191#if defined(__LP64__)
Dimitry Ivanov816676e2016-10-19 11:00:28 -07003192 DL_ERR("\"%s\" has text relocations", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003193 return false;
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003194#else
3195 has_text_relocations = true;
3196#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003197 }
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -07003198 if (d->d_un.d_val & DF_SYMBOLIC) {
3199 has_DT_SYMBOLIC = true;
3200 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003201 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003202
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07003203 case DT_FLAGS_1:
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07003204 set_dt_flags_1(d->d_un.d_val);
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -07003205
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07003206 if ((d->d_un.d_val & ~SUPPORTED_DT_FLAGS_1) != 0) {
Dimitry Ivanov816676e2016-10-19 11:00:28 -07003207 DL_WARN("\"%s\" has unsupported flags DT_FLAGS_1=%p", get_realpath(), reinterpret_cast<void*>(d->d_un.d_val));
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07003208 }
3209 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003210#if defined(__mips__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003211 case DT_MIPS_RLD_MAP:
3212 // Set the DT_MIPS_RLD_MAP entry to the address of _r_debug for GDB.
3213 {
3214 r_debug** dp = reinterpret_cast<r_debug**>(load_bias + d->d_un.d_ptr);
3215 *dp = &_r_debug;
3216 }
3217 break;
Lazar Trsic83b44a92016-04-06 13:39:17 +02003218 case DT_MIPS_RLD_MAP_REL:
3219 // Set the DT_MIPS_RLD_MAP_REL entry to the address of _r_debug for GDB.
Raghu Gandham68815722014-12-18 19:12:19 -08003220 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07003221 r_debug** dp = reinterpret_cast<r_debug**>(
3222 reinterpret_cast<ElfW(Addr)>(d) + d->d_un.d_val);
Raghu Gandham68815722014-12-18 19:12:19 -08003223 *dp = &_r_debug;
3224 }
3225 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003226
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003227 case DT_MIPS_RLD_VERSION:
3228 case DT_MIPS_FLAGS:
3229 case DT_MIPS_BASE_ADDRESS:
3230 case DT_MIPS_UNREFEXTNO:
3231 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003232
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003233 case DT_MIPS_SYMTABNO:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003234 mips_symtabno_ = d->d_un.d_val;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003235 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003236
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003237 case DT_MIPS_LOCAL_GOTNO:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003238 mips_local_gotno_ = d->d_un.d_val;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003239 break;
3240
3241 case DT_MIPS_GOTSYM:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003242 mips_gotsym_ = d->d_un.d_val;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003243 break;
3244#endif
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003245 // Ignored: "Its use has been superseded by the DF_BIND_NOW flag"
3246 case DT_BIND_NOW:
3247 break;
3248
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003249 case DT_VERSYM:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003250 versym_ = reinterpret_cast<ElfW(Versym)*>(load_bias + d->d_un.d_ptr);
3251 break;
3252
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003253 case DT_VERDEF:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003254 verdef_ptr_ = load_bias + d->d_un.d_ptr;
3255 break;
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003256 case DT_VERDEFNUM:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003257 verdef_cnt_ = d->d_un.d_val;
3258 break;
3259
Alexander Ivchenkoe8314332014-12-02 15:32:25 +03003260 case DT_VERNEED:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003261 verneed_ptr_ = load_bias + d->d_un.d_ptr;
3262 break;
3263
Alexander Ivchenkoe8314332014-12-02 15:32:25 +03003264 case DT_VERNEEDNUM:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003265 verneed_cnt_ = d->d_un.d_val;
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003266 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003267
Evgenii Stepanov68650822015-06-10 13:38:39 -07003268 case DT_RUNPATH:
3269 // this is parsed after we have strtab initialized (see below).
3270 break;
3271
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003272 default:
Dmitriy Ivanov8f61d992014-09-16 14:31:06 -07003273 if (!relocating_linker) {
Dimitry Ivanov816676e2016-10-19 11:00:28 -07003274 DL_WARN("\"%s\" unused DT entry: type %p arg %p", get_realpath(),
Dmitriy Ivanov8f61d992014-09-16 14:31:06 -07003275 reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
3276 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003277 break;
Brian Carlstromd4ee82d2013-02-28 15:58:45 -08003278 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003279 }
3280
Duane Sandbc425c72015-06-01 16:29:14 -07003281#if defined(__mips__) && !defined(__LP64__)
3282 if (!mips_check_and_adjust_fp_modes()) {
3283 return false;
3284 }
3285#endif
3286
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003287 DEBUG("si->base = %p, si->strtab = %p, si->symtab = %p",
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003288 reinterpret_cast<void*>(base), strtab_, symtab_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003289
3290 // Sanity checks.
3291 if (relocating_linker && needed_count != 0) {
3292 DL_ERR("linker cannot have DT_NEEDED dependencies on other libraries");
3293 return false;
3294 }
Dmitriy Ivanov3597b802015-03-09 12:02:02 -07003295 if (nbucket_ == 0 && gnu_nbucket_ == 0) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003296 DL_ERR("empty/missing DT_HASH/DT_GNU_HASH in \"%s\" "
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003297 "(new hash type from the future?)", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003298 return false;
3299 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003300 if (strtab_ == 0) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003301 DL_ERR("empty/missing DT_STRTAB in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003302 return false;
3303 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003304 if (symtab_ == 0) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003305 DL_ERR("empty/missing DT_SYMTAB in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003306 return false;
3307 }
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003308
Dmitriy Ivanov624b8f12015-06-08 10:41:33 -07003309 // second pass - parse entries relying on strtab
3310 for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
Evgenii Stepanov68650822015-06-10 13:38:39 -07003311 switch (d->d_tag) {
3312 case DT_SONAME:
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07003313 set_soname(get_string(d->d_un.d_val));
Evgenii Stepanov68650822015-06-10 13:38:39 -07003314 break;
3315 case DT_RUNPATH:
Evgenii Stepanov68650822015-06-10 13:38:39 -07003316 set_dt_runpath(get_string(d->d_un.d_val));
3317 break;
Dmitriy Ivanov624b8f12015-06-08 10:41:33 -07003318 }
3319 }
3320
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003321 // Before M release linker was using basename in place of soname.
Dmitriy Ivanov19133522015-06-02 17:36:54 -07003322 // In the case when dt_soname is absent some apps stop working
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003323 // because they can't find dt_needed library by soname.
3324 // This workaround should keep them working. (applies only
Elliott Hughes5bc78c82016-11-16 11:35:43 -08003325 // for apps targeting sdk version < M). Make an exception for
Dmitriy Ivanov19133522015-06-02 17:36:54 -07003326 // the main executable and linker; they do not need to have dt_soname
Dimitry Ivanov3f660572016-09-09 10:00:39 -07003327 if (soname_ == nullptr &&
3328 this != solist_get_somain() &&
3329 (flags_ & FLAG_LINKER) == 0 &&
Elliott Hughes5bc78c82016-11-16 11:35:43 -08003330 get_application_target_sdk_version() < __ANDROID_API_M__) {
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003331 soname_ = basename(realpath_.c_str());
3332 DL_WARN("%s: is missing DT_SONAME will use basename as a replacement: \"%s\"",
3333 get_realpath(), soname_);
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07003334 // 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 -07003335 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003336 return true;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07003337}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003338
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003339bool soinfo::link_image(const soinfo_list_t& global_group, const soinfo_list_t& local_group,
3340 const android_dlextinfo* extinfo) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003341
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08003342 local_group_root_ = local_group.front();
3343 if (local_group_root_ == nullptr) {
3344 local_group_root_ = this;
3345 }
3346
Dmitriy Ivanov19133522015-06-02 17:36:54 -07003347 if ((flags_ & FLAG_LINKER) == 0 && local_group_root_ == this) {
3348 target_sdk_version_ = get_application_target_sdk_version();
3349 }
3350
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003351 VersionTracker version_tracker;
3352
3353 if (!version_tracker.init(this)) {
3354 return false;
3355 }
3356
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003357#if !defined(__LP64__)
3358 if (has_text_relocations) {
Elliott Hughes5bc78c82016-11-16 11:35:43 -08003359 // Fail if app is targeting M or above.
Adrian DCc8145ab2016-08-27 15:09:36 +02003360#if defined(TARGET_NEEDS_PLATFORM_TEXT_RELOCATIONS)
3361 if (get_application_target_sdk_version() != __ANDROID_API__
3362 && get_application_target_sdk_version() >= __ANDROID_API_M__) {
3363#else
Elliott Hughes5bc78c82016-11-16 11:35:43 -08003364 if (get_application_target_sdk_version() >= __ANDROID_API_M__) {
Adrian DCc8145ab2016-08-27 15:09:36 +02003365#endif
Elliott Hughes763f6e12017-04-10 09:52:33 -07003366 DL_ERR_AND_LOG("\"%s\" has text relocations (https://android.googlesource.com/platform/"
3367 "bionic/+/master/android-changes-for-ndk-developers.md#Text-Relocations-"
3368 "Enforced-for-API-level-23)", get_realpath());
Dmitriy Ivanove4ad91f2015-06-12 15:00:31 -07003369 return false;
3370 }
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003371 // Make segments writable to allow text relocations to work properly. We will later call
Dmitriy Ivanov7e039932015-10-01 14:02:19 -07003372 // phdr_table_protect_segments() after all of them are applied.
Elliott Hughes763f6e12017-04-10 09:52:33 -07003373 DL_WARN("\"%s\" has text relocations (https://android.googlesource.com/platform/"
3374 "bionic/+/master/android-changes-for-ndk-developers.md#Text-Relocations-Enforced-"
3375 "for-API-level-23)", get_realpath());
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07003376 add_dlwarning(get_realpath(), "text relocations");
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003377 if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
3378 DL_ERR("can't unprotect loadable segments for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003379 get_realpath(), strerror(errno));
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003380 return false;
3381 }
3382 }
3383#endif
3384
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003385 if (android_relocs_ != nullptr) {
3386 // check signature
3387 if (android_relocs_size_ > 3 &&
3388 android_relocs_[0] == 'A' &&
3389 android_relocs_[1] == 'P' &&
Dmitriy Ivanov18870d32015-04-22 13:10:04 -07003390 android_relocs_[2] == 'S' &&
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003391 android_relocs_[3] == '2') {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003392 DEBUG("[ android relocating %s ]", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003393
3394 bool relocated = false;
3395 const uint8_t* packed_relocs = android_relocs_ + 4;
3396 const size_t packed_relocs_size = android_relocs_size_ - 4;
3397
Dmitriy Ivanov18870d32015-04-22 13:10:04 -07003398 relocated = relocate(
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003399 version_tracker,
Dmitriy Ivanov18870d32015-04-22 13:10:04 -07003400 packed_reloc_iterator<sleb128_decoder>(
3401 sleb128_decoder(packed_relocs, packed_relocs_size)),
3402 global_group, local_group);
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003403
3404 if (!relocated) {
3405 return false;
3406 }
3407 } else {
3408 DL_ERR("bad android relocation header.");
3409 return false;
3410 }
3411 }
3412
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07003413#if defined(USE_RELA)
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003414 if (rela_ != nullptr) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003415 DEBUG("[ relocating %s ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003416 if (!relocate(version_tracker,
3417 plain_reloc_iterator(rela_, rela_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003418 return false;
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07003419 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003420 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003421 if (plt_rela_ != nullptr) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003422 DEBUG("[ relocating %s plt ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003423 if (!relocate(version_tracker,
3424 plain_reloc_iterator(plt_rela_, plt_rela_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003425 return false;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003426 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003427 }
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07003428#else
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003429 if (rel_ != nullptr) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003430 DEBUG("[ relocating %s ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003431 if (!relocate(version_tracker,
3432 plain_reloc_iterator(rel_, rel_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003433 return false;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003434 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003435 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003436 if (plt_rel_ != nullptr) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003437 DEBUG("[ relocating %s plt ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003438 if (!relocate(version_tracker,
3439 plain_reloc_iterator(plt_rel_, plt_rel_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003440 return false;
Brigid Smithc5a13ef2014-07-23 11:22:25 -07003441 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003442 }
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07003443#endif
Brigid Smithc5a13ef2014-07-23 11:22:25 -07003444
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07003445#if defined(__mips__)
Dmitriy Ivanovf39cb632015-04-30 20:17:03 -07003446 if (!mips_relocate_got(version_tracker, global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003447 return false;
3448 }
Raghu Gandhamd7daacb2012-07-31 12:07:22 -07003449#endif
3450
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003451 DEBUG("[ finished linking %s ]", get_realpath());
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003452
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003453#if !defined(__LP64__)
3454 if (has_text_relocations) {
3455 // All relocations are done, we can protect our segments back to read-only.
3456 if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
3457 DL_ERR("can't protect segments for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003458 get_realpath(), strerror(errno));
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003459 return false;
3460 }
3461 }
3462#endif
3463
Mingwei Shibe910522015-11-12 07:02:14 +00003464 // We can also turn on GNU RELRO protection if we're not linking the dynamic linker
3465 // itself --- it can't make system calls yet, and will have to call protect_relro later.
3466 if (!is_linker() && !protect_relro()) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003467 return false;
3468 }
Nick Kralevich9ec0f032012-02-28 10:40:00 -08003469
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003470 /* Handle serializing/sharing the RELRO segment */
3471 if (extinfo && (extinfo->flags & ANDROID_DLEXT_WRITE_RELRO)) {
3472 if (phdr_table_serialize_gnu_relro(phdr, phnum, load_bias,
3473 extinfo->relro_fd) < 0) {
3474 DL_ERR("failed serializing GNU RELRO section for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003475 get_realpath(), strerror(errno));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003476 return false;
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +00003477 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003478 } else if (extinfo && (extinfo->flags & ANDROID_DLEXT_USE_RELRO)) {
3479 if (phdr_table_map_gnu_relro(phdr, phnum, load_bias,
3480 extinfo->relro_fd) < 0) {
3481 DL_ERR("failed mapping GNU RELRO section for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003482 get_realpath(), strerror(errno));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003483 return false;
3484 }
3485 }
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +00003486
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003487 notify_gdb_of_load(this);
3488 return true;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003489}
3490
Mingwei Shibe910522015-11-12 07:02:14 +00003491bool soinfo::protect_relro() {
3492 if (phdr_table_protect_gnu_relro(phdr, phnum, load_bias) < 0) {
3493 DL_ERR("can't enable GNU RELRO protection for \"%s\": %s",
3494 get_realpath(), strerror(errno));
3495 return false;
3496 }
3497 return true;
3498}
3499
Dimitry Ivanov4cabfaa2017-03-07 11:19:05 -08003500static void init_default_namespace_no_config(bool is_asan) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003501 g_default_namespace.set_isolated(false);
Dimitry Ivanov77ad6422017-03-06 13:02:29 -08003502 auto default_ld_paths = is_asan ? kAsanDefaultLdPaths : kDefaultLdPaths;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003503
neo.chae2589f9d2016-10-04 11:00:27 +09003504 char real_path[PATH_MAX];
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003505 std::vector<std::string> ld_default_paths;
Dimitry Ivanov77ad6422017-03-06 13:02:29 -08003506 for (size_t i = 0; default_ld_paths[i] != nullptr; ++i) {
3507 if (realpath(default_ld_paths[i], real_path) != nullptr) {
neo.chae2589f9d2016-10-04 11:00:27 +09003508 ld_default_paths.push_back(real_path);
3509 } else {
Dimitry Ivanov77ad6422017-03-06 13:02:29 -08003510 ld_default_paths.push_back(default_ld_paths[i]);
neo.chae2589f9d2016-10-04 11:00:27 +09003511 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003512 }
3513
3514 g_default_namespace.set_default_library_paths(std::move(ld_default_paths));
Dimitry Ivanov4cabfaa2017-03-07 11:19:05 -08003515}
3516
3517void init_default_namespace(const char* executable_path) {
3518 g_default_namespace.set_name("(default)");
3519
3520 soinfo* somain = solist_get_somain();
3521
3522 const char *interp = phdr_table_get_interpreter_name(somain->phdr, somain->phnum,
3523 somain->load_bias);
3524 const char* bname = basename(interp);
3525
3526 g_is_asan = bname != nullptr &&
3527 (strcmp(bname, "linker_asan") == 0 ||
3528 strcmp(bname, "linker_asan64") == 0);
3529
3530 const Config* config = nullptr;
3531
3532 std::string error_msg;
3533
3534 if (!Config::read_binary_config(kLdConfigFilePath,
3535 executable_path,
3536 g_is_asan,
3537 &config,
3538 &error_msg)) {
3539 if (!error_msg.empty()) {
3540 DL_WARN("error reading config file \"%s\" for \"%s\" (will use default configuration): %s",
3541 kLdConfigFilePath,
3542 executable_path,
3543 error_msg.c_str());
3544 }
3545 config = nullptr;
3546 }
3547
3548 if (config == nullptr) {
3549 init_default_namespace_no_config(g_is_asan);
3550 return;
3551 }
3552
3553 const auto& namespace_configs = config->namespace_configs();
3554 std::unordered_map<std::string, android_namespace_t*> namespaces;
3555
3556 // 1. Initialize default namespace
3557 const NamespaceConfig* default_ns_config = config->default_namespace_config();
3558
3559 g_default_namespace.set_isolated(default_ns_config->isolated());
3560 g_default_namespace.set_default_library_paths(default_ns_config->search_paths());
3561 g_default_namespace.set_permitted_paths(default_ns_config->permitted_paths());
3562
3563 namespaces[default_ns_config->name()] = &g_default_namespace;
3564
3565 // 2. Initialize other namespaces
3566
3567 for (auto& ns_config : namespace_configs) {
3568 if (namespaces.find(ns_config->name()) != namespaces.end()) {
3569 continue;
3570 }
3571
3572 android_namespace_t* ns = new (g_namespace_allocator.alloc()) android_namespace_t();
3573 ns->set_name(ns_config->name());
3574 ns->set_isolated(ns_config->isolated());
3575 ns->set_default_library_paths(ns_config->search_paths());
3576 ns->set_permitted_paths(ns_config->permitted_paths());
3577
3578 namespaces[ns_config->name()] = ns;
Jiyong Park01de74e2017-04-03 23:10:37 +09003579 if (ns_config->visible()) {
3580 g_exported_namespaces[ns_config->name()] = ns;
3581 }
Dimitry Ivanov4cabfaa2017-03-07 11:19:05 -08003582 }
3583
3584 // 3. Establish links between namespaces
3585 for (auto& ns_config : namespace_configs) {
3586 auto it_from = namespaces.find(ns_config->name());
3587 CHECK(it_from != namespaces.end());
3588 android_namespace_t* namespace_from = it_from->second;
3589 for (const NamespaceLinkConfig& ns_link : ns_config->links()) {
3590 auto it_to = namespaces.find(ns_link.ns_name());
3591 CHECK(it_to != namespaces.end());
3592 android_namespace_t* namespace_to = it_to->second;
3593 link_namespaces(namespace_from, namespace_to, ns_link.shared_libs().c_str());
3594 }
3595 }
3596 // we can no longer rely on the fact that libdl.so is part of default namespace
3597 // this is why we want to add ld-android.so to all namespaces from ld.config.txt
3598 soinfo* ld_android_so = solist_get_head();
3599 for (auto it : namespaces) {
3600 it.second->add_soinfo(ld_android_so);
3601 // TODO (dimitry): somain and ld_preloads should probably be added to all of these namespaces too?
3602 }
3603
3604 set_application_target_sdk_version(config->target_sdk_version());
3605}
Jiyong Park01de74e2017-04-03 23:10:37 +09003606
3607// This function finds a namespace exported in ld.config.txt by its name.
3608// A namespace can be exported by setting .visible property to true.
3609android_namespace_t* get_exported_namespace(const char* name) {
3610 if (name == nullptr) {
3611 return nullptr;
3612 }
3613 auto it = g_exported_namespaces.find(std::string(name));
3614 if (it == g_exported_namespaces.end()) {
3615 return nullptr;
3616 }
3617 return it->second;
3618}