blob: c78b9aba66528104a20f4605ed3c8971996f0952 [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
Logan Chiendd184722018-05-08 20:17:26 +080047#include <android-base/properties.h>
Tom Cherryb8ab6182017-04-05 16:20:29 -070048#include <android-base/scopeguard.h>
49
Christopher Ferris7a3681e2017-04-24 17:48:32 -070050#include <async_safe/log.h>
51
Elliott Hughes46882792012-08-03 16:49:39 -070052// Private C library headers.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080053
54#include "linker.h"
Dmitriy Ivanovc9ce70d2015-03-10 15:30:26 -070055#include "linker_block_allocator.h"
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -070056#include "linker_cfi.h"
Dimitry Ivanov4cabfaa2017-03-07 11:19:05 -080057#include "linker_config.h"
Dimitry Ivanov6b788ee2016-02-17 16:08:03 -080058#include "linker_gdb_support.h"
Dimitry Ivanov48ec2882016-08-04 11:50:36 -070059#include "linker_globals.h"
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080060#include "linker_debug.h"
Dimitry Ivanov769b33f2016-07-21 11:33:40 -070061#include "linker_dlwarning.h"
Dimitry Ivanov3f660572016-09-09 10:00:39 -070062#include "linker_main.h"
Dimitry Ivanovb943f302016-08-03 16:00:10 -070063#include "linker_namespaces.h"
Dmitriy Ivanov18870d32015-04-22 13:10:04 -070064#include "linker_sleb128.h"
David 'Digit' Turner23363ed2012-06-18 18:13:49 +020065#include "linker_phdr.h"
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -080066#include "linker_relocs.h"
Dmitriy Ivanovfa26eee2015-02-03 16:06:47 -080067#include "linker_reloc_iterators.h"
Dmitriy Ivanova1feb112015-10-01 18:41:57 -070068#include "linker_utils.h"
tony.ys_liub4474402015-07-29 18:00:22 +080069
dimitryfe1b27c2017-08-11 14:43:21 +020070#include "android-base/macros.h"
Elliott Hughes939a7e02015-12-04 15:27:46 -080071#include "android-base/strings.h"
Dimitry Ivanovb996d602016-07-11 18:11:39 -070072#include "android-base/stringprintf.h"
Simon Baldwinaef71952015-01-16 13:22:54 +000073#include "ziparchive/zip_archive.h"
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080074
Elliott Hughes1801db32015-06-08 18:04:00 -070075// Override macros to use C++ style casts.
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -080076#undef ELF_ST_TYPE
77#define ELF_ST_TYPE(x) (static_cast<uint32_t>(x) & 0xf)
78
dimitry06016f22018-01-05 11:39:28 +010079static std::unordered_map<void*, size_t> g_dso_handle_counters;
80
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -070081static android_namespace_t* g_anonymous_namespace = &g_default_namespace;
Jiyong Park01de74e2017-04-03 23:10:37 +090082static std::unordered_map<std::string, android_namespace_t*> g_exported_namespaces;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -070083
Dmitriy Ivanov600bc3c2015-03-10 15:43:50 -070084static LinkerTypeAllocator<soinfo> g_soinfo_allocator;
85static LinkerTypeAllocator<LinkedListEntry<soinfo>> g_soinfo_links_allocator;
Magnus Malmbornba98d922012-09-12 13:00:55 +020086
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -070087static LinkerTypeAllocator<android_namespace_t> g_namespace_allocator;
Dimitry Ivanovaca299a2016-04-11 12:42:58 -070088static LinkerTypeAllocator<LinkedListEntry<android_namespace_t>> g_namespace_list_allocator;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -070089
dimitryfe1b27c2017-08-11 14:43:21 +020090static const char* const kLdConfigArchFilePath = "/system/etc/ld.config." ABI_STRING ".txt";
91
Dimitry Ivanov4cabfaa2017-03-07 11:19:05 -080092static const char* const kLdConfigFilePath = "/system/etc/ld.config.txt";
Logan Chiendd184722018-05-08 20:17:26 +080093static const char* const kLdConfigVndkLiteFilePath = "/system/etc/ld.config.vndk_lite.txt";
Dimitry Ivanov4cabfaa2017-03-07 11:19:05 -080094
Elliott Hughes4eeb1f12013-10-25 17:38:02 -070095#if defined(__LP64__)
Dimitry Ivanova1446972017-03-17 00:08:23 +000096static const char* const kSystemLibDir = "/system/lib64";
Alin Jerpelea074a9fd2017-09-25 17:47:49 +020097static const char* const kOdmLibDir = "/odm/lib64";
Dimitry Ivanova1446972017-03-17 00:08:23 +000098static const char* const kVendorLibDir = "/vendor/lib64";
Vishwath Mohan4113def2017-03-29 15:31:34 -070099static const char* const kAsanSystemLibDir = "/data/asan/system/lib64";
Alin Jerpelea074a9fd2017-09-25 17:47:49 +0200100static const char* const kAsanOdmLibDir = "/data/asan/odm/lib64";
Vishwath Mohan4113def2017-03-29 15:31:34 -0700101static const char* const kAsanVendorLibDir = "/data/asan/vendor/lib64";
Elliott Hughes011bc0b2013-10-08 14:27:10 -0700102#else
Dimitry Ivanova1446972017-03-17 00:08:23 +0000103static const char* const kSystemLibDir = "/system/lib";
Alin Jerpelea074a9fd2017-09-25 17:47:49 +0200104static const char* const kOdmLibDir = "/odm/lib";
Dimitry Ivanova1446972017-03-17 00:08:23 +0000105static const char* const kVendorLibDir = "/vendor/lib";
Vishwath Mohan4113def2017-03-29 15:31:34 -0700106static const char* const kAsanSystemLibDir = "/data/asan/system/lib";
Alin Jerpelea074a9fd2017-09-25 17:47:49 +0200107static const char* const kAsanOdmLibDir = "/data/asan/odm/lib";
Vishwath Mohan4113def2017-03-29 15:31:34 -0700108static const char* const kAsanVendorLibDir = "/data/asan/vendor/lib";
Elliott Hughes011bc0b2013-10-08 14:27:10 -0700109#endif
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700110
Vishwath Mohan4113def2017-03-29 15:31:34 -0700111static const char* const kAsanLibDirPrefix = "/data/asan";
112
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700113static const char* const kDefaultLdPaths[] = {
114 kSystemLibDir,
Alin Jerpelea074a9fd2017-09-25 17:47:49 +0200115 kOdmLibDir,
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700116 kVendorLibDir,
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700117 nullptr
Elliott Hughes124fae92012-10-31 14:20:03 -0700118};
David Bartleybc3a5c22009-06-02 18:27:28 -0700119
Evgenii Stepanovd640b222015-07-10 17:54:01 -0700120static const char* const kAsanDefaultLdPaths[] = {
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700121 kAsanSystemLibDir,
122 kSystemLibDir,
Alin Jerpelea074a9fd2017-09-25 17:47:49 +0200123 kAsanOdmLibDir,
124 kOdmLibDir,
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700125 kAsanVendorLibDir,
126 kVendorLibDir,
Evgenii Stepanovd640b222015-07-10 17:54:01 -0700127 nullptr
128};
129
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700130// Is ASAN enabled?
131static bool g_is_asan = false;
132
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -0700133static CFIShadowWriter g_cfi_shadow;
134
135CFIShadowWriter* get_cfi_shadow() {
136 return &g_cfi_shadow;
137}
138
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700139static bool is_system_library(const std::string& realpath) {
140 for (const auto& dir : g_default_namespace.get_default_library_paths()) {
141 if (file_is_in_dir(realpath, dir)) {
142 return true;
143 }
144 }
145 return false;
146}
147
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700148// Checks if the file exists and not a directory.
149static bool file_exists(const char* path) {
Dimitry Ivanov4cf70242016-08-11 11:11:52 -0700150 struct stat s;
151
152 if (stat(path, &s) != 0) {
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700153 return false;
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700154 }
Dimitry Ivanov4cf70242016-08-11 11:11:52 -0700155
156 return S_ISREG(s.st_mode);
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -0700157}
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700158
Dimitry Ivanov35c8e3b2017-02-27 12:17:47 -0800159static std::string resolve_soname(const std::string& name) {
160 // We assume that soname equals to basename here
161
162 // TODO(dimitry): consider having honest absolute-path -> soname resolution
163 // note that since we might end up refusing to load this library because
164 // it is not in shared libs list we need to get the soname without actually loading
165 // the library.
166 //
167 // On the other hand there are several places where we already assume that
168 // soname == basename in particular for any not-loaded library mentioned
169 // in DT_NEEDED list.
170 return basename(name.c_str());
171}
172
173static bool maybe_accessible_via_namespace_links(android_namespace_t* ns, const char* name) {
174 std::string soname = resolve_soname(name);
175 for (auto& ns_link : ns->linked_namespaces()) {
176 if (ns_link.is_accessible(soname.c_str())) {
177 return true;
178 }
179 }
180
181 return false;
182}
183
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700184// TODO(dimitry): The grey-list is a workaround for http://b/26394120 ---
185// gradually remove libraries from this list until it is gone.
Dimitry Ivanov35c8e3b2017-02-27 12:17:47 -0800186static bool is_greylisted(android_namespace_t* ns, const char* name, const soinfo* needed_by) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700187 static const char* const kLibraryGreyList[] = {
188 "libandroid_runtime.so",
189 "libbinder.so",
190 "libcrypto.so",
191 "libcutils.so",
192 "libexpat.so",
193 "libgui.so",
194 "libmedia.so",
195 "libnativehelper.so",
196 "libskia.so",
197 "libssl.so",
198 "libstagefright.so",
199 "libsqlite.so",
200 "libui.so",
201 "libutils.so",
202 "libvorbisidec.so",
203 nullptr
204 };
205
Elliott Hughes5bc78c82016-11-16 11:35:43 -0800206 // If you're targeting N, you don't get the greylist.
Elliott Hughes9e27e582017-03-23 17:42:49 -0700207 if (g_greylist_disabled || get_application_target_sdk_version() >= __ANDROID_API_N__) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700208 return false;
209 }
210
211 // if the library needed by a system library - implicitly assume it
Dimitry Ivanov35c8e3b2017-02-27 12:17:47 -0800212 // is greylisted unless it is in the list of shared libraries for one or
213 // more linked namespaces
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700214 if (needed_by != nullptr && is_system_library(needed_by->get_realpath())) {
Dimitry Ivanov35c8e3b2017-02-27 12:17:47 -0800215 return !maybe_accessible_via_namespace_links(ns, name);
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700216 }
217
218 // if this is an absolute path - make sure it points to /system/lib(64)
219 if (name[0] == '/' && dirname(name) == kSystemLibDir) {
220 // and reduce the path to basename
221 name = basename(name);
222 }
223
224 for (size_t i = 0; kLibraryGreyList[i] != nullptr; ++i) {
225 if (strcmp(name, kLibraryGreyList[i]) == 0) {
226 return true;
227 }
228 }
229
230 return false;
231}
232// END OF WORKAROUND
233
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700234static std::vector<std::string> g_ld_preload_names;
Elliott Hughesa4aafd12014-01-13 16:37:47 -0800235
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800236static bool g_anonymous_namespace_initialized;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700237
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800238#if STATS
Elliott Hughesbedfe382012-08-14 14:07:59 -0700239struct linker_stats_t {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700240 int count[kRelocMax];
Elliott Hughesbedfe382012-08-14 14:07:59 -0700241};
242
243static linker_stats_t linker_stats;
244
Dmitriy Ivanov114ff692015-01-14 11:36:38 -0800245void count_relocation(RelocationKind kind) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700246 ++linker_stats.count[kind];
Elliott Hughesbedfe382012-08-14 14:07:59 -0700247}
248#else
Dmitriy Ivanov114ff692015-01-14 11:36:38 -0800249void count_relocation(RelocationKind) {
Elliott Hughesbedfe382012-08-14 14:07:59 -0700250}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800251#endif
252
253#if COUNT_PAGES
Dmitriy Ivanov114ff692015-01-14 11:36:38 -0800254uint32_t bitmask[4096];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800255#endif
256
Elliott Hughesbedfe382012-08-14 14:07:59 -0700257static void notify_gdb_of_load(soinfo* info) {
Dimitry Ivanove97d8ed2016-03-01 15:55:56 -0800258 if (info->is_linker() || info->is_main_executable()) {
259 // gdb already knows about the linker and the main executable.
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700260 return;
261 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800262
Dimitry Ivanov6b788ee2016-02-17 16:08:03 -0800263 link_map* map = &(info->link_map_head);
Nicolas Geoffray0fa54102016-02-18 09:31:24 +0000264
Dimitry Ivanov6b788ee2016-02-17 16:08:03 -0800265 map->l_addr = info->load_bias;
266 // link_map l_name field is not const.
267 map->l_name = const_cast<char*>(info->get_realpath());
268 map->l_ld = info->dynamic;
Nicolas Geoffray0fa54102016-02-18 09:31:24 +0000269
Dimitry Ivanove97d8ed2016-03-01 15:55:56 -0800270 CHECK(map->l_name != nullptr);
271 CHECK(map->l_name[0] != '\0');
272
Dimitry Ivanov6b788ee2016-02-17 16:08:03 -0800273 notify_gdb_of_load(map);
Iliyan Malchev5e12d7e2009-03-24 19:02:00 -0700274}
275
Elliott Hughesbedfe382012-08-14 14:07:59 -0700276static void notify_gdb_of_unload(soinfo* info) {
Dimitry Ivanov6b788ee2016-02-17 16:08:03 -0800277 notify_gdb_of_unload(&(info->link_map_head));
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800278}
279
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -0700280LinkedListEntry<soinfo>* SoinfoListAllocator::alloc() {
281 return g_soinfo_links_allocator.alloc();
282}
283
284void SoinfoListAllocator::free(LinkedListEntry<soinfo>* entry) {
285 g_soinfo_links_allocator.free(entry);
286}
287
Dimitry Ivanovaca299a2016-04-11 12:42:58 -0700288LinkedListEntry<android_namespace_t>* NamespaceListAllocator::alloc() {
289 return g_namespace_list_allocator.alloc();
290}
291
292void NamespaceListAllocator::free(LinkedListEntry<android_namespace_t>* entry) {
293 g_namespace_list_allocator.free(entry);
294}
295
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700296soinfo* soinfo_alloc(android_namespace_t* ns, const char* name,
297 struct stat* file_stat, off64_t file_offset,
298 uint32_t rtld_flags) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700299 if (strlen(name) >= PATH_MAX) {
Elliott Hughes7b0af7a2017-09-15 16:09:22 -0700300 async_safe_fatal("library name \"%s\" too long", name);
Magnus Malmbornba98d922012-09-12 13:00:55 +0200301 }
302
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700303 TRACE("name %s: allocating soinfo for ns=%p", name, ns);
304
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700305 soinfo* si = new (g_soinfo_allocator.alloc()) soinfo(ns, name, file_stat,
306 file_offset, rtld_flags);
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -0700307
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700308 solist_add_soinfo(si);
Magnus Malmbornba98d922012-09-12 13:00:55 +0200309
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -0700310 si->generate_handle();
311 ns->add_soinfo(si);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700312
Elliott Hughesca0c11b2013-03-12 10:40:45 -0700313 TRACE("name %s: allocated soinfo @ %p", name, si);
Magnus Malmbornba98d922012-09-12 13:00:55 +0200314 return si;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800315}
316
Elliott Hughesfaf05ba2014-02-11 16:59:37 -0800317static void soinfo_free(soinfo* si) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700318 if (si == nullptr) {
319 return;
320 }
321
322 if (si->base != 0 && si->size != 0) {
Dimitry Ivanovf45b0e92016-01-15 11:13:35 -0800323 if (!si->is_mapped_by_caller()) {
324 munmap(reinterpret_cast<void*>(si->base), si->size);
325 } else {
326 // remap the region as PROT_NONE, MAP_ANONYMOUS | MAP_NORESERVE
327 mmap(reinterpret_cast<void*>(si->base), si->size, PROT_NONE,
328 MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
329 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700330 }
331
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700332 TRACE("name %s: freeing soinfo @ %p", si->get_realpath(), si);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700333
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700334 if (!solist_remove_soinfo(si)) {
dimitry965d06d2017-11-28 16:03:07 +0100335 async_safe_fatal("soinfo=%p is not in soinfo_list (double unload?)", si);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700336 }
Elliott Hughes46882792012-08-03 16:49:39 -0700337
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700338 // clear links to/from si
339 si->remove_all_links();
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -0700340
Dmitriy Ivanov609f11b2015-07-08 15:26:46 -0700341 si->~soinfo();
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700342 g_soinfo_allocator.free(si);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800343}
344
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700345static void parse_path(const char* path, const char* delimiters,
346 std::vector<std::string>* resolved_paths) {
347 std::vector<std::string> paths;
348 split_path(path, delimiters, &paths);
349 resolve_paths(paths, resolved_paths);
350}
351
Elliott Hughescade4c32012-12-20 14:42:14 -0800352static void parse_LD_LIBRARY_PATH(const char* path) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700353 std::vector<std::string> ld_libary_paths;
354 parse_path(path, ":", &ld_libary_paths);
355 g_default_namespace.set_ld_library_paths(std::move(ld_libary_paths));
Elliott Hughescade4c32012-12-20 14:42:14 -0800356}
357
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700358static bool realpath_fd(int fd, std::string* realpath) {
359 std::vector<char> buf(PATH_MAX), proc_self_fd(PATH_MAX);
Christopher Ferris7a3681e2017-04-24 17:48:32 -0700360 async_safe_format_buffer(&proc_self_fd[0], proc_self_fd.size(), "/proc/self/fd/%d", fd);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700361 if (readlink(&proc_self_fd[0], &buf[0], buf.size()) == -1) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700362 PRINT("readlink(\"%s\") failed: %s [fd=%d]", &proc_self_fd[0], strerror(errno), fd);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700363 return false;
364 }
365
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700366 *realpath = &buf[0];
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700367 return true;
368}
369
Elliott Hughes4eeb1f12013-10-25 17:38:02 -0700370#if defined(__arm__)
Elliott Hughes46882792012-08-03 16:49:39 -0700371
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700372// For a given PC, find the .so that it belongs to.
373// Returns the base address of the .ARM.exidx section
374// for that .so, and the number of 8-byte entries
375// in that section (via *pcount).
376//
377// Intended to be called by libc's __gnu_Unwind_Find_exidx().
Dimitry Ivanovd9e427c2016-11-22 16:55:25 -0800378_Unwind_Ptr do_dl_unwind_find_exidx(_Unwind_Ptr pc, int* pcount) {
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700379 for (soinfo* si = solist_get_head(); si != 0; si = si->next) {
Elliott Hughesf2c6ad62017-04-21 10:25:56 -0700380 if ((pc >= si->base) && (pc < (si->base + si->size))) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700381 *pcount = si->ARM_exidx_count;
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -0800382 return reinterpret_cast<_Unwind_Ptr>(si->ARM_exidx);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800383 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700384 }
385 *pcount = 0;
Elliott Hughesf2c6ad62017-04-21 10:25:56 -0700386 return 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800387}
Elliott Hughes46882792012-08-03 16:49:39 -0700388
Christopher Ferris24053a42013-08-19 17:45:09 -0700389#endif
Elliott Hughes46882792012-08-03 16:49:39 -0700390
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700391// Here, we only have to provide a callback to iterate across all the
392// loaded libraries. gcc_eh does the rest.
Dmitriy Ivanov7271caf2015-06-29 14:48:25 -0700393int do_dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void* data) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700394 int rv = 0;
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700395 for (soinfo* si = solist_get_head(); si != nullptr; si = si->next) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700396 dl_phdr_info dl_info;
397 dl_info.dlpi_addr = si->link_map_head.l_addr;
398 dl_info.dlpi_name = si->link_map_head.l_name;
399 dl_info.dlpi_phdr = si->phdr;
400 dl_info.dlpi_phnum = si->phnum;
401 rv = cb(&dl_info, sizeof(dl_phdr_info), data);
402 if (rv != 0) {
403 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800404 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700405 }
406 return rv;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800407}
Elliott Hughes46882792012-08-03 16:49:39 -0700408
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800409
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700410bool soinfo_do_lookup(soinfo* si_from, const char* name, const version_info* vi,
Dimitry Ivanovb943f302016-08-03 16:00:10 -0700411 soinfo** si_found_in, const soinfo_list_t& global_group,
412 const soinfo_list_t& local_group, const ElfW(Sym)** symbol) {
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800413 SymbolName symbol_name(name);
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700414 const ElfW(Sym)* s = nullptr;
Iliyan Malchev6ed80c82009-09-28 19:38:04 -0700415
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -0700416 /* "This element's presence in a shared object library alters the dynamic linker's
417 * symbol resolution algorithm for references within the library. Instead of starting
418 * a symbol search with the executable file, the dynamic linker starts from the shared
419 * object itself. If the shared object fails to supply the referenced symbol, the
420 * dynamic linker then searches the executable file and other shared objects as usual."
421 *
422 * http://www.sco.com/developers/gabi/2012-12-31/ch5.dynamic.html
423 *
424 * Note that this is unlikely since static linker avoids generating
425 * relocations for -Bsymbolic linked dynamic executables.
426 */
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700427 if (si_from->has_DT_SYMBOLIC) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700428 DEBUG("%s: looking up %s in local scope (DT_SYMBOLIC)", si_from->get_realpath(), name);
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700429 if (!si_from->find_symbol_by_name(symbol_name, vi, &s)) {
430 return false;
431 }
432
Dmitriy Ivanov8f61d992014-09-16 14:31:06 -0700433 if (s != nullptr) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700434 *si_found_in = si_from;
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -0700435 }
436 }
437
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700438 // 1. Look for it in global_group
439 if (s == nullptr) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700440 bool error = false;
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700441 global_group.visit([&](soinfo* global_si) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700442 DEBUG("%s: looking up %s in %s (from global group)",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700443 si_from->get_realpath(), name, global_si->get_realpath());
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700444 if (!global_si->find_symbol_by_name(symbol_name, vi, &s)) {
445 error = true;
446 return false;
447 }
448
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -0700449 if (s != nullptr) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700450 *si_found_in = global_si;
451 return false;
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -0700452 }
Dmitriy Ivanovc2048942014-08-29 10:15:25 -0700453
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700454 return true;
455 });
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700456
457 if (error) {
458 return false;
459 }
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -0700460 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700461
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700462 // 2. Look for it in the local group
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700463 if (s == nullptr) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700464 bool error = false;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700465 local_group.visit([&](soinfo* local_si) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700466 if (local_si == si_from && si_from->has_DT_SYMBOLIC) {
Dmitriy Ivanove47b3f82014-10-23 14:19:07 -0700467 // we already did this - skip
468 return true;
469 }
470
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700471 DEBUG("%s: looking up %s in %s (from local group)",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700472 si_from->get_realpath(), name, local_si->get_realpath());
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700473 if (!local_si->find_symbol_by_name(symbol_name, vi, &s)) {
474 error = true;
475 return false;
476 }
477
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700478 if (s != nullptr) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700479 *si_found_in = local_si;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700480 return false;
481 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700482
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700483 return true;
484 });
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700485
486 if (error) {
487 return false;
488 }
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700489 }
490
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700491 if (s != nullptr) {
492 TRACE_TYPE(LOOKUP, "si %s sym %s s->st_value = %p, "
493 "found in %s, base = %p, load bias = %p",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700494 si_from->get_realpath(), name, reinterpret_cast<void*>(s->st_value),
495 (*si_found_in)->get_realpath(), reinterpret_cast<void*>((*si_found_in)->base),
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700496 reinterpret_cast<void*>((*si_found_in)->load_bias));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700497 }
Iliyan Malchev6ed80c82009-09-28 19:38:04 -0700498
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700499 *symbol = s;
500 return true;
Iliyan Malchev6ed80c82009-09-28 19:38:04 -0700501}
502
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700503ProtectedDataGuard::ProtectedDataGuard() {
504 if (ref_count_++ == 0) {
505 protect_data(PROT_READ | PROT_WRITE);
506 }
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700507
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700508 if (ref_count_ == 0) { // overflow
Christopher Ferris7a3681e2017-04-24 17:48:32 -0700509 async_safe_fatal("Too many nested calls to dlopen()");
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -0800510 }
Dimitry Ivanov68e6c032017-02-01 12:55:11 -0800511}
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -0800512
Dimitry Ivanov68e6c032017-02-01 12:55:11 -0800513ProtectedDataGuard::~ProtectedDataGuard() {
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700514 if (--ref_count_ == 0) {
515 protect_data(PROT_READ);
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -0800516 }
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700517}
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -0800518
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700519void ProtectedDataGuard::protect_data(int protection) {
520 g_soinfo_allocator.protect_all(protection);
521 g_soinfo_links_allocator.protect_all(protection);
522 g_namespace_allocator.protect_all(protection);
523 g_namespace_list_allocator.protect_all(protection);
524}
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -0800525
526size_t ProtectedDataGuard::ref_count_ = 0;
527
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700528// Each size has it's own allocator.
529template<size_t size>
530class SizeBasedAllocator {
531 public:
532 static void* alloc() {
533 return allocator_.alloc();
534 }
Dmitriy Ivanov4bea4982014-08-29 14:01:48 -0700535
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700536 static void free(void* ptr) {
537 allocator_.free(ptr);
538 }
Dmitriy Ivanov4bea4982014-08-29 14:01:48 -0700539
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700540 private:
541 static LinkerBlockAllocator allocator_;
542};
543
544template<size_t size>
545LinkerBlockAllocator SizeBasedAllocator<size>::allocator_(size);
546
547template<typename T>
548class TypeBasedAllocator {
549 public:
550 static T* alloc() {
551 return reinterpret_cast<T*>(SizeBasedAllocator<sizeof(T)>::alloc());
552 }
553
554 static void free(T* ptr) {
555 SizeBasedAllocator<sizeof(T)>::free(ptr);
556 }
557};
558
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700559class LoadTask {
560 public:
561 struct deleter_t {
562 void operator()(LoadTask* t) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700563 t->~LoadTask();
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700564 TypeBasedAllocator<LoadTask>::free(t);
565 }
566 };
567
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700568 static deleter_t deleter;
569
Dimitry Ivanov7d429d32017-02-01 15:28:52 -0800570 static LoadTask* create(const char* name,
571 soinfo* needed_by,
Jiyong Park02586a22017-05-20 01:01:24 +0900572 android_namespace_t* start_from,
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700573 std::unordered_map<const soinfo*, ElfReader>* readers_map) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700574 LoadTask* ptr = TypeBasedAllocator<LoadTask>::alloc();
Jiyong Park02586a22017-05-20 01:01:24 +0900575 return new (ptr) LoadTask(name, needed_by, start_from, readers_map);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700576 }
577
578 const char* get_name() const {
579 return name_;
580 }
581
582 soinfo* get_needed_by() const {
583 return needed_by_;
584 }
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700585
586 soinfo* get_soinfo() const {
587 return si_;
588 }
589
590 void set_soinfo(soinfo* si) {
591 si_ = si;
592 }
593
594 off64_t get_file_offset() const {
595 return file_offset_;
596 }
597
598 void set_file_offset(off64_t offset) {
599 file_offset_ = offset;
600 }
601
602 int get_fd() const {
603 return fd_;
604 }
605
606 void set_fd(int fd, bool assume_ownership) {
607 fd_ = fd;
608 close_fd_ = assume_ownership;
609 }
610
611 const android_dlextinfo* get_extinfo() const {
612 return extinfo_;
613 }
614
615 void set_extinfo(const android_dlextinfo* extinfo) {
616 extinfo_ = extinfo;
617 }
618
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700619 bool is_dt_needed() const {
620 return is_dt_needed_;
621 }
622
623 void set_dt_needed(bool is_dt_needed) {
624 is_dt_needed_ = is_dt_needed;
625 }
626
Jiyong Park02586a22017-05-20 01:01:24 +0900627 // returns the namespace from where we need to start loading this.
628 const android_namespace_t* get_start_from() const {
629 return start_from_;
630 }
631
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700632 const ElfReader& get_elf_reader() const {
633 CHECK(si_ != nullptr);
634 return (*elf_readers_map_)[si_];
635 }
636
637 ElfReader& get_elf_reader() {
638 CHECK(si_ != nullptr);
639 return (*elf_readers_map_)[si_];
640 }
641
642 std::unordered_map<const soinfo*, ElfReader>* get_readers_map() {
643 return elf_readers_map_;
644 }
645
646 bool read(const char* realpath, off64_t file_size) {
647 ElfReader& elf_reader = get_elf_reader();
648 return elf_reader.Read(realpath, fd_, file_offset_, file_size);
649 }
650
651 bool load() {
652 ElfReader& elf_reader = get_elf_reader();
653 if (!elf_reader.Load(extinfo_)) {
654 return false;
655 }
656
657 si_->base = elf_reader.load_start();
658 si_->size = elf_reader.load_size();
Dimitry Ivanovf45b0e92016-01-15 11:13:35 -0800659 si_->set_mapped_by_caller(elf_reader.is_mapped_by_caller());
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700660 si_->load_bias = elf_reader.load_bias();
661 si_->phnum = elf_reader.phdr_count();
662 si_->phdr = elf_reader.loaded_phdr();
663
664 return true;
665 }
666
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700667 private:
Dimitry Ivanov7d429d32017-02-01 15:28:52 -0800668 LoadTask(const char* name,
669 soinfo* needed_by,
Jiyong Park02586a22017-05-20 01:01:24 +0900670 android_namespace_t* start_from,
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700671 std::unordered_map<const soinfo*, ElfReader>* readers_map)
672 : name_(name), needed_by_(needed_by), si_(nullptr),
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700673 fd_(-1), close_fd_(false), file_offset_(0), elf_readers_map_(readers_map),
Jiyong Park02586a22017-05-20 01:01:24 +0900674 is_dt_needed_(false), start_from_(start_from) {}
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700675
676 ~LoadTask() {
677 if (fd_ != -1 && close_fd_) {
678 close(fd_);
679 }
680 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700681
682 const char* name_;
683 soinfo* needed_by_;
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700684 soinfo* si_;
685 const android_dlextinfo* extinfo_;
686 int fd_;
687 bool close_fd_;
688 off64_t file_offset_;
689 std::unordered_map<const soinfo*, ElfReader>* elf_readers_map_;
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700690 // TODO(dimitry): needed by workaround for http://b/26394120 (the grey-list)
691 bool is_dt_needed_;
692 // END OF WORKAROUND
Jiyong Park02586a22017-05-20 01:01:24 +0900693 const android_namespace_t* const start_from_;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700694
695 DISALLOW_IMPLICIT_CONSTRUCTORS(LoadTask);
696};
697
Ningsheng Jiane93be992014-09-16 15:22:10 +0800698LoadTask::deleter_t LoadTask::deleter;
699
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700700template <typename T>
701using linked_list_t = LinkedList<T, TypeBasedAllocator<LinkedListEntry<T>>>;
702
703typedef linked_list_t<soinfo> SoinfoLinkedList;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700704typedef linked_list_t<const char> StringLinkedList;
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700705typedef std::vector<LoadTask*> LoadTaskList;
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700706
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800707enum walk_action_result_t : uint32_t {
708 kWalkStop = 0,
709 kWalkContinue = 1,
710 kWalkSkip = 2
711};
Dmitriy Ivanovaa0f2bd2014-07-28 17:32:20 -0700712
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700713// This function walks down the tree of soinfo dependencies
714// in breadth-first order and
715// * calls action(soinfo* si) for each node, and
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800716// * terminates walk if action returns kWalkStop
717// * skips children of the node if action
718// return kWalkSkip
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700719//
720// walk_dependencies_tree returns false if walk was terminated
721// by the action and true otherwise.
722template<typename F>
dimitry965d06d2017-11-28 16:03:07 +0100723static bool walk_dependencies_tree(soinfo* root_soinfo, F action) {
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -0700724 SoinfoLinkedList visit_list;
725 SoinfoLinkedList visited;
726
dimitry965d06d2017-11-28 16:03:07 +0100727 visit_list.push_back(root_soinfo);
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700728
729 soinfo* si;
730 while ((si = visit_list.pop_front()) != nullptr) {
731 if (visited.contains(si)) {
Dmitriy Ivanov042426b2014-08-12 21:02:13 -0700732 continue;
733 }
734
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800735 walk_action_result_t result = action(si);
736
737 if (result == kWalkStop) {
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700738 return false;
Dmitriy Ivanovaa0f2bd2014-07-28 17:32:20 -0700739 }
740
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700741 visited.push_back(si);
742
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800743 if (result != kWalkSkip) {
744 si->get_children().for_each([&](soinfo* child) {
745 visit_list.push_back(child);
746 });
747 }
Dmitriy Ivanovaa0f2bd2014-07-28 17:32:20 -0700748 }
749
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700750 return true;
751}
752
753
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800754static const ElfW(Sym)* dlsym_handle_lookup(android_namespace_t* ns,
755 soinfo* root,
756 soinfo* skip_until,
757 soinfo** found,
758 SymbolName& symbol_name,
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800759 const version_info* vi) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700760 const ElfW(Sym)* result = nullptr;
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700761 bool skip_lookup = skip_until != nullptr;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700762
dimitry965d06d2017-11-28 16:03:07 +0100763 walk_dependencies_tree(root, [&](soinfo* current_soinfo) {
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700764 if (skip_lookup) {
765 skip_lookup = current_soinfo != skip_until;
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800766 return kWalkContinue;
767 }
768
769 if (!ns->is_accessible(current_soinfo)) {
770 return kWalkSkip;
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700771 }
772
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800773 if (!current_soinfo->find_symbol_by_name(symbol_name, vi, &result)) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700774 result = nullptr;
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800775 return kWalkStop;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700776 }
777
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700778 if (result != nullptr) {
779 *found = current_soinfo;
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800780 return kWalkStop;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700781 }
782
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800783 return kWalkContinue;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700784 });
785
786 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800787}
788
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800789static const ElfW(Sym)* dlsym_linear_lookup(android_namespace_t* ns,
790 const char* name,
791 const version_info* vi,
792 soinfo** found,
793 soinfo* caller,
794 void* handle);
795
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700796// This is used by dlsym(3). It performs symbol lookup only within the
797// specified soinfo object and its dependencies in breadth first order.
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800798static const ElfW(Sym)* dlsym_handle_lookup(soinfo* si,
799 soinfo** found,
800 const char* name,
801 const version_info* vi) {
Dmitriy Ivanovf439b5a2015-05-30 13:04:39 -0700802 // According to man dlopen(3) and posix docs in the case when si is handle
803 // of the main executable we need to search not only in the executable and its
804 // dependencies but also in all libraries loaded with RTLD_GLOBAL.
805 //
806 // Since RTLD_GLOBAL is always set for the main executable and all dt_needed shared
807 // libraries and they are loaded in breath-first (correct) order we can just execute
808 // dlsym(RTLD_DEFAULT, ...); instead of doing two stage lookup.
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700809 if (si == solist_get_somain()) {
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800810 return dlsym_linear_lookup(&g_default_namespace, name, vi, found, nullptr, RTLD_DEFAULT);
Dmitriy Ivanovf439b5a2015-05-30 13:04:39 -0700811 }
812
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700813 SymbolName symbol_name(name);
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800814 // note that the namespace is not the namespace associated with caller_addr
815 // we use ns associated with root si intentionally here. Using caller_ns
816 // causes problems when user uses dlopen_ext to open a library in the separate
817 // namespace and then calls dlsym() on the handle.
818 return dlsym_handle_lookup(si->get_primary_namespace(), si, nullptr, found, symbol_name, vi);
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -0700819}
820
Brian Carlstromd4ee82d2013-02-28 15:58:45 -0800821/* This is used by dlsym(3) to performs a global symbol lookup. If the
822 start value is null (for RTLD_DEFAULT), the search starts at the
823 beginning of the global solist. Otherwise the search starts at the
824 specified soinfo (for RTLD_NEXT).
Iliyan Malchev6ed80c82009-09-28 19:38:04 -0700825 */
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800826static const ElfW(Sym)* dlsym_linear_lookup(android_namespace_t* ns,
827 const char* name,
828 const version_info* vi,
829 soinfo** found,
830 soinfo* caller,
831 void* handle) {
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800832 SymbolName symbol_name(name);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800833
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -0700834 auto& soinfo_list = ns->soinfo_list();
835 auto start = soinfo_list.begin();
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -0700836
837 if (handle == RTLD_NEXT) {
Dmitriy Ivanovb96ac412015-05-22 12:34:42 -0700838 if (caller == nullptr) {
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -0700839 return nullptr;
840 } else {
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -0700841 auto it = soinfo_list.find(caller);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700842 CHECK (it != soinfo_list.end());
843 start = ++it;
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -0700844 }
Elliott Hughescade4c32012-12-20 14:42:14 -0800845 }
846
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700847 const ElfW(Sym)* s = nullptr;
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -0700848 for (auto it = start, end = soinfo_list.end(); it != end; ++it) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700849 soinfo* si = *it;
Dmitriy Ivanov19133522015-06-02 17:36:54 -0700850 // Do not skip RTLD_LOCAL libraries in dlsym(RTLD_DEFAULT, ...)
Elliott Hughes5bc78c82016-11-16 11:35:43 -0800851 // if the library is opened by application with target api level < M.
Dmitriy Ivanov19133522015-06-02 17:36:54 -0700852 // See http://b/21565766
Elliott Hughes5bc78c82016-11-16 11:35:43 -0800853 if ((si->get_rtld_flags() & RTLD_GLOBAL) == 0 &&
854 si->get_target_sdk_version() >= __ANDROID_API_M__) {
Dmitriy Ivanove8ba50f2014-09-15 17:00:10 -0700855 continue;
856 }
857
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800858 if (!si->find_symbol_by_name(symbol_name, vi, &s)) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700859 return nullptr;
860 }
861
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700862 if (s != nullptr) {
Elliott Hughescade4c32012-12-20 14:42:14 -0800863 *found = si;
864 break;
Matt Fischer1698d9e2009-12-31 12:17:56 -0600865 }
Elliott Hughescade4c32012-12-20 14:42:14 -0800866 }
Matt Fischer1698d9e2009-12-31 12:17:56 -0600867
dimitry153168c2018-02-20 16:51:41 +0100868 // If not found - use dlsym_handle_lookup for caller's local_group
869 if (s == nullptr && caller != nullptr) {
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800870 soinfo* local_group_root = caller->get_local_group_root();
871
872 return dlsym_handle_lookup(local_group_root->get_primary_namespace(),
873 local_group_root,
874 (handle == RTLD_NEXT) ? caller : nullptr,
875 found,
876 symbol_name,
877 vi);
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -0700878 }
879
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700880 if (s != nullptr) {
Elliott Hughesc00f2cb2013-10-04 17:01:33 -0700881 TRACE_TYPE(LOOKUP, "%s s->st_value = %p, found->base = %p",
882 name, reinterpret_cast<void*>(s->st_value), reinterpret_cast<void*>((*found)->base));
Elliott Hughescade4c32012-12-20 14:42:14 -0800883 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800884
Elliott Hughescade4c32012-12-20 14:42:14 -0800885 return s;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800886}
887
Kito Chengfa8c05d2013-03-12 14:58:06 +0800888soinfo* find_containing_library(const void* p) {
Elliott Hughes0266ae52014-02-10 17:46:57 -0800889 ElfW(Addr) address = reinterpret_cast<ElfW(Addr)>(p);
Dimitry Ivanov3f660572016-09-09 10:00:39 -0700890 for (soinfo* si = solist_get_head(); si != nullptr; si = si->next) {
Kito Chengfa8c05d2013-03-12 14:58:06 +0800891 if (address >= si->base && address - si->base < si->size) {
892 return si;
Matt Fischere2a8b1f2009-12-31 12:17:40 -0600893 }
Kito Chengfa8c05d2013-03-12 14:58:06 +0800894 }
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700895 return nullptr;
Matt Fischere2a8b1f2009-12-31 12:17:40 -0600896}
897
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700898class ZipArchiveCache {
899 public:
900 ZipArchiveCache() {}
901 ~ZipArchiveCache();
902
903 bool get_or_open(const char* zip_path, ZipArchiveHandle* handle);
904 private:
905 DISALLOW_COPY_AND_ASSIGN(ZipArchiveCache);
906
907 std::unordered_map<std::string, ZipArchiveHandle> cache_;
908};
909
910bool ZipArchiveCache::get_or_open(const char* zip_path, ZipArchiveHandle* handle) {
911 std::string key(zip_path);
912
913 auto it = cache_.find(key);
914 if (it != cache_.end()) {
915 *handle = it->second;
916 return true;
917 }
918
919 int fd = TEMP_FAILURE_RETRY(open(zip_path, O_RDONLY | O_CLOEXEC));
920 if (fd == -1) {
921 return false;
922 }
923
924 if (OpenArchiveFd(fd, "", handle) != 0) {
925 // invalid zip-file (?)
Yabin Cui722072d2016-03-21 17:10:12 -0700926 CloseArchive(handle);
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700927 close(fd);
928 return false;
929 }
930
931 cache_[key] = *handle;
932 return true;
933}
934
935ZipArchiveCache::~ZipArchiveCache() {
Dmitriy Ivanov5dce8942015-10-13 12:14:16 -0700936 for (const auto& it : cache_) {
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700937 CloseArchive(it.second);
938 }
939}
940
941static int open_library_in_zipfile(ZipArchiveCache* zip_archive_cache,
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700942 const char* const input_path,
943 off64_t* file_offset, std::string* realpath) {
944 std::string normalized_path;
945 if (!normalize_path(input_path, &normalized_path)) {
946 return -1;
947 }
948
949 const char* const path = normalized_path.c_str();
Dimitry Ivanov769b33f2016-07-21 11:33:40 -0700950 TRACE("Trying zip file open from path \"%s\" -> normalized \"%s\"", input_path, path);
Simon Baldwinaef71952015-01-16 13:22:54 +0000951
Dmitriy Ivanov402a7502015-06-09 13:46:51 -0700952 // Treat an '!/' separator inside a path as the separator between the name
Simon Baldwinaef71952015-01-16 13:22:54 +0000953 // of the zip file on disk and the subdirectory to search within it.
Dmitriy Ivanov402a7502015-06-09 13:46:51 -0700954 // For example, if path is "foo.zip!/bar/bas/x.so", then we search for
Simon Baldwinaef71952015-01-16 13:22:54 +0000955 // "bar/bas/x.so" within "foo.zip".
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700956 const char* const separator = strstr(path, kZipFileSeparator);
Simon Baldwinaef71952015-01-16 13:22:54 +0000957 if (separator == nullptr) {
958 return -1;
Elliott Hughes124fae92012-10-31 14:20:03 -0700959 }
Simon Baldwinaef71952015-01-16 13:22:54 +0000960
961 char buf[512];
962 if (strlcpy(buf, path, sizeof(buf)) >= sizeof(buf)) {
963 PRINT("Warning: ignoring very long library path: %s", path);
964 return -1;
965 }
966
967 buf[separator - path] = '\0';
968
969 const char* zip_path = buf;
Dmitriy Ivanov402a7502015-06-09 13:46:51 -0700970 const char* file_path = &buf[separator - path + 2];
Simon Baldwinaef71952015-01-16 13:22:54 +0000971 int fd = TEMP_FAILURE_RETRY(open(zip_path, O_RDONLY | O_CLOEXEC));
972 if (fd == -1) {
973 return -1;
974 }
975
976 ZipArchiveHandle handle;
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700977 if (!zip_archive_cache->get_or_open(zip_path, &handle)) {
Simon Baldwinaef71952015-01-16 13:22:54 +0000978 // invalid zip-file (?)
979 close(fd);
980 return -1;
981 }
982
Simon Baldwinaef71952015-01-16 13:22:54 +0000983 ZipEntry entry;
984
Yusuke Sato56f40fb2015-06-25 14:56:07 -0700985 if (FindEntry(handle, ZipString(file_path), &entry) != 0) {
Simon Baldwinaef71952015-01-16 13:22:54 +0000986 // Entry was not found.
987 close(fd);
988 return -1;
989 }
990
991 // Check if it is properly stored
992 if (entry.method != kCompressStored || (entry.offset % PAGE_SIZE) != 0) {
993 close(fd);
994 return -1;
995 }
996
997 *file_offset = entry.offset;
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700998
999 if (realpath_fd(fd, realpath)) {
1000 *realpath += separator;
1001 } else {
1002 PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.",
1003 normalized_path.c_str());
1004 *realpath = normalized_path;
1005 }
1006
Simon Baldwinaef71952015-01-16 13:22:54 +00001007 return fd;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001008}
1009
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07001010static bool format_path(char* buf, size_t buf_size, const char* path, const char* name) {
Christopher Ferris7a3681e2017-04-24 17:48:32 -07001011 int n = async_safe_format_buffer(buf, buf_size, "%s/%s", path, name);
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07001012 if (n < 0 || n >= static_cast<int>(buf_size)) {
1013 PRINT("Warning: ignoring very long library path: %s/%s", path, name);
1014 return false;
1015 }
Simon Baldwinaef71952015-01-16 13:22:54 +00001016
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07001017 return true;
1018}
1019
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001020static int open_library_on_paths(ZipArchiveCache* zip_archive_cache,
1021 const char* name, off64_t* file_offset,
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001022 const std::vector<std::string>& paths,
1023 std::string* realpath) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001024 for (const auto& path : paths) {
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07001025 char buf[512];
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001026 if (!format_path(buf, sizeof(buf), path.c_str(), name)) {
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07001027 continue;
1028 }
1029
1030 int fd = -1;
Dmitriy Ivanov730ed9d2015-07-16 04:52:06 -07001031 if (strstr(buf, kZipFileSeparator) != nullptr) {
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001032 fd = open_library_in_zipfile(zip_archive_cache, buf, file_offset, realpath);
Simon Baldwinaef71952015-01-16 13:22:54 +00001033 }
1034
1035 if (fd == -1) {
1036 fd = TEMP_FAILURE_RETRY(open(buf, O_RDONLY | O_CLOEXEC));
1037 if (fd != -1) {
1038 *file_offset = 0;
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001039 if (!realpath_fd(fd, realpath)) {
1040 PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.", buf);
1041 *realpath = buf;
1042 }
Simon Baldwinaef71952015-01-16 13:22:54 +00001043 }
1044 }
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07001045
1046 if (fd != -1) {
1047 return fd;
1048 }
Simon Baldwinaef71952015-01-16 13:22:54 +00001049 }
1050
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07001051 return -1;
Simon Baldwinaef71952015-01-16 13:22:54 +00001052}
1053
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001054static int open_library(android_namespace_t* ns,
1055 ZipArchiveCache* zip_archive_cache,
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001056 const char* name, soinfo *needed_by,
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001057 off64_t* file_offset, std::string* realpath) {
Jiyong Park02586a22017-05-20 01:01:24 +09001058 TRACE("[ opening %s at namespace %s]", name, ns->get_name());
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001059
Elliott Hughes124fae92012-10-31 14:20:03 -07001060 // 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 -07001061 if (strchr(name, '/') != nullptr) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001062 int fd = -1;
1063
Dmitriy Ivanov730ed9d2015-07-16 04:52:06 -07001064 if (strstr(name, kZipFileSeparator) != nullptr) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001065 fd = open_library_in_zipfile(zip_archive_cache, name, file_offset, realpath);
1066 }
1067
1068 if (fd == -1) {
1069 fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_CLOEXEC));
Simon Baldwinaef71952015-01-16 13:22:54 +00001070 if (fd != -1) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001071 *file_offset = 0;
1072 if (!realpath_fd(fd, realpath)) {
1073 PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.", name);
1074 *realpath = name;
1075 }
Simon Baldwinaef71952015-01-16 13:22:54 +00001076 }
1077 }
1078
Dmitriy Ivanove44fffd2015-03-17 17:12:18 -07001079 return fd;
Elliott Hughes124fae92012-10-31 14:20:03 -07001080 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001081
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001082 // Otherwise we try LD_LIBRARY_PATH first, and fall back to the default library path
1083 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 -07001084 if (fd == -1 && needed_by != nullptr) {
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001085 fd = open_library_on_paths(zip_archive_cache, name, file_offset, needed_by->get_dt_runpath(), realpath);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001086 // Check if the library is accessible
1087 if (fd != -1 && !ns->is_accessible(*realpath)) {
1088 fd = -1;
1089 }
Evgenii Stepanov68650822015-06-10 13:38:39 -07001090 }
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001091
Elliott Hughes124fae92012-10-31 14:20:03 -07001092 if (fd == -1) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001093 fd = open_library_on_paths(zip_archive_cache, name, file_offset, ns->get_default_library_paths(), realpath);
Elliott Hughes124fae92012-10-31 14:20:03 -07001094 }
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001095
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001096 // TODO(dimitry): workaround for http://b/26394120 (the grey-list)
Jiyong Park37b91af2017-05-05 22:07:05 +09001097 if (fd == -1 && ns->is_greylist_enabled() && is_greylisted(ns, name, needed_by)) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001098 // try searching for it on default_namespace default_library_path
1099 fd = open_library_on_paths(zip_archive_cache, name, file_offset,
1100 g_default_namespace.get_default_library_paths(), realpath);
1101 }
1102 // END OF WORKAROUND
1103
Elliott Hughes124fae92012-10-31 14:20:03 -07001104 return fd;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001105}
1106
Dimitry Ivanov3f660572016-09-09 10:00:39 -07001107const char* fix_dt_needed(const char* dt_needed, const char* sopath __unused) {
Dmitriy Ivanovd974e882015-05-27 18:29:41 -07001108#if !defined(__LP64__)
1109 // Work around incorrect DT_NEEDED entries for old apps: http://b/21364029
Elliott Hughes9076b0c2018-02-28 11:29:45 -08001110 int app_target_api_level = get_application_target_sdk_version();
1111 if (app_target_api_level < __ANDROID_API_M__) {
Dmitriy Ivanovd974e882015-05-27 18:29:41 -07001112 const char* bname = basename(dt_needed);
1113 if (bname != dt_needed) {
Elliott Hughes9076b0c2018-02-28 11:29:45 -08001114 DL_WARN_documented_change(__ANDROID_API_M__,
1115 "invalid-dt_needed-entries-enforced-for-api-level-23",
1116 "library \"%s\" has invalid DT_NEEDED entry \"%s\"",
1117 sopath, dt_needed, app_target_api_level);
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001118 add_dlwarning(sopath, "invalid DT_NEEDED entry", dt_needed);
Dmitriy Ivanovd974e882015-05-27 18:29:41 -07001119 }
1120
1121 return bname;
1122 }
1123#endif
1124 return dt_needed;
1125}
1126
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001127template<typename F>
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001128static void for_each_dt_needed(const ElfReader& elf_reader, F action) {
1129 for (const ElfW(Dyn)* d = elf_reader.dynamic(); d->d_tag != DT_NULL; ++d) {
1130 if (d->d_tag == DT_NEEDED) {
1131 action(fix_dt_needed(elf_reader.get_string(d->d_un.d_val), elf_reader.name()));
1132 }
1133 }
1134}
1135
Dimitry Ivanovd3e7d082017-03-27 14:11:02 -07001136static bool find_loaded_library_by_inode(android_namespace_t* ns,
1137 const struct stat& file_stat,
1138 off64_t file_offset,
1139 bool search_linked_namespaces,
1140 soinfo** candidate) {
1141
1142 auto predicate = [&](soinfo* si) {
1143 return si->get_st_dev() != 0 &&
1144 si->get_st_ino() != 0 &&
1145 si->get_st_dev() == file_stat.st_dev &&
1146 si->get_st_ino() == file_stat.st_ino &&
1147 si->get_file_offset() == file_offset;
1148 };
1149
1150 *candidate = ns->soinfo_list().find_if(predicate);
1151
1152 if (*candidate == nullptr && search_linked_namespaces) {
1153 for (auto& link : ns->linked_namespaces()) {
1154 android_namespace_t* linked_ns = link.linked_namespace();
1155 soinfo* si = linked_ns->soinfo_list().find_if(predicate);
1156
1157 if (si != nullptr && link.is_accessible(si->get_soname())) {
1158 *candidate = si;
1159 return true;
1160 }
1161 }
1162 }
1163
1164 return *candidate != nullptr;
1165}
1166
Evgenii Stepanov9e77a642017-07-27 14:55:44 -07001167static bool find_loaded_library_by_realpath(android_namespace_t* ns, const char* realpath,
1168 bool search_linked_namespaces, soinfo** candidate) {
1169 auto predicate = [&](soinfo* si) { return strcmp(realpath, si->get_realpath()) == 0; };
1170
1171 *candidate = ns->soinfo_list().find_if(predicate);
1172
1173 if (*candidate == nullptr && search_linked_namespaces) {
1174 for (auto& link : ns->linked_namespaces()) {
1175 android_namespace_t* linked_ns = link.linked_namespace();
1176 soinfo* si = linked_ns->soinfo_list().find_if(predicate);
1177
1178 if (si != nullptr && link.is_accessible(si->get_soname())) {
1179 *candidate = si;
1180 return true;
1181 }
1182 }
1183 }
1184
1185 return *candidate != nullptr;
1186}
1187
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001188static bool load_library(android_namespace_t* ns,
1189 LoadTask* task,
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001190 LoadTaskList* load_tasks,
1191 int rtld_flags,
Dimitry Ivanovd3e7d082017-03-27 14:11:02 -07001192 const std::string& realpath,
1193 bool search_linked_namespaces) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001194 off64_t file_offset = task->get_file_offset();
1195 const char* name = task->get_name();
1196 const android_dlextinfo* extinfo = task->get_extinfo();
1197
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001198 if ((file_offset % PAGE_SIZE) != 0) {
Dmitriy Ivanova6c12792014-10-21 12:09:18 -07001199 DL_ERR("file offset for the library \"%s\" is not page-aligned: %" PRId64, name, file_offset);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001200 return false;
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001201 }
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001202 if (file_offset < 0) {
1203 DL_ERR("file offset for the library \"%s\" is negative: %" PRId64, name, file_offset);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001204 return false;
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001205 }
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001206
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001207 struct stat file_stat;
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001208 if (TEMP_FAILURE_RETRY(fstat(task->get_fd(), &file_stat)) != 0) {
Dmitriy Ivanova6c12792014-10-21 12:09:18 -07001209 DL_ERR("unable to stat file for the library \"%s\": %s", name, strerror(errno));
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001210 return false;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001211 }
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001212 if (file_offset >= file_stat.st_size) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07001213 DL_ERR("file offset for the library \"%s\" >= file size: %" PRId64 " >= %" PRId64,
1214 name, file_offset, file_stat.st_size);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001215 return false;
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001216 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001217
1218 // Check for symlink and other situations where
Dmitriy Ivanov9b821362015-04-02 16:03:56 -07001219 // file can have different names, unless ANDROID_DLEXT_FORCE_LOAD is set
1220 if (extinfo == nullptr || (extinfo->flags & ANDROID_DLEXT_FORCE_LOAD) == 0) {
Dimitry Ivanovd3e7d082017-03-27 14:11:02 -07001221 soinfo* si = nullptr;
1222 if (find_loaded_library_by_inode(ns, file_stat, file_offset, search_linked_namespaces, &si)) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001223 TRACE("library \"%s\" is already loaded under different name/path \"%s\" - "
1224 "will return existing soinfo", name, si->get_realpath());
1225 task->set_soinfo(si);
1226 return true;
1227 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001228 }
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07001229
Dmitriy Ivanove8ba50f2014-09-15 17:00:10 -07001230 if ((rtld_flags & RTLD_NOLOAD) != 0) {
Dmitriy Ivanova6ac54a2014-09-09 10:21:42 -07001231 DL_ERR("library \"%s\" wasn't loaded and RTLD_NOLOAD prevented it", name);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001232 return false;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001233 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001234
Dimitry Ivanovbf34ba32017-04-21 13:12:05 -07001235 struct statfs fs_stat;
1236 if (TEMP_FAILURE_RETRY(fstatfs(task->get_fd(), &fs_stat)) != 0) {
1237 DL_ERR("unable to fstatfs file for the library \"%s\": %s", name, strerror(errno));
1238 return false;
1239 }
1240
1241 // do not check accessibility using realpath if fd is located on tmpfs
1242 // this enables use of memfd_create() for apps
1243 if ((fs_stat.f_type != TMPFS_MAGIC) && (!ns->is_accessible(realpath))) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001244 // TODO(dimitry): workaround for http://b/26394120 - the grey-list
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001245
1246 // TODO(dimitry) before O release: add a namespace attribute to have this enabled
1247 // only for classloader-namespaces
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001248 const soinfo* needed_by = task->is_dt_needed() ? task->get_needed_by() : nullptr;
Dimitry Ivanov35c8e3b2017-02-27 12:17:47 -08001249 if (is_greylisted(ns, name, needed_by)) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001250 // print warning only if needed by non-system library
1251 if (needed_by == nullptr || !is_system_library(needed_by->get_realpath())) {
1252 const soinfo* needed_or_dlopened_by = task->get_needed_by();
1253 const char* sopath = needed_or_dlopened_by == nullptr ? "(unknown)" :
1254 needed_or_dlopened_by->get_realpath();
Elliott Hughes9076b0c2018-02-28 11:29:45 -08001255 DL_WARN_documented_change(__ANDROID_API_N__,
1256 "private-api-enforced-for-api-level-24",
1257 "library \"%s\" (\"%s\") needed or dlopened by \"%s\" "
1258 "is not accessible by namespace \"%s\"",
1259 name, realpath.c_str(), sopath, ns->get_name());
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001260 add_dlwarning(sopath, "unauthorized access to", name);
1261 }
1262 } else {
1263 // do not load libraries if they are not accessible for the specified namespace.
1264 const char* needed_or_dlopened_by = task->get_needed_by() == nullptr ?
1265 "(unknown)" :
1266 task->get_needed_by()->get_realpath();
Dimitry Ivanovd17a3772016-03-01 13:11:28 -08001267
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001268 DL_ERR("library \"%s\" needed or dlopened by \"%s\" is not accessible for the namespace \"%s\"",
1269 name, needed_or_dlopened_by, ns->get_name());
Dimitry Ivanovd17a3772016-03-01 13:11:28 -08001270
Dimitry Ivanov35c8e3b2017-02-27 12:17:47 -08001271 // do not print this if a library is in the list of shared libraries for linked namespaces
1272 if (!maybe_accessible_via_namespace_links(ns, name)) {
1273 PRINT("library \"%s\" (\"%s\") needed or dlopened by \"%s\" is not accessible for the"
1274 " namespace: [name=\"%s\", ld_library_paths=\"%s\", default_library_paths=\"%s\","
1275 " permitted_paths=\"%s\"]",
1276 name, realpath.c_str(),
1277 needed_or_dlopened_by,
1278 ns->get_name(),
1279 android::base::Join(ns->get_ld_library_paths(), ':').c_str(),
1280 android::base::Join(ns->get_default_library_paths(), ':').c_str(),
1281 android::base::Join(ns->get_permitted_paths(), ':').c_str());
1282 }
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001283 return false;
1284 }
Dimitry Ivanov22840aa2015-12-04 18:28:49 -08001285 }
1286
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001287 soinfo* si = soinfo_alloc(ns, realpath.c_str(), &file_stat, file_offset, rtld_flags);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001288 if (si == nullptr) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001289 return false;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001290 }
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07001291
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001292 task->set_soinfo(si);
1293
1294 // Read the ELF header and some of the segments.
1295 if (!task->read(realpath.c_str(), file_stat.st_size)) {
Dmitriy Ivanovfd7a91e2015-11-06 10:44:37 -08001296 soinfo_free(si);
1297 task->set_soinfo(nullptr);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001298 return false;
1299 }
1300
1301 // find and set DT_RUNPATH and dt_soname
1302 // Note that these field values are temporary and are
1303 // going to be overwritten on soinfo::prelink_image
1304 // with values from PT_LOAD segments.
1305 const ElfReader& elf_reader = task->get_elf_reader();
1306 for (const ElfW(Dyn)* d = elf_reader.dynamic(); d->d_tag != DT_NULL; ++d) {
1307 if (d->d_tag == DT_RUNPATH) {
1308 si->set_dt_runpath(elf_reader.get_string(d->d_un.d_val));
1309 }
1310 if (d->d_tag == DT_SONAME) {
1311 si->set_soname(elf_reader.get_string(d->d_un.d_val));
1312 }
1313 }
1314
1315 for_each_dt_needed(task->get_elf_reader(), [&](const char* name) {
Jiyong Park02586a22017-05-20 01:01:24 +09001316 load_tasks->push_back(LoadTask::create(name, si, ns, task->get_readers_map()));
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001317 });
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07001318
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001319 return true;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001320}
1321
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001322static bool load_library(android_namespace_t* ns,
1323 LoadTask* task,
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001324 ZipArchiveCache* zip_archive_cache,
1325 LoadTaskList* load_tasks,
Dimitry Ivanovd3e7d082017-03-27 14:11:02 -07001326 int rtld_flags,
1327 bool search_linked_namespaces) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001328 const char* name = task->get_name();
1329 soinfo* needed_by = task->get_needed_by();
1330 const android_dlextinfo* extinfo = task->get_extinfo();
1331
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001332 off64_t file_offset;
1333 std::string realpath;
Spencer Low0346ad72015-04-22 18:06:51 -07001334 if (extinfo != nullptr && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) {
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001335 file_offset = 0;
Spencer Low0346ad72015-04-22 18:06:51 -07001336 if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
1337 file_offset = extinfo->library_fd_offset;
1338 }
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001339
1340 if (!realpath_fd(extinfo->library_fd, &realpath)) {
1341 PRINT("warning: unable to get realpath for the library \"%s\" by extinfo->library_fd. "
1342 "Will use given name.", name);
1343 realpath = name;
1344 }
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001345
1346 task->set_fd(extinfo->library_fd, false);
1347 task->set_file_offset(file_offset);
Dimitry Ivanovd3e7d082017-03-27 14:11:02 -07001348 return load_library(ns, task, load_tasks, rtld_flags, realpath, search_linked_namespaces);
Spencer Low0346ad72015-04-22 18:06:51 -07001349 }
1350
1351 // Open the file.
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001352 int fd = open_library(ns, zip_archive_cache, name, needed_by, &file_offset, &realpath);
Spencer Low0346ad72015-04-22 18:06:51 -07001353 if (fd == -1) {
1354 DL_ERR("library \"%s\" not found", name);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001355 return false;
Spencer Low0346ad72015-04-22 18:06:51 -07001356 }
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001357
1358 task->set_fd(fd, true);
1359 task->set_file_offset(file_offset);
1360
Dimitry Ivanovd3e7d082017-03-27 14:11:02 -07001361 return load_library(ns, task, load_tasks, rtld_flags, realpath, search_linked_namespaces);
Spencer Low0346ad72015-04-22 18:06:51 -07001362}
1363
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001364static bool find_loaded_library_by_soname(android_namespace_t* ns,
Dimitry Ivanovd3e7d082017-03-27 14:11:02 -07001365 const char* name,
1366 soinfo** candidate) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001367 return !ns->soinfo_list().visit([&](soinfo* si) {
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07001368 const char* soname = si->get_soname();
1369 if (soname != nullptr && (strcmp(name, soname) == 0)) {
Dimitry Ivanov3bd90612017-02-01 08:54:43 -08001370 *candidate = si;
1371 return false;
Ard Biesheuvel12c78bb2012-08-14 12:30:09 +02001372 }
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001373
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001374 return true;
1375 });
Ard Biesheuvel12c78bb2012-08-14 12:30:09 +02001376}
1377
Dimitry Ivanovd3e7d082017-03-27 14:11:02 -07001378// Returns true if library was found and false otherwise
1379static bool find_loaded_library_by_soname(android_namespace_t* ns,
1380 const char* name,
1381 bool search_linked_namespaces,
1382 soinfo** candidate) {
1383 *candidate = nullptr;
1384
1385 // Ignore filename with path.
1386 if (strchr(name, '/') != nullptr) {
1387 return false;
1388 }
1389
1390 bool found = find_loaded_library_by_soname(ns, name, candidate);
1391
1392 if (!found && search_linked_namespaces) {
1393 // if a library was not found - look into linked namespaces
1394 for (auto& link : ns->linked_namespaces()) {
1395 if (!link.is_accessible(name)) {
1396 continue;
1397 }
1398
1399 android_namespace_t* linked_ns = link.linked_namespace();
1400
1401 if (find_loaded_library_by_soname(linked_ns, name, candidate)) {
1402 return true;
1403 }
1404 }
1405 }
1406
1407 return found;
1408}
1409
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001410static bool find_library_in_linked_namespace(const android_namespace_link_t& namespace_link,
Jiyong Park02586a22017-05-20 01:01:24 +09001411 LoadTask* task) {
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001412 android_namespace_t* ns = namespace_link.linked_namespace();
1413
1414 soinfo* candidate;
1415 bool loaded = false;
1416
1417 std::string soname;
Dimitry Ivanovd3e7d082017-03-27 14:11:02 -07001418 if (find_loaded_library_by_soname(ns, task->get_name(), false, &candidate)) {
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001419 loaded = true;
1420 soname = candidate->get_soname();
1421 } else {
1422 soname = resolve_soname(task->get_name());
1423 }
1424
1425 if (!namespace_link.is_accessible(soname.c_str())) {
1426 // the library is not accessible via namespace_link
1427 return false;
1428 }
1429
1430 // if library is already loaded - return it
1431 if (loaded) {
1432 task->set_soinfo(candidate);
1433 return true;
1434 }
1435
Jiyong Park02586a22017-05-20 01:01:24 +09001436 // returning true with empty soinfo means that the library is okay to be
Logan Chien9ee45912018-01-18 12:05:09 +08001437 // loaded in the namespace but has not yet been loaded there before.
Jiyong Park02586a22017-05-20 01:01:24 +09001438 task->set_soinfo(nullptr);
1439 return true;
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001440}
1441
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001442static bool find_library_internal(android_namespace_t* ns,
1443 LoadTask* task,
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001444 ZipArchiveCache* zip_archive_cache,
1445 LoadTaskList* load_tasks,
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001446 int rtld_flags,
1447 bool search_linked_namespaces) {
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001448 soinfo* candidate;
1449
Dimitry Ivanovd3e7d082017-03-27 14:11:02 -07001450 if (find_loaded_library_by_soname(ns, task->get_name(), search_linked_namespaces, &candidate)) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001451 task->set_soinfo(candidate);
1452 return true;
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001453 }
Dmitriy Ivanovb648a8a2014-05-19 15:06:58 -07001454
1455 // Library might still be loaded, the accurate detection
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001456 // of this fact is done by load_library.
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001457 TRACE("[ \"%s\" find_loaded_library_by_soname failed (*candidate=%s@%p). Trying harder...]",
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001458 task->get_name(), candidate == nullptr ? "n/a" : candidate->get_realpath(), candidate);
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001459
Dimitry Ivanovd3e7d082017-03-27 14:11:02 -07001460 if (load_library(ns, task, zip_archive_cache, load_tasks, rtld_flags, search_linked_namespaces)) {
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001461 return true;
1462 }
1463
1464 if (search_linked_namespaces) {
1465 // if a library was not found - look into linked namespaces
dimitry8db36a52017-10-23 15:10:10 +02001466 // preserve current dlerror in the case it fails.
1467 DlErrorRestorer dlerror_restorer;
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001468 for (auto& linked_namespace : ns->linked_namespaces()) {
1469 if (find_library_in_linked_namespace(linked_namespace,
Jiyong Park02586a22017-05-20 01:01:24 +09001470 task)) {
1471 if (task->get_soinfo() == nullptr) {
1472 // try to load the library - once namespace boundary is crossed
1473 // we need to load a library within separate load_group
1474 // to avoid using symbols from foreign namespace while.
1475 //
1476 // However, actual linking is deferred until when the global group
1477 // is fully identified and is applied to all namespaces.
1478 // Otherwise, the libs in the linked namespace won't get symbols from
1479 // the global group.
1480 if (load_library(linked_namespace.linked_namespace(), task, zip_archive_cache, load_tasks, rtld_flags, false)) {
1481 return true;
1482 }
Jiyong Park02586a22017-05-20 01:01:24 +09001483 } else {
1484 // lib is already loaded
1485 return true;
1486 }
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001487 }
1488 }
1489 }
1490
1491 return false;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001492}
1493
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001494static void soinfo_unload(soinfo* si);
1495
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001496static void shuffle(std::vector<LoadTask*>* v) {
1497 for (size_t i = 0, size = v->size(); i < size; ++i) {
1498 size_t n = size - i;
1499 size_t r = arc4random_uniform(n);
1500 std::swap((*v)[n-1], (*v)[r]);
1501 }
1502}
1503
Evgenii Stepanov0cdef7e2015-07-06 17:56:31 -07001504// add_as_children - add first-level loaded libraries (i.e. library_names[], but
1505// not their transitive dependencies) as children of the start_with library.
1506// This is false when find_libraries is called for dlopen(), when newly loaded
1507// libraries must form a disjoint tree.
Dimitry Ivanov3f660572016-09-09 10:00:39 -07001508bool find_libraries(android_namespace_t* ns,
1509 soinfo* start_with,
1510 const char* const library_names[],
1511 size_t library_names_count,
1512 soinfo* soinfos[],
1513 std::vector<soinfo*>* ld_preloads,
1514 size_t ld_preloads_count,
1515 int rtld_flags,
1516 const android_dlextinfo* extinfo,
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001517 bool add_as_children,
Jiyong Park02586a22017-05-20 01:01:24 +09001518 bool search_linked_namespaces,
Jiyong Park02586a22017-05-20 01:01:24 +09001519 std::vector<android_namespace_t*>* namespaces) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001520 // Step 0: prepare.
dimitry965d06d2017-11-28 16:03:07 +01001521 std::unordered_map<const soinfo*, ElfReader> readers_map;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001522 LoadTaskList load_tasks;
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001523
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001524 for (size_t i = 0; i < library_names_count; ++i) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001525 const char* name = library_names[i];
Jiyong Park02586a22017-05-20 01:01:24 +09001526 load_tasks.push_back(LoadTask::create(name, start_with, ns, &readers_map));
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001527 }
1528
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001529 // If soinfos array is null allocate one on stack.
1530 // The array is needed in case of failure; for example
1531 // when library_names[] = {libone.so, libtwo.so} and libone.so
1532 // is loaded correctly but libtwo.so failed for some reason.
1533 // In this case libone.so should be unloaded on return.
1534 // See also implementation of failure_guard below.
1535
1536 if (soinfos == nullptr) {
1537 size_t soinfos_size = sizeof(soinfo*)*library_names_count;
1538 soinfos = reinterpret_cast<soinfo**>(alloca(soinfos_size));
1539 memset(soinfos, 0, soinfos_size);
1540 }
1541
1542 // list of libraries to link - see step 2.
1543 size_t soinfos_count = 0;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001544
Tom Cherryb8ab6182017-04-05 16:20:29 -07001545 auto scope_guard = android::base::make_scope_guard([&]() {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001546 for (LoadTask* t : load_tasks) {
1547 LoadTask::deleter(t);
1548 }
1549 });
1550
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001551 ZipArchiveCache zip_archive_cache;
1552
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001553 // Step 1: expand the list of load_tasks to include
1554 // all DT_NEEDED libraries (do not load them just yet)
1555 for (size_t i = 0; i<load_tasks.size(); ++i) {
1556 LoadTask* task = load_tasks[i];
Evgenii Stepanov68650822015-06-10 13:38:39 -07001557 soinfo* needed_by = task->get_needed_by();
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001558
Dmitriy Ivanovedfc9f62015-09-02 16:32:02 -07001559 bool is_dt_needed = needed_by != nullptr && (needed_by != start_with || add_as_children);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001560 task->set_extinfo(is_dt_needed ? nullptr : extinfo);
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07001561 task->set_dt_needed(is_dt_needed);
Dmitriy Ivanovedfc9f62015-09-02 16:32:02 -07001562
Jiyong Park02586a22017-05-20 01:01:24 +09001563 // Note: start from the namespace that is stored in the LoadTask. This namespace
1564 // is different from the current namespace when the LoadTask is for a transitive
1565 // dependency and the lib that created the LoadTask is not found in the
1566 // current namespace but in one of the linked namespace.
1567 if (!find_library_internal(const_cast<android_namespace_t*>(task->get_start_from()),
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001568 task,
1569 &zip_archive_cache,
1570 &load_tasks,
1571 rtld_flags,
1572 search_linked_namespaces || is_dt_needed)) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001573 return false;
1574 }
1575
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001576 soinfo* si = task->get_soinfo();
1577
Dmitriy Ivanovedfc9f62015-09-02 16:32:02 -07001578 if (is_dt_needed) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001579 needed_by->add_child(si);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001580 }
1581
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001582 // When ld_preloads is not null, the first
1583 // ld_preloads_count libs are in fact ld_preloads.
1584 if (ld_preloads != nullptr && soinfos_count < ld_preloads_count) {
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07001585 ld_preloads->push_back(si);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001586 }
1587
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001588 if (soinfos_count < library_names_count) {
1589 soinfos[soinfos_count++] = si;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001590 }
1591 }
1592
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001593 // Step 2: Load libraries in random order (see b/24047022)
1594 LoadTaskList load_list;
1595 for (auto&& task : load_tasks) {
1596 soinfo* si = task->get_soinfo();
1597 auto pred = [&](const LoadTask* t) {
1598 return t->get_soinfo() == si;
1599 };
1600
1601 if (!si->is_linked() &&
1602 std::find_if(load_list.begin(), load_list.end(), pred) == load_list.end() ) {
1603 load_list.push_back(task);
1604 }
1605 }
1606 shuffle(&load_list);
1607
1608 for (auto&& task : load_list) {
1609 if (!task->load()) {
1610 return false;
1611 }
1612 }
1613
1614 // Step 3: pre-link all DT_NEEDED libraries in breadth first order.
1615 for (auto&& task : load_tasks) {
1616 soinfo* si = task->get_soinfo();
1617 if (!si->is_linked() && !si->prelink_image()) {
1618 return false;
1619 }
1620 }
1621
Jiyong Park02586a22017-05-20 01:01:24 +09001622 // Step 4: Construct the global group. Note: DF_1_GLOBAL bit of a library is
1623 // determined at step 3.
1624
1625 // Step 4-1: DF_1_GLOBAL bit is force set for LD_PRELOADed libs because they
1626 // must be added to the global group
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001627 if (ld_preloads != nullptr) {
1628 for (auto&& si : *ld_preloads) {
1629 si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL);
1630 }
1631 }
1632
Jiyong Park02586a22017-05-20 01:01:24 +09001633 // Step 4-2: Gather all DF_1_GLOBAL libs which were newly loaded during this
1634 // run. These will be the new member of the global group
1635 soinfo_list_t new_global_group_members;
1636 for (auto&& task : load_tasks) {
1637 soinfo* si = task->get_soinfo();
1638 if (!si->is_linked() && (si->get_dt_flags_1() & DF_1_GLOBAL) != 0) {
1639 new_global_group_members.push_back(si);
1640 }
1641 }
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001642
Jiyong Park02586a22017-05-20 01:01:24 +09001643 // Step 4-3: Add the new global group members to all the linked namespaces
Jiyong Park01162f22017-10-16 15:31:09 +09001644 if (namespaces != nullptr) {
Jiyong Park02586a22017-05-20 01:01:24 +09001645 for (auto linked_ns : *namespaces) {
Jiyong Park01162f22017-10-16 15:31:09 +09001646 for (auto si : new_global_group_members) {
1647 if (si->get_primary_namespace() != linked_ns) {
1648 linked_ns->add_soinfo(si);
1649 si->add_secondary_namespace(linked_ns);
1650 }
Jiyong Park02586a22017-05-20 01:01:24 +09001651 }
1652 }
1653 }
1654
dimitry965d06d2017-11-28 16:03:07 +01001655 // Step 5: Collect roots of local_groups.
1656 // Whenever needed_by->si link crosses a namespace boundary it forms its own local_group.
1657 // Here we collect new roots to link them separately later on. Note that we need to avoid
1658 // collecting duplicates. Also the order is important. They need to be linked in the same
1659 // BFS order we link individual libraries.
1660 std::vector<soinfo*> local_group_roots;
1661 if (start_with != nullptr && add_as_children) {
1662 local_group_roots.push_back(start_with);
1663 } else {
1664 CHECK(soinfos_count == 1);
1665 local_group_roots.push_back(soinfos[0]);
1666 }
1667
Jiyong Park02586a22017-05-20 01:01:24 +09001668 for (auto&& task : load_tasks) {
1669 soinfo* si = task->get_soinfo();
dimitry965d06d2017-11-28 16:03:07 +01001670 soinfo* needed_by = task->get_needed_by();
1671 bool is_dt_needed = needed_by != nullptr && (needed_by != start_with || add_as_children);
1672 android_namespace_t* needed_by_ns =
1673 is_dt_needed ? needed_by->get_primary_namespace() : ns;
1674
1675 if (!si->is_linked() && si->get_primary_namespace() != needed_by_ns) {
1676 auto it = std::find(local_group_roots.begin(), local_group_roots.end(), si);
1677 LD_LOG(kLogDlopen,
1678 "Crossing namespace boundary (si=%s@%p, si_ns=%s@%p, needed_by=%s@%p, ns=%s@%p, needed_by_ns=%s@%p) adding to local_group_roots: %s",
1679 si->get_realpath(),
1680 si,
1681 si->get_primary_namespace()->get_name(),
1682 si->get_primary_namespace(),
1683 needed_by == nullptr ? "(nullptr)" : needed_by->get_realpath(),
1684 needed_by,
1685 ns->get_name(),
1686 ns,
1687 needed_by_ns->get_name(),
1688 needed_by_ns,
1689 it == local_group_roots.end() ? "yes" : "no");
1690
1691 if (it == local_group_roots.end()) {
1692 local_group_roots.push_back(si);
Jiyong Park02586a22017-05-20 01:01:24 +09001693 }
1694 }
1695 }
1696
dimitry965d06d2017-11-28 16:03:07 +01001697 // Step 6: Link all local groups
1698 for (auto root : local_group_roots) {
1699 soinfo_list_t local_group;
1700 android_namespace_t* local_group_ns = root->get_primary_namespace();
1701
1702 walk_dependencies_tree(root,
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001703 [&] (soinfo* si) {
dimitry965d06d2017-11-28 16:03:07 +01001704 if (local_group_ns->is_accessible(si)) {
1705 local_group.push_back(si);
1706 return kWalkContinue;
1707 } else {
1708 return kWalkSkip;
1709 }
1710 });
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001711
dimitry965d06d2017-11-28 16:03:07 +01001712 soinfo_list_t global_group = local_group_ns->get_global_group();
1713 bool linked = local_group.visit([&](soinfo* si) {
1714 // Even though local group may contain accessible soinfos from other namesapces
1715 // we should avoid linking them (because if they are not linked -> they
1716 // are in the local_group_roots and will be linked later).
1717 if (!si->is_linked() && si->get_primary_namespace() == local_group_ns) {
1718 if (!si->link_image(global_group, local_group, extinfo) ||
1719 !get_cfi_shadow()->AfterLoad(si, solist_get_head())) {
1720 return false;
1721 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001722 }
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001723
dimitry965d06d2017-11-28 16:03:07 +01001724 return true;
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001725 });
Elliott Hughes27f18062017-11-29 18:47:42 +00001726
dimitry965d06d2017-11-28 16:03:07 +01001727 if (!linked) {
1728 return false;
1729 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001730 }
1731
dimitry965d06d2017-11-28 16:03:07 +01001732 // Step 7: Mark all load_tasks as linked and increment refcounts
1733 // for references between load_groups (at this point it does not matter if
1734 // referenced load_groups were loaded by previous dlopen or as part of this
1735 // one on step 6)
1736 if (start_with != nullptr && add_as_children) {
1737 start_with->set_linked();
1738 }
1739
1740 for (auto&& task : load_tasks) {
1741 soinfo* si = task->get_soinfo();
1742 si->set_linked();
1743 }
1744
1745 for (auto&& task : load_tasks) {
1746 soinfo* si = task->get_soinfo();
1747 soinfo* needed_by = task->get_needed_by();
1748 if (needed_by != nullptr &&
1749 needed_by != start_with &&
1750 needed_by->get_local_group_root() != si->get_local_group_root()) {
1751 si->increment_ref_count();
1752 }
1753 }
1754
1755
1756 return true;
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) {
dimitry965d06d2017-11-28 16:03:07 +01001763 soinfo* si = nullptr;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001764
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 */,
dimitry965d06d2017-11-28 16:03:07 +01001777 true /* search_linked_namespaces */)) {
1778 if (si != nullptr) {
1779 soinfo_unload(si);
1780 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001781 return nullptr;
1782 }
1783
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08001784 si->increment_ref_count();
1785
Elliott Hughesd23736e2012-11-01 15:16:56 -07001786 return si;
1787}
Elliott Hughesbedfe382012-08-14 14:07:59 -07001788
dimitry06016f22018-01-05 11:39:28 +01001789static void soinfo_unload_impl(soinfo* root) {
Dimitry Ivanov6705e8c2017-03-21 10:29:06 -07001790 ScopedTrace trace((std::string("unload ") + root->get_realpath()).c_str());
dimitry06016f22018-01-05 11:39:28 +01001791 bool is_linked = root->is_linked();
Dimitry Ivanov6705e8c2017-03-21 10:29:06 -07001792
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001793 if (!root->can_unload()) {
dimitryc92ce712017-10-27 14:12:53 +02001794 LD_LOG(kLogDlopen,
1795 "... dlclose(root=\"%s\"@%p) ... not unloading - the load group is flagged with NODELETE",
1796 root->get_realpath(),
1797 root);
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -07001798 return;
1799 }
1800
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001801
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001802 soinfo_list_t unload_list;
dimitry965d06d2017-11-28 16:03:07 +01001803 unload_list.push_back(root);
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001804
Dimitry Ivanovb943f302016-08-03 16:00:10 -07001805 soinfo_list_t local_unload_list;
1806 soinfo_list_t external_unload_list;
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001807 soinfo* si = nullptr;
1808
1809 while ((si = unload_list.pop_front()) != nullptr) {
1810 if (local_unload_list.contains(si)) {
1811 continue;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001812 }
Elliott Hughesd23736e2012-11-01 15:16:56 -07001813
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001814 local_unload_list.push_back(si);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001815
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001816 if (si->has_min_version(0)) {
1817 soinfo* child = nullptr;
1818 while ((child = si->get_children().pop_front()) != nullptr) {
1819 TRACE("%s@%p needs to unload %s@%p", si->get_realpath(), si,
1820 child->get_realpath(), child);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001821
Dimitry Ivanovec90e242017-02-10 11:04:20 -08001822 child->get_parents().remove(si);
1823
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001824 if (local_unload_list.contains(child)) {
1825 continue;
1826 } else if (child->is_linked() && child->get_local_group_root() != root) {
1827 external_unload_list.push_back(child);
Dimitry Ivanovec90e242017-02-10 11:04:20 -08001828 } else if (child->get_parents().empty()) {
1829 unload_list.push_back(child);
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001830 }
1831 }
1832 } else {
1833#if !defined(__work_around_b_24465209__)
Christopher Ferris7a3681e2017-04-24 17:48:32 -07001834 async_safe_fatal("soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001835#else
1836 PRINT("warning: soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
1837 for_each_dt_needed(si, [&] (const char* library_name) {
1838 TRACE("deprecated (old format of soinfo): %s needs to unload %s",
1839 si->get_realpath(), library_name);
1840
1841 soinfo* needed = find_library(si->get_primary_namespace(),
1842 library_name, RTLD_NOLOAD, nullptr, nullptr);
1843
1844 if (needed != nullptr) {
1845 // Not found: for example if symlink was deleted between dlopen and dlclose
1846 // Since we cannot really handle errors at this point - print and continue.
1847 PRINT("warning: couldn't find %s needed by %s on unload.",
1848 library_name, si->get_realpath());
1849 return;
1850 } else if (local_unload_list.contains(needed)) {
1851 // already visited
1852 return;
1853 } else if (needed->is_linked() && needed->get_local_group_root() != root) {
1854 // external group
1855 external_unload_list.push_back(needed);
1856 } else {
1857 // local group
1858 unload_list.push_front(needed);
1859 }
1860 });
1861#endif
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08001862 }
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001863 }
1864
1865 local_unload_list.for_each([](soinfo* si) {
dimitryc92ce712017-10-27 14:12:53 +02001866 LD_LOG(kLogDlopen,
1867 "... dlclose: calling destructors for \"%s\"@%p ... ",
1868 si->get_realpath(),
1869 si);
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001870 si->call_destructors();
dimitryc92ce712017-10-27 14:12:53 +02001871 LD_LOG(kLogDlopen,
1872 "... dlclose: calling destructors for \"%s\"@%p ... done",
1873 si->get_realpath(),
1874 si);
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001875 });
1876
1877 while ((si = local_unload_list.pop_front()) != nullptr) {
dimitryc92ce712017-10-27 14:12:53 +02001878 LD_LOG(kLogDlopen,
1879 "... dlclose: unloading \"%s\"@%p ...",
1880 si->get_realpath(),
1881 si);
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001882 notify_gdb_of_unload(si);
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -07001883 get_cfi_shadow()->BeforeUnload(si);
Dimitry Ivanov83fcb542016-05-04 17:19:14 -07001884 soinfo_free(si);
1885 }
1886
dimitry965d06d2017-11-28 16:03:07 +01001887 if (is_linked) {
1888 while ((si = external_unload_list.pop_front()) != nullptr) {
1889 LD_LOG(kLogDlopen,
1890 "... dlclose: unloading external reference \"%s\"@%p ...",
1891 si->get_realpath(),
1892 si);
1893 soinfo_unload(si);
1894 }
1895 } else {
1896 LD_LOG(kLogDlopen,
1897 "... dlclose: unload_si was not linked - not unloading external references ...");
Dmitriy Ivanova2547052014-11-18 12:03:09 -08001898 }
1899}
1900
dimitry06016f22018-01-05 11:39:28 +01001901static void soinfo_unload(soinfo* unload_si) {
1902 // Note that the library can be loaded but not linked;
1903 // in which case there is no root but we still need
1904 // to walk the tree and unload soinfos involved.
1905 //
1906 // This happens on unsuccessful dlopen, when one of
1907 // the DT_NEEDED libraries could not be linked/found.
1908 bool is_linked = unload_si->is_linked();
1909 soinfo* root = is_linked ? unload_si->get_local_group_root() : unload_si;
1910
1911 LD_LOG(kLogDlopen,
1912 "... dlclose(realpath=\"%s\"@%p) ... load group root is \"%s\"@%p",
1913 unload_si->get_realpath(),
1914 unload_si,
1915 root->get_realpath(),
1916 root);
1917
1918
1919 size_t ref_count = is_linked ? root->decrement_ref_count() : 0;
1920 if (ref_count > 0) {
1921 LD_LOG(kLogDlopen,
1922 "... dlclose(root=\"%s\"@%p) ... not unloading - decrementing ref_count to %zd",
1923 root->get_realpath(),
1924 root,
1925 ref_count);
1926 return;
1927 }
1928
1929 soinfo_unload_impl(root);
1930}
1931
1932void increment_dso_handle_reference_counter(void* dso_handle) {
1933 if (dso_handle == nullptr) {
1934 return;
1935 }
1936
1937 auto it = g_dso_handle_counters.find(dso_handle);
1938 if (it != g_dso_handle_counters.end()) {
1939 CHECK(++it->second != 0);
1940 } else {
1941 soinfo* si = find_containing_library(dso_handle);
1942 if (si != nullptr) {
1943 ProtectedDataGuard guard;
1944 si->set_tls_nodelete();
1945 } else {
1946 async_safe_fatal(
1947 "increment_dso_handle_reference_counter: Couldn't find soinfo by dso_handle=%p",
1948 dso_handle);
1949 }
1950 g_dso_handle_counters[dso_handle] = 1U;
1951 }
1952}
1953
1954void decrement_dso_handle_reference_counter(void* dso_handle) {
1955 if (dso_handle == nullptr) {
1956 return;
1957 }
1958
1959 auto it = g_dso_handle_counters.find(dso_handle);
1960 CHECK(it != g_dso_handle_counters.end());
1961 CHECK(it->second != 0);
1962
1963 if (--it->second == 0) {
1964 soinfo* si = find_containing_library(dso_handle);
1965 if (si != nullptr) {
1966 ProtectedDataGuard guard;
1967 si->unset_tls_nodelete();
1968 if (si->get_ref_count() == 0) {
1969 // Perform deferred unload - note that soinfo_unload_impl does not decrement ref_count
1970 soinfo_unload_impl(si);
1971 }
1972 } else {
1973 async_safe_fatal(
1974 "decrement_dso_handle_reference_counter: Couldn't find soinfo by dso_handle=%p",
1975 dso_handle);
1976 }
1977 g_dso_handle_counters.erase(it);
1978 }
1979}
1980
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001981static std::string symbol_display_name(const char* sym_name, const char* sym_ver) {
1982 if (sym_ver == nullptr) {
1983 return sym_name;
1984 }
1985
Dimitry Ivanov9cf99cb2015-12-11 14:22:24 -08001986 return std::string(sym_name) + ", version " + sym_ver;
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001987}
1988
Dimitry Ivanovaca299a2016-04-11 12:42:58 -07001989static android_namespace_t* get_caller_namespace(soinfo* caller) {
1990 return caller != nullptr ? caller->get_primary_namespace() : g_anonymous_namespace;
1991}
1992
Elliott Hughesa4aafd12014-01-13 16:37:47 -08001993void do_android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size) {
Christopher Ferris052fa3a2014-08-26 20:48:11 -07001994 // Use basic string manipulation calls to avoid snprintf.
1995 // snprintf indirectly calls pthread_getspecific to get the size of a buffer.
1996 // When debug malloc is enabled, this call returns 0. This in turn causes
1997 // snprintf to do nothing, which causes libraries to fail to load.
1998 // See b/17302493 for further details.
1999 // Once the above bug is fixed, this code can be modified to use
2000 // snprintf again.
Dimitry Ivanov77ad6422017-03-06 13:02:29 -08002001 const auto& default_ld_paths = g_default_namespace.get_default_library_paths();
2002
2003 size_t required_size = 0;
2004 for (const auto& path : default_ld_paths) {
2005 required_size += path.size() + 1;
Evgenii Stepanovd640b222015-07-10 17:54:01 -07002006 }
Dimitry Ivanov77ad6422017-03-06 13:02:29 -08002007
2008 if (buffer_size < required_size) {
Christopher Ferris7a3681e2017-04-24 17:48:32 -07002009 async_safe_fatal("android_get_LD_LIBRARY_PATH failed, buffer too small: "
2010 "buffer len %zu, required len %zu", buffer_size, required_size);
Christopher Ferris052fa3a2014-08-26 20:48:11 -07002011 }
Dimitry Ivanov77ad6422017-03-06 13:02:29 -08002012
Evgenii Stepanovd640b222015-07-10 17:54:01 -07002013 char* end = buffer;
Dimitry Ivanov77ad6422017-03-06 13:02:29 -08002014 for (size_t i = 0; i < default_ld_paths.size(); ++i) {
Evgenii Stepanovd640b222015-07-10 17:54:01 -07002015 if (i > 0) *end++ = ':';
Dimitry Ivanov77ad6422017-03-06 13:02:29 -08002016 end = stpcpy(end, default_ld_paths[i].c_str());
Evgenii Stepanovd640b222015-07-10 17:54:01 -07002017 }
Elliott Hughesa4aafd12014-01-13 16:37:47 -08002018}
2019
Elliott Hughescade4c32012-12-20 14:42:14 -08002020void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path) {
Nick Kralevich6bb01b62015-03-07 13:37:05 -08002021 parse_LD_LIBRARY_PATH(ld_library_path);
Elliott Hughescade4c32012-12-20 14:42:14 -08002022}
2023
Dimitry Ivanovb996d602016-07-11 18:11:39 -07002024static std::string android_dlextinfo_to_string(const android_dlextinfo* info) {
2025 if (info == nullptr) {
2026 return "(null)";
2027 }
2028
2029 return android::base::StringPrintf("[flags=0x%" PRIx64 ","
2030 " reserved_addr=%p,"
2031 " reserved_size=0x%zx,"
2032 " relro_fd=%d,"
2033 " library_fd=%d,"
2034 " library_fd_offset=0x%" PRIx64 ","
2035 " library_namespace=%s@%p]",
2036 info->flags,
2037 info->reserved_addr,
2038 info->reserved_size,
2039 info->relro_fd,
2040 info->library_fd,
2041 info->library_fd_offset,
2042 (info->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0 ?
2043 (info->library_namespace != nullptr ?
2044 info->library_namespace->get_name() : "(null)") : "(n/a)",
2045 (info->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0 ?
2046 info->library_namespace : nullptr);
2047}
2048
Dimitry Ivanovd9e427c2016-11-22 16:55:25 -08002049void* do_dlopen(const char* name, int flags,
2050 const android_dlextinfo* extinfo,
2051 const void* caller_addr) {
Dimitry Ivanov5c4a5802017-03-17 16:41:34 -07002052 std::string trace_prefix = std::string("dlopen: ") + (name == nullptr ? "(nullptr)" : name);
2053 ScopedTrace trace(trace_prefix.c_str());
2054 ScopedTrace loading_trace((trace_prefix + " - loading and linking").c_str());
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08002055 soinfo* const caller = find_containing_library(caller_addr);
Dimitry Ivanovb996d602016-07-11 18:11:39 -07002056 android_namespace_t* ns = get_caller_namespace(caller);
2057
2058 LD_LOG(kLogDlopen,
2059 "dlopen(name=\"%s\", flags=0x%x, extinfo=%s, caller=\"%s\", caller_ns=%s@%p) ...",
2060 name,
2061 flags,
2062 android_dlextinfo_to_string(extinfo).c_str(),
2063 caller == nullptr ? "(null)" : caller->get_realpath(),
2064 ns == nullptr ? "(null)" : ns->get_name(),
2065 ns);
2066
Tom Cherryb8ab6182017-04-05 16:20:29 -07002067 auto failure_guard = android::base::make_scope_guard(
2068 [&]() { LD_LOG(kLogDlopen, "... dlopen failed: %s", linker_get_error_buffer()); });
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08002069
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -07002070 if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL|RTLD_NODELETE|RTLD_NOLOAD)) != 0) {
Elliott Hughese66190d2012-12-18 15:57:55 -08002071 DL_ERR("invalid flags to dlopen: %x", flags);
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07002072 return nullptr;
Elliott Hughese66190d2012-12-18 15:57:55 -08002073 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002074
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07002075 if (extinfo != nullptr) {
2076 if ((extinfo->flags & ~(ANDROID_DLEXT_VALID_FLAG_BITS)) != 0) {
2077 DL_ERR("invalid extended flags to android_dlopen_ext: 0x%" PRIx64, extinfo->flags);
2078 return nullptr;
2079 }
Dmitriy Ivanov126af752015-10-07 16:34:20 -07002080
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07002081 if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) == 0 &&
Dmitriy Ivanova6c12792014-10-21 12:09:18 -07002082 (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002083 DL_ERR("invalid extended flag combination (ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET without "
2084 "ANDROID_DLEXT_USE_LIBRARY_FD): 0x%" PRIx64, extinfo->flags);
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07002085 return nullptr;
2086 }
Dmitriy Ivanov126af752015-10-07 16:34:20 -07002087
2088 if ((extinfo->flags & ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS) != 0 &&
2089 (extinfo->flags & (ANDROID_DLEXT_RESERVED_ADDRESS | ANDROID_DLEXT_RESERVED_ADDRESS_HINT)) != 0) {
2090 DL_ERR("invalid extended flag combination: ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS is not "
2091 "compatible with ANDROID_DLEXT_RESERVED_ADDRESS/ANDROID_DLEXT_RESERVED_ADDRESS_HINT");
2092 return nullptr;
2093 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002094
2095 if ((extinfo->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0) {
2096 if (extinfo->library_namespace == nullptr) {
2097 DL_ERR("ANDROID_DLEXT_USE_NAMESPACE is set but extinfo->library_namespace is null");
2098 return nullptr;
2099 }
2100 ns = extinfo->library_namespace;
2101 }
Torne (Richard Coles)012cb452014-02-06 14:34:21 +00002102 }
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -08002103
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -07002104 std::string asan_name_holder;
2105
2106 const char* translated_name = name;
Dimitry Ivanov6c14f862016-12-05 13:35:47 -08002107 if (g_is_asan && translated_name != nullptr && translated_name[0] == '/') {
Evgenii Stepanov9e77a642017-07-27 14:55:44 -07002108 char original_path[PATH_MAX];
2109 if (realpath(name, original_path) != nullptr) {
2110 asan_name_holder = std::string(kAsanLibDirPrefix) + original_path;
Vishwath Mohan4113def2017-03-29 15:31:34 -07002111 if (file_exists(asan_name_holder.c_str())) {
Evgenii Stepanov9e77a642017-07-27 14:55:44 -07002112 soinfo* si = nullptr;
2113 if (find_loaded_library_by_realpath(ns, original_path, true, &si)) {
2114 PRINT("linker_asan dlopen NOT translating \"%s\" -> \"%s\": library already loaded", name,
2115 asan_name_holder.c_str());
2116 } else {
2117 PRINT("linker_asan dlopen translating \"%s\" -> \"%s\"", name, translated_name);
2118 translated_name = asan_name_holder.c_str();
2119 }
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -07002120 }
2121 }
2122 }
2123
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -08002124 ProtectedDataGuard guard;
Dimitry Ivanov45d25ca2016-08-09 19:38:43 -07002125 soinfo* si = find_library(ns, translated_name, flags, extinfo, caller);
Dimitry Ivanov5c4a5802017-03-17 16:41:34 -07002126 loading_trace.End();
2127
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07002128 if (si != nullptr) {
Dimitry Ivanovb996d602016-07-11 18:11:39 -07002129 void* handle = si->to_handle();
2130 LD_LOG(kLogDlopen,
Dimitry Ivanovae4a0c12016-11-21 10:44:35 -08002131 "... dlopen calling constructors: realpath=\"%s\", soname=\"%s\", handle=%p",
2132 si->get_realpath(), si->get_soname(), handle);
2133 si->call_constructors();
Tom Cherryb8ab6182017-04-05 16:20:29 -07002134 failure_guard.Disable();
Dimitry Ivanovae4a0c12016-11-21 10:44:35 -08002135 LD_LOG(kLogDlopen,
Dimitry Ivanovb996d602016-07-11 18:11:39 -07002136 "... dlopen successful: realpath=\"%s\", soname=\"%s\", handle=%p",
2137 si->get_realpath(), si->get_soname(), handle);
2138 return handle;
Elliott Hughesd23736e2012-11-01 15:16:56 -07002139 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002140
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07002141 return nullptr;
Elliott Hughesd23736e2012-11-01 15:16:56 -07002142}
2143
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08002144int do_dladdr(const void* addr, Dl_info* info) {
2145 // Determine if this address can be found in any library currently mapped.
2146 soinfo* si = find_containing_library(addr);
2147 if (si == nullptr) {
2148 return 0;
2149 }
2150
2151 memset(info, 0, sizeof(Dl_info));
2152
2153 info->dli_fname = si->get_realpath();
2154 // Address at which the shared object is loaded.
2155 info->dli_fbase = reinterpret_cast<void*>(si->base);
2156
2157 // Determine if any symbol in the library contains the specified address.
2158 ElfW(Sym)* sym = si->find_symbol_by_address(addr);
2159 if (sym != nullptr) {
2160 info->dli_sname = si->get_string(sym->st_name);
2161 info->dli_saddr = reinterpret_cast<void*>(si->resolve_symbol_address(sym));
2162 }
2163
2164 return 1;
2165}
2166
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07002167static soinfo* soinfo_from_handle(void* handle) {
2168 if ((reinterpret_cast<uintptr_t>(handle) & 1) != 0) {
2169 auto it = g_soinfo_handles_map.find(reinterpret_cast<uintptr_t>(handle));
2170 if (it == g_soinfo_handles_map.end()) {
2171 return nullptr;
2172 } else {
2173 return it->second;
2174 }
2175 }
2176
2177 return static_cast<soinfo*>(handle);
2178}
2179
Dimitry Ivanovd9e427c2016-11-22 16:55:25 -08002180bool do_dlsym(void* handle,
2181 const char* sym_name,
2182 const char* sym_ver,
2183 const void* caller_addr,
2184 void** symbol) {
Dimitry Ivanov6705e8c2017-03-21 10:29:06 -07002185 ScopedTrace trace("dlsym");
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08002186#if !defined(__LP64__)
2187 if (handle == nullptr) {
2188 DL_ERR("dlsym failed: library handle is null");
2189 return false;
2190 }
2191#endif
2192
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08002193 soinfo* found = nullptr;
2194 const ElfW(Sym)* sym = nullptr;
2195 soinfo* caller = find_containing_library(caller_addr);
Dimitry Ivanovaca299a2016-04-11 12:42:58 -07002196 android_namespace_t* ns = get_caller_namespace(caller);
Dimitry Ivanov4742abd2016-12-12 16:30:15 -08002197 soinfo* si = nullptr;
2198 if (handle != RTLD_DEFAULT && handle != RTLD_NEXT) {
2199 si = soinfo_from_handle(handle);
2200 }
2201
2202 LD_LOG(kLogDlsym,
2203 "dlsym(handle=%p(\"%s\"), sym_name=\"%s\", sym_ver=\"%s\", caller=\"%s\", caller_ns=%s@%p) ...",
2204 handle,
2205 si != nullptr ? si->get_realpath() : "n/a",
2206 sym_name,
2207 sym_ver,
2208 caller == nullptr ? "(null)" : caller->get_realpath(),
2209 ns == nullptr ? "(null)" : ns->get_name(),
2210 ns);
2211
Tom Cherryb8ab6182017-04-05 16:20:29 -07002212 auto failure_guard = android::base::make_scope_guard(
2213 [&]() { LD_LOG(kLogDlsym, "... dlsym failed: %s", linker_get_error_buffer()); });
Dimitry Ivanov4742abd2016-12-12 16:30:15 -08002214
2215 if (sym_name == nullptr) {
2216 DL_ERR("dlsym failed: symbol name is null");
2217 return false;
2218 }
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08002219
2220 version_info vi_instance;
2221 version_info* vi = nullptr;
2222
2223 if (sym_ver != nullptr) {
Dimitry Ivanov9cf99cb2015-12-11 14:22:24 -08002224 vi_instance.name = sym_ver;
2225 vi_instance.elf_hash = calculate_elf_hash(sym_ver);
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08002226 vi = &vi_instance;
2227 }
2228
2229 if (handle == RTLD_DEFAULT || handle == RTLD_NEXT) {
2230 sym = dlsym_linear_lookup(ns, sym_name, vi, &found, caller, handle);
2231 } else {
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07002232 if (si == nullptr) {
2233 DL_ERR("dlsym failed: invalid handle: %p", handle);
2234 return false;
2235 }
2236 sym = dlsym_handle_lookup(si, &found, sym_name, vi);
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08002237 }
2238
2239 if (sym != nullptr) {
2240 uint32_t bind = ELF_ST_BIND(sym->st_info);
2241
2242 if ((bind == STB_GLOBAL || bind == STB_WEAK) && sym->st_shndx != 0) {
2243 *symbol = reinterpret_cast<void*>(found->resolve_symbol_address(sym));
Tom Cherryb8ab6182017-04-05 16:20:29 -07002244 failure_guard.Disable();
Dimitry Ivanov4742abd2016-12-12 16:30:15 -08002245 LD_LOG(kLogDlsym,
2246 "... dlsym successful: sym_name=\"%s\", sym_ver=\"%s\", found in=\"%s\", address=%p",
2247 sym_name, sym_ver, found->get_soname(), *symbol);
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08002248 return true;
2249 }
2250
2251 DL_ERR("symbol \"%s\" found but not global", symbol_display_name(sym_name, sym_ver).c_str());
2252 return false;
2253 }
2254
2255 DL_ERR("undefined symbol: %s", symbol_display_name(sym_name, sym_ver).c_str());
2256 return false;
2257}
2258
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07002259int do_dlclose(void* handle) {
Dimitry Ivanov6705e8c2017-03-21 10:29:06 -07002260 ScopedTrace trace("dlclose");
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -08002261 ProtectedDataGuard guard;
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07002262 soinfo* si = soinfo_from_handle(handle);
2263 if (si == nullptr) {
2264 DL_ERR("invalid handle: %p", handle);
2265 return -1;
2266 }
2267
dimitryc92ce712017-10-27 14:12:53 +02002268 LD_LOG(kLogDlopen,
2269 "dlclose(handle=%p, realpath=\"%s\"@%p) ...",
2270 handle,
2271 si->get_realpath(),
2272 si);
Dmitriy Ivanovb648a8a2014-05-19 15:06:58 -07002273 soinfo_unload(si);
dimitryc92ce712017-10-27 14:12:53 +02002274 LD_LOG(kLogDlopen,
2275 "dlclose(handle=%p) ... done",
2276 handle);
Dimitry Ivanovd88e1f32016-03-24 15:30:30 -07002277 return 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002278}
2279
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -08002280bool init_anonymous_namespace(const char* shared_lib_sonames, const char* library_search_path) {
2281 if (g_anonymous_namespace_initialized) {
2282 DL_ERR("anonymous namespace has already been initialized.");
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002283 return false;
2284 }
2285
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002286 ProtectedDataGuard guard;
2287
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002288 // create anonymous namespace
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002289 // When the caller is nullptr - create_namespace will take global group
2290 // from the anonymous namespace, which is fine because anonymous namespace
2291 // is still pointing to the default one.
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002292 android_namespace_t* anon_ns =
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -08002293 create_namespace(nullptr,
2294 "(anonymous)",
2295 nullptr,
2296 library_search_path,
Dimitry Ivanovc9dced22017-03-27 15:42:17 -07002297 ANDROID_NAMESPACE_TYPE_ISOLATED,
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -08002298 nullptr,
2299 &g_default_namespace);
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002300
2301 if (anon_ns == nullptr) {
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -08002302 return false;
2303 }
2304
2305 if (!link_namespaces(anon_ns, &g_default_namespace, shared_lib_sonames)) {
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002306 return false;
2307 }
Dimitry Ivanov7d429d32017-02-01 15:28:52 -08002308
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002309 g_anonymous_namespace = anon_ns;
Dimitry Ivanov3e0821d2017-03-07 11:02:10 -08002310 g_anonymous_namespace_initialized = true;
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -08002311
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002312 return true;
2313}
2314
Dimitry Ivanovb943f302016-08-03 16:00:10 -07002315static void add_soinfos_to_namespace(const soinfo_list_t& soinfos, android_namespace_t* ns) {
2316 ns->add_soinfos(soinfos);
2317 for (auto si : soinfos) {
2318 si->add_secondary_namespace(ns);
2319 }
2320}
2321
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002322android_namespace_t* create_namespace(const void* caller_addr,
2323 const char* name,
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002324 const char* ld_library_path,
2325 const char* default_library_path,
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002326 uint64_t type,
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002327 const char* permitted_when_isolated_path,
2328 android_namespace_t* parent_namespace) {
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002329 if (parent_namespace == nullptr) {
Dimitry Ivanov52408632016-05-23 10:31:11 -07002330 // if parent_namespace is nullptr -> set it to the caller namespace
2331 soinfo* caller_soinfo = find_containing_library(caller_addr);
2332
2333 parent_namespace = caller_soinfo != nullptr ?
2334 caller_soinfo->get_primary_namespace() :
2335 g_anonymous_namespace;
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002336 }
2337
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002338 ProtectedDataGuard guard;
2339 std::vector<std::string> ld_library_paths;
2340 std::vector<std::string> default_library_paths;
Dimitry Ivanov284ae352015-12-08 10:47:13 -08002341 std::vector<std::string> permitted_paths;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002342
2343 parse_path(ld_library_path, ":", &ld_library_paths);
2344 parse_path(default_library_path, ":", &default_library_paths);
Dimitry Ivanov284ae352015-12-08 10:47:13 -08002345 parse_path(permitted_when_isolated_path, ":", &permitted_paths);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002346
2347 android_namespace_t* ns = new (g_namespace_allocator.alloc()) android_namespace_t();
2348 ns->set_name(name);
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002349 ns->set_isolated((type & ANDROID_NAMESPACE_TYPE_ISOLATED) != 0);
Jiyong Park37b91af2017-05-05 22:07:05 +09002350 ns->set_greylist_enabled((type & ANDROID_NAMESPACE_TYPE_GREYLIST_ENABLED) != 0);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002351
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002352 if ((type & ANDROID_NAMESPACE_TYPE_SHARED) != 0) {
Dimitry Ivanovf1cb6692017-05-01 17:45:38 -07002353 // append parent namespace paths.
2354 std::copy(parent_namespace->get_ld_library_paths().begin(),
2355 parent_namespace->get_ld_library_paths().end(),
2356 back_inserter(ld_library_paths));
2357
2358 std::copy(parent_namespace->get_default_library_paths().begin(),
2359 parent_namespace->get_default_library_paths().end(),
2360 back_inserter(default_library_paths));
2361
2362 std::copy(parent_namespace->get_permitted_paths().begin(),
2363 parent_namespace->get_permitted_paths().end(),
2364 back_inserter(permitted_paths));
2365
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002366 // If shared - clone the parent namespace
Dimitry Ivanovb943f302016-08-03 16:00:10 -07002367 add_soinfos_to_namespace(parent_namespace->soinfo_list(), ns);
Dimitry Ivanovf1cb6692017-05-01 17:45:38 -07002368 // and copy parent namespace links
2369 for (auto& link : parent_namespace->linked_namespaces()) {
Logan Chien9ee45912018-01-18 12:05:09 +08002370 ns->add_linked_namespace(link.linked_namespace(), link.shared_lib_sonames(),
2371 link.allow_all_shared_libs());
Dimitry Ivanovf1cb6692017-05-01 17:45:38 -07002372 }
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002373 } else {
Dimitry Ivanovfc2da532016-05-12 15:20:21 -07002374 // If not shared - copy only the shared group
Jiyong Park02586a22017-05-20 01:01:24 +09002375 add_soinfos_to_namespace(parent_namespace->get_shared_group(), ns);
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002376 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002377
Dimitry Ivanovf1cb6692017-05-01 17:45:38 -07002378 ns->set_ld_library_paths(std::move(ld_library_paths));
2379 ns->set_default_library_paths(std::move(default_library_paths));
2380 ns->set_permitted_paths(std::move(permitted_paths));
2381
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002382 return ns;
2383}
2384
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -08002385bool link_namespaces(android_namespace_t* namespace_from,
2386 android_namespace_t* namespace_to,
2387 const char* shared_lib_sonames) {
2388 if (namespace_to == nullptr) {
2389 namespace_to = &g_default_namespace;
2390 }
2391
2392 if (namespace_from == nullptr) {
2393 DL_ERR("error linking namespaces: namespace_from is null.");
2394 return false;
2395 }
2396
2397 if (shared_lib_sonames == nullptr || shared_lib_sonames[0] == '\0') {
2398 DL_ERR("error linking namespaces \"%s\"->\"%s\": the list of shared libraries is empty.",
2399 namespace_from->get_name(), namespace_to->get_name());
2400 return false;
2401 }
2402
2403 auto sonames = android::base::Split(shared_lib_sonames, ":");
2404 std::unordered_set<std::string> sonames_set(sonames.begin(), sonames.end());
2405
2406 ProtectedDataGuard guard;
Logan Chien9ee45912018-01-18 12:05:09 +08002407 namespace_from->add_linked_namespace(namespace_to, sonames_set, false);
2408
2409 return true;
2410}
2411
2412bool link_namespaces_all_libs(android_namespace_t* namespace_from,
2413 android_namespace_t* namespace_to) {
2414 if (namespace_from == nullptr) {
2415 DL_ERR("error linking namespaces: namespace_from is null.");
2416 return false;
2417 }
2418
2419 if (namespace_to == nullptr) {
2420 DL_ERR("error linking namespaces: namespace_to is null.");
2421 return false;
2422 }
2423
2424 ProtectedDataGuard guard;
2425 namespace_from->add_linked_namespace(namespace_to, std::unordered_set<std::string>(), true);
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -08002426
2427 return true;
2428}
2429
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002430ElfW(Addr) call_ifunc_resolver(ElfW(Addr) resolver_addr) {
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07002431 typedef ElfW(Addr) (*ifunc_resolver_t)(void);
2432 ifunc_resolver_t ifunc_resolver = reinterpret_cast<ifunc_resolver_t>(resolver_addr);
2433 ElfW(Addr) ifunc_addr = ifunc_resolver();
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002434 TRACE_TYPE(RELO, "Called ifunc_resolver@%p. The result is %p",
2435 ifunc_resolver, reinterpret_cast<void*>(ifunc_addr));
Brigid Smithc5a13ef2014-07-23 11:22:25 -07002436
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07002437 return ifunc_addr;
Brigid Smithc5a13ef2014-07-23 11:22:25 -07002438}
Brigid Smithc5a13ef2014-07-23 11:22:25 -07002439
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002440const version_info* VersionTracker::get_version_info(ElfW(Versym) source_symver) const {
2441 if (source_symver < 2 ||
2442 source_symver >= version_infos.size() ||
2443 version_infos[source_symver].name == nullptr) {
2444 return nullptr;
2445 }
2446
2447 return &version_infos[source_symver];
2448}
2449
2450void VersionTracker::add_version_info(size_t source_index,
2451 ElfW(Word) elf_hash,
2452 const char* ver_name,
2453 const soinfo* target_si) {
2454 if (source_index >= version_infos.size()) {
2455 version_infos.resize(source_index+1);
2456 }
2457
2458 version_infos[source_index].elf_hash = elf_hash;
2459 version_infos[source_index].name = ver_name;
2460 version_infos[source_index].target_si = target_si;
2461}
2462
2463bool VersionTracker::init_verneed(const soinfo* si_from) {
2464 uintptr_t verneed_ptr = si_from->get_verneed_ptr();
2465
2466 if (verneed_ptr == 0) {
2467 return true;
2468 }
2469
2470 size_t verneed_cnt = si_from->get_verneed_cnt();
2471
2472 for (size_t i = 0, offset = 0; i<verneed_cnt; ++i) {
2473 const ElfW(Verneed)* verneed = reinterpret_cast<ElfW(Verneed)*>(verneed_ptr + offset);
2474 size_t vernaux_offset = offset + verneed->vn_aux;
2475 offset += verneed->vn_next;
2476
2477 if (verneed->vn_version != 1) {
2478 DL_ERR("unsupported verneed[%zd] vn_version: %d (expected 1)", i, verneed->vn_version);
2479 return false;
2480 }
2481
2482 const char* target_soname = si_from->get_string(verneed->vn_file);
2483 // find it in dependencies
2484 soinfo* target_si = si_from->get_children().find_if([&](const soinfo* si) {
Dmitriy Ivanov406d9962015-05-06 11:05:27 -07002485 return si->get_soname() != nullptr && strcmp(si->get_soname(), target_soname) == 0;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002486 });
2487
2488 if (target_si == nullptr) {
2489 DL_ERR("cannot find \"%s\" from verneed[%zd] in DT_NEEDED list for \"%s\"",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002490 target_soname, i, si_from->get_realpath());
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002491 return false;
2492 }
2493
2494 for (size_t j = 0; j<verneed->vn_cnt; ++j) {
2495 const ElfW(Vernaux)* vernaux = reinterpret_cast<ElfW(Vernaux)*>(verneed_ptr + vernaux_offset);
2496 vernaux_offset += vernaux->vna_next;
2497
2498 const ElfW(Word) elf_hash = vernaux->vna_hash;
2499 const char* ver_name = si_from->get_string(vernaux->vna_name);
2500 ElfW(Half) source_index = vernaux->vna_other;
2501
2502 add_version_info(source_index, elf_hash, ver_name, target_si);
2503 }
2504 }
2505
2506 return true;
2507}
2508
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002509template <typename F>
2510static bool for_each_verdef(const soinfo* si, F functor) {
2511 if (!si->has_min_version(2)) {
2512 return true;
2513 }
2514
2515 uintptr_t verdef_ptr = si->get_verdef_ptr();
2516 if (verdef_ptr == 0) {
2517 return true;
2518 }
2519
2520 size_t offset = 0;
2521
2522 size_t verdef_cnt = si->get_verdef_cnt();
2523 for (size_t i = 0; i<verdef_cnt; ++i) {
2524 const ElfW(Verdef)* verdef = reinterpret_cast<ElfW(Verdef)*>(verdef_ptr + offset);
2525 size_t verdaux_offset = offset + verdef->vd_aux;
2526 offset += verdef->vd_next;
2527
2528 if (verdef->vd_version != 1) {
2529 DL_ERR("unsupported verdef[%zd] vd_version: %d (expected 1) library: %s",
2530 i, verdef->vd_version, si->get_realpath());
2531 return false;
2532 }
2533
2534 if ((verdef->vd_flags & VER_FLG_BASE) != 0) {
2535 // "this is the version of the file itself. It must not be used for
2536 // matching a symbol. It can be used to match references."
2537 //
2538 // http://www.akkadia.org/drepper/symbol-versioning
2539 continue;
2540 }
2541
2542 if (verdef->vd_cnt == 0) {
2543 DL_ERR("invalid verdef[%zd] vd_cnt == 0 (version without a name)", i);
2544 return false;
2545 }
2546
2547 const ElfW(Verdaux)* verdaux = reinterpret_cast<ElfW(Verdaux)*>(verdef_ptr + verdaux_offset);
2548
2549 if (functor(i, verdef, verdaux) == true) {
2550 break;
2551 }
2552 }
2553
2554 return true;
2555}
2556
2557bool find_verdef_version_index(const soinfo* si, const version_info* vi, ElfW(Versym)* versym) {
2558 if (vi == nullptr) {
2559 *versym = kVersymNotNeeded;
2560 return true;
2561 }
2562
2563 *versym = kVersymGlobal;
2564
2565 return for_each_verdef(si,
2566 [&](size_t, const ElfW(Verdef)* verdef, const ElfW(Verdaux)* verdaux) {
2567 if (verdef->vd_hash == vi->elf_hash &&
2568 strcmp(vi->name, si->get_string(verdaux->vda_name)) == 0) {
2569 *versym = verdef->vd_ndx;
2570 return true;
2571 }
2572
2573 return false;
2574 }
2575 );
2576}
2577
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002578bool VersionTracker::init_verdef(const soinfo* si_from) {
2579 return for_each_verdef(si_from,
2580 [&](size_t, const ElfW(Verdef)* verdef, const ElfW(Verdaux)* verdaux) {
2581 add_version_info(verdef->vd_ndx, verdef->vd_hash,
2582 si_from->get_string(verdaux->vda_name), si_from);
2583 return false;
2584 }
2585 );
2586}
2587
2588bool VersionTracker::init(const soinfo* si_from) {
2589 if (!si_from->has_min_version(2)) {
2590 return true;
2591 }
2592
2593 return init_verneed(si_from) && init_verdef(si_from);
2594}
2595
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07002596// TODO (dimitry): Methods below need to be moved out of soinfo
2597// and in more isolated file in order minimize dependencies on
2598// unnecessary object in the linker binary. Consider making them
2599// independent from soinfo (?).
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002600bool soinfo::lookup_version_info(const VersionTracker& version_tracker, ElfW(Word) sym,
2601 const char* sym_name, const version_info** vi) {
2602 const ElfW(Versym)* sym_ver_ptr = get_versym(sym);
2603 ElfW(Versym) sym_ver = sym_ver_ptr == nullptr ? 0 : *sym_ver_ptr;
2604
2605 if (sym_ver != VER_NDX_LOCAL && sym_ver != VER_NDX_GLOBAL) {
2606 *vi = version_tracker.get_version_info(sym_ver);
2607
2608 if (*vi == nullptr) {
2609 DL_ERR("cannot find verneed/verdef for version index=%d "
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002610 "referenced by symbol \"%s\" at \"%s\"", sym_ver, sym_name, get_realpath());
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002611 return false;
2612 }
2613 } else {
2614 // there is no version info
2615 *vi = nullptr;
2616 }
2617
2618 return true;
2619}
2620
Rahul Chaudhryf16b6592018-01-25 15:34:15 -08002621void soinfo::apply_relr_reloc(ElfW(Addr) offset) {
2622 ElfW(Addr) address = offset + load_bias;
2623 *reinterpret_cast<ElfW(Addr)*>(address) += load_bias;
2624}
2625
Rahul Chaudhryb7feec72017-12-19 15:25:23 -08002626// Process relocations in SHT_RELR section (experimental).
Rahul Chaudhryf16b6592018-01-25 15:34:15 -08002627// Details of the encoding are described in this post:
2628// https://groups.google.com/d/msg/generic-abi/bX460iggiKg/Pi9aSwwABgAJ
Rahul Chaudhryb7feec72017-12-19 15:25:23 -08002629bool soinfo::relocate_relr() {
2630 ElfW(Relr)* begin = relr_;
2631 ElfW(Relr)* end = relr_ + relr_count_;
Rahul Chaudhryf16b6592018-01-25 15:34:15 -08002632 constexpr size_t wordsize = sizeof(ElfW(Addr));
Rahul Chaudhryb7feec72017-12-19 15:25:23 -08002633
Rahul Chaudhryf16b6592018-01-25 15:34:15 -08002634 ElfW(Addr) base = 0;
Rahul Chaudhryb7feec72017-12-19 15:25:23 -08002635 for (ElfW(Relr)* current = begin; current < end; ++current) {
Rahul Chaudhryf16b6592018-01-25 15:34:15 -08002636 ElfW(Relr) entry = *current;
2637 ElfW(Addr) offset;
2638
2639 if ((entry&1) == 0) {
2640 // Even entry: encodes the offset for next relocation.
2641 offset = static_cast<ElfW(Addr)>(entry);
2642 apply_relr_reloc(offset);
2643 // Set base offset for subsequent bitmap entries.
2644 base = offset + wordsize;
2645 continue;
Rahul Chaudhryb7feec72017-12-19 15:25:23 -08002646 }
Rahul Chaudhryf16b6592018-01-25 15:34:15 -08002647
2648 // Odd entry: encodes bitmap for relocations starting at base.
2649 offset = base;
2650 while (entry != 0) {
2651 entry >>= 1;
2652 if ((entry&1) != 0) {
2653 apply_relr_reloc(offset);
Rahul Chaudhryb7feec72017-12-19 15:25:23 -08002654 }
Rahul Chaudhryf16b6592018-01-25 15:34:15 -08002655 offset += wordsize;
Rahul Chaudhryb7feec72017-12-19 15:25:23 -08002656 }
Rahul Chaudhryf16b6592018-01-25 15:34:15 -08002657
2658 // Advance base offset by 63 words for 64-bit platforms,
2659 // or 31 words for 32-bit platforms.
2660 base += (8*wordsize - 1) * wordsize;
Rahul Chaudhryb7feec72017-12-19 15:25:23 -08002661 }
2662 return true;
2663}
2664
Dimitry Ivanov576a3752016-08-09 06:58:55 -07002665#if !defined(__mips__)
2666#if defined(USE_RELA)
2667static ElfW(Addr) get_addend(ElfW(Rela)* rela, ElfW(Addr) reloc_addr __unused) {
2668 return rela->r_addend;
2669}
2670#else
2671static ElfW(Addr) get_addend(ElfW(Rel)* rel, ElfW(Addr) reloc_addr) {
2672 if (ELFW(R_TYPE)(rel->r_info) == R_GENERIC_RELATIVE ||
2673 ELFW(R_TYPE)(rel->r_info) == R_GENERIC_IRELATIVE) {
2674 return *reinterpret_cast<ElfW(Addr)*>(reloc_addr);
2675 }
2676 return 0;
2677}
2678#endif
2679
Dmitriy Ivanovfa26eee2015-02-03 16:06:47 -08002680template<typename ElfRelIteratorT>
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07002681bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& rel_iterator,
2682 const soinfo_list_t& global_group, const soinfo_list_t& local_group) {
Dmitriy Ivanovfa26eee2015-02-03 16:06:47 -08002683 for (size_t idx = 0; rel_iterator.has_next(); ++idx) {
2684 const auto rel = rel_iterator.next();
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002685 if (rel == nullptr) {
2686 return false;
2687 }
2688
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002689 ElfW(Word) type = ELFW(R_TYPE)(rel->r_info);
2690 ElfW(Word) sym = ELFW(R_SYM)(rel->r_info);
2691
2692 ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rel->r_offset + load_bias);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002693 ElfW(Addr) sym_addr = 0;
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07002694 const char* sym_name = nullptr;
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002695 ElfW(Addr) addend = get_addend(rel, reloc);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002696
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07002697 DEBUG("Processing \"%s\" relocation at index %zd", get_realpath(), idx);
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002698 if (type == R_GENERIC_NONE) {
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002699 continue;
2700 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002701
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002702 const ElfW(Sym)* s = nullptr;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002703 soinfo* lsi = nullptr;
2704
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002705 if (sym != 0) {
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002706 sym_name = get_string(symtab_[sym].st_name);
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002707 const version_info* vi = nullptr;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002708
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002709 if (!lookup_version_info(version_tracker, sym, sym_name, &vi)) {
2710 return false;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002711 }
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002712
2713 if (!soinfo_do_lookup(this, sym_name, vi, &lsi, global_group, local_group, &s)) {
2714 return false;
2715 }
2716
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07002717 if (s == nullptr) {
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002718 // We only allow an undefined symbol if this is a weak reference...
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002719 s = &symtab_[sym];
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002720 if (ELF_ST_BIND(s->st_info) != STB_WEAK) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002721 DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, get_realpath());
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002722 return false;
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002723 }
2724
2725 /* IHI0044C AAELF 4.5.1.1:
2726
2727 Libraries are not searched to resolve weak references.
2728 It is not an error for a weak reference to remain unsatisfied.
2729
2730 During linking, the value of an undefined weak reference is:
2731 - Zero if the relocation type is absolute
2732 - The address of the place if the relocation is pc-relative
2733 - The address of nominal base address if the relocation
2734 type is base-relative.
2735 */
2736
2737 switch (type) {
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002738 case R_GENERIC_JUMP_SLOT:
2739 case R_GENERIC_GLOB_DAT:
2740 case R_GENERIC_RELATIVE:
2741 case R_GENERIC_IRELATIVE:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002742#if defined(__aarch64__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002743 case R_AARCH64_ABS64:
2744 case R_AARCH64_ABS32:
2745 case R_AARCH64_ABS16:
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002746#elif defined(__x86_64__)
2747 case R_X86_64_32:
2748 case R_X86_64_64:
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002749#elif defined(__arm__)
2750 case R_ARM_ABS32:
2751#elif defined(__i386__)
2752 case R_386_32:
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002753#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002754 /*
2755 * The sym_addr was initialized to be zero above, or the relocation
2756 * code below does not care about value of sym_addr.
2757 * No need to do anything.
2758 */
2759 break;
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002760#if defined(__x86_64__)
Dimitry Ivanovd338aac2015-01-13 22:31:54 +00002761 case R_X86_64_PC32:
2762 sym_addr = reloc;
2763 break;
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002764#elif defined(__i386__)
2765 case R_386_PC32:
2766 sym_addr = reloc;
2767 break;
2768#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002769 default:
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002770 DL_ERR("unknown weak reloc type %d @ %p (%zu)", type, rel, idx);
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002771 return false;
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002772 }
Dmitriy Ivanovec83a612015-07-26 07:37:09 -07002773 } else { // We got a definition.
2774#if !defined(__LP64__)
2775 // When relocating dso with text_relocation .text segment is
2776 // not executable. We need to restore elf flags before resolving
2777 // STT_GNU_IFUNC symbol.
2778 bool protect_segments = has_text_relocations &&
2779 lsi == this &&
2780 ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC;
2781 if (protect_segments) {
2782 if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
2783 DL_ERR("can't protect segments for \"%s\": %s",
2784 get_realpath(), strerror(errno));
2785 return false;
2786 }
2787 }
2788#endif
Elliott Hughes45a93c12018-03-23 18:46:07 -07002789 if (ELF_ST_TYPE(s->st_info) == STT_TLS) {
2790 DL_ERR("unsupported ELF TLS symbol \"%s\" referenced by \"%s\"",
2791 sym_name, get_realpath());
2792 return false;
2793 }
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07002794 sym_addr = lsi->resolve_symbol_address(s);
Dmitriy Ivanovec83a612015-07-26 07:37:09 -07002795#if !defined(__LP64__)
2796 if (protect_segments) {
2797 if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
2798 DL_ERR("can't unprotect loadable segments for \"%s\": %s",
2799 get_realpath(), strerror(errno));
2800 return false;
2801 }
2802 }
2803#endif
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002804 }
2805 count_relocation(kRelocSymbol);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002806 }
2807
2808 switch (type) {
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002809 case R_GENERIC_JUMP_SLOT:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002810 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002811 MARK(rel->r_offset);
2812 TRACE_TYPE(RELO, "RELO JMP_SLOT %16p <- %16p %s\n",
2813 reinterpret_cast<void*>(reloc),
2814 reinterpret_cast<void*>(sym_addr + addend), sym_name);
2815
2816 *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002817 break;
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002818 case R_GENERIC_GLOB_DAT:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002819 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002820 MARK(rel->r_offset);
2821 TRACE_TYPE(RELO, "RELO GLOB_DAT %16p <- %16p %s\n",
2822 reinterpret_cast<void*>(reloc),
2823 reinterpret_cast<void*>(sym_addr + addend), sym_name);
2824 *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002825 break;
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002826 case R_GENERIC_RELATIVE:
2827 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002828 MARK(rel->r_offset);
2829 TRACE_TYPE(RELO, "RELO RELATIVE %16p <- %16p\n",
2830 reinterpret_cast<void*>(reloc),
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002831 reinterpret_cast<void*>(load_bias + addend));
2832 *reinterpret_cast<ElfW(Addr)*>(reloc) = (load_bias + addend);
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002833 break;
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002834 case R_GENERIC_IRELATIVE:
2835 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002836 MARK(rel->r_offset);
2837 TRACE_TYPE(RELO, "RELO IRELATIVE %16p <- %16p\n",
2838 reinterpret_cast<void*>(reloc),
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002839 reinterpret_cast<void*>(load_bias + addend));
Dmitriy Ivanovec83a612015-07-26 07:37:09 -07002840 {
2841#if !defined(__LP64__)
2842 // When relocating dso with text_relocation .text segment is
2843 // not executable. We need to restore elf flags for this
2844 // particular call.
2845 if (has_text_relocations) {
2846 if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
2847 DL_ERR("can't protect segments for \"%s\": %s",
2848 get_realpath(), strerror(errno));
2849 return false;
2850 }
2851 }
2852#endif
2853 ElfW(Addr) ifunc_addr = call_ifunc_resolver(load_bias + addend);
2854#if !defined(__LP64__)
2855 // Unprotect it afterwards...
2856 if (has_text_relocations) {
2857 if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
2858 DL_ERR("can't unprotect loadable segments for \"%s\": %s",
2859 get_realpath(), strerror(errno));
2860 return false;
2861 }
2862 }
2863#endif
2864 *reinterpret_cast<ElfW(Addr)*>(reloc) = ifunc_addr;
2865 }
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002866 break;
2867
2868#if defined(__aarch64__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002869 case R_AARCH64_ABS64:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002870 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002871 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002872 TRACE_TYPE(RELO, "RELO ABS64 %16llx <- %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002873 reloc, sym_addr + addend, sym_name);
2874 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend;
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002875 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002876 case R_AARCH64_ABS32:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002877 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002878 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002879 TRACE_TYPE(RELO, "RELO ABS32 %16llx <- %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002880 reloc, sym_addr + addend, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002881 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002882 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT32_MIN);
2883 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT32_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002884 if ((min_value <= (sym_addr + addend)) &&
2885 ((sym_addr + addend) <= max_value)) {
2886 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend;
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002887 } else {
2888 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002889 sym_addr + addend, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002890 return false;
2891 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002892 }
2893 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002894 case R_AARCH64_ABS16:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002895 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002896 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002897 TRACE_TYPE(RELO, "RELO ABS16 %16llx <- %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002898 reloc, sym_addr + addend, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002899 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002900 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN);
2901 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT16_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002902 if ((min_value <= (sym_addr + addend)) &&
2903 ((sym_addr + addend) <= max_value)) {
2904 *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002905 } else {
2906 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002907 sym_addr + addend, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002908 return false;
2909 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002910 }
2911 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002912 case R_AARCH64_PREL64:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002913 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002914 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002915 TRACE_TYPE(RELO, "RELO REL64 %16llx <- %16llx - %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002916 reloc, sym_addr + addend, rel->r_offset, sym_name);
2917 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset;
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002918 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002919 case R_AARCH64_PREL32:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002920 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002921 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002922 TRACE_TYPE(RELO, "RELO REL32 %16llx <- %16llx - %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002923 reloc, sym_addr + addend, rel->r_offset, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002924 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002925 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT32_MIN);
2926 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT32_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002927 if ((min_value <= (sym_addr + addend - rel->r_offset)) &&
2928 ((sym_addr + addend - rel->r_offset) <= max_value)) {
2929 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset;
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002930 } else {
2931 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002932 sym_addr + addend - rel->r_offset, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002933 return false;
2934 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002935 }
2936 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002937 case R_AARCH64_PREL16:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002938 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002939 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002940 TRACE_TYPE(RELO, "RELO REL16 %16llx <- %16llx - %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002941 reloc, sym_addr + addend, rel->r_offset, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002942 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002943 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN);
2944 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT16_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002945 if ((min_value <= (sym_addr + addend - rel->r_offset)) &&
2946 ((sym_addr + addend - rel->r_offset) <= max_value)) {
2947 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset;
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002948 } else {
2949 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002950 sym_addr + addend - rel->r_offset, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002951 return false;
2952 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002953 }
2954 break;
2955
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002956 case R_AARCH64_COPY:
Nick Kralevich76e289c2014-07-03 12:04:31 -07002957 /*
2958 * ET_EXEC is not supported so this should not happen.
2959 *
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002960 * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0056b/IHI0056B_aaelf64.pdf
Nick Kralevich76e289c2014-07-03 12:04:31 -07002961 *
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002962 * Section 4.6.11 "Dynamic relocations"
Nick Kralevich76e289c2014-07-03 12:04:31 -07002963 * R_AARCH64_COPY may only appear in executable objects where e_type is
2964 * set to ET_EXEC.
2965 */
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002966 DL_ERR("%s R_AARCH64_COPY relocations are not supported", get_realpath());
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002967 return false;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002968 case R_AARCH64_TLS_TPREL64:
Elliott Hughes0266ae52014-02-10 17:46:57 -08002969 TRACE_TYPE(RELO, "RELO TLS_TPREL64 *** %16llx <- %16llx - %16llx\n",
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002970 reloc, (sym_addr + addend), rel->r_offset);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002971 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002972 case R_AARCH64_TLS_DTPREL32:
Elliott Hughes0266ae52014-02-10 17:46:57 -08002973 TRACE_TYPE(RELO, "RELO TLS_DTPREL32 *** %16llx <- %16llx - %16llx\n",
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002974 reloc, (sym_addr + addend), rel->r_offset);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002975 break;
2976#elif defined(__x86_64__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002977 case R_X86_64_32:
2978 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002979 MARK(rel->r_offset);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002980 TRACE_TYPE(RELO, "RELO R_X86_64_32 %08zx <- +%08zx %s", static_cast<size_t>(reloc),
2981 static_cast<size_t>(sym_addr), sym_name);
Junichi Uekawaff35b1e2015-11-18 10:18:59 +09002982 *reinterpret_cast<Elf32_Addr*>(reloc) = sym_addr + addend;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002983 break;
2984 case R_X86_64_64:
2985 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002986 MARK(rel->r_offset);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002987 TRACE_TYPE(RELO, "RELO R_X86_64_64 %08zx <- +%08zx %s", static_cast<size_t>(reloc),
2988 static_cast<size_t>(sym_addr), sym_name);
Junichi Uekawaff35b1e2015-11-18 10:18:59 +09002989 *reinterpret_cast<Elf64_Addr*>(reloc) = sym_addr + addend;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002990 break;
2991 case R_X86_64_PC32:
2992 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002993 MARK(rel->r_offset);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002994 TRACE_TYPE(RELO, "RELO R_X86_64_PC32 %08zx <- +%08zx (%08zx - %08zx) %s",
2995 static_cast<size_t>(reloc), static_cast<size_t>(sym_addr - reloc),
2996 static_cast<size_t>(sym_addr), static_cast<size_t>(reloc), sym_name);
Junichi Uekawaff35b1e2015-11-18 10:18:59 +09002997 *reinterpret_cast<Elf32_Addr*>(reloc) = sym_addr + addend - reloc;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002998 break;
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002999#elif defined(__arm__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003000 case R_ARM_ABS32:
3001 count_relocation(kRelocAbsolute);
3002 MARK(rel->r_offset);
3003 TRACE_TYPE(RELO, "RELO ABS %08x <- %08x %s", reloc, sym_addr, sym_name);
3004 *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
3005 break;
3006 case R_ARM_REL32:
3007 count_relocation(kRelocRelative);
3008 MARK(rel->r_offset);
3009 TRACE_TYPE(RELO, "RELO REL32 %08x <- %08x - %08x %s",
3010 reloc, sym_addr, rel->r_offset, sym_name);
3011 *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr - rel->r_offset;
3012 break;
3013 case R_ARM_COPY:
3014 /*
3015 * ET_EXEC is not supported so this should not happen.
3016 *
3017 * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044d/IHI0044D_aaelf.pdf
3018 *
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003019 * Section 4.6.1.10 "Dynamic relocations"
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003020 * R_ARM_COPY may only appear in executable objects where e_type is
3021 * set to ET_EXEC.
3022 */
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003023 DL_ERR("%s R_ARM_COPY relocations are not supported", get_realpath());
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08003024 return false;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003025#elif defined(__i386__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003026 case R_386_32:
3027 count_relocation(kRelocRelative);
3028 MARK(rel->r_offset);
3029 TRACE_TYPE(RELO, "RELO R_386_32 %08x <- +%08x %s", reloc, sym_addr, sym_name);
3030 *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
3031 break;
3032 case R_386_PC32:
3033 count_relocation(kRelocRelative);
3034 MARK(rel->r_offset);
3035 TRACE_TYPE(RELO, "RELO R_386_PC32 %08x <- +%08x (%08x - %08x) %s",
3036 reloc, (sym_addr - reloc), sym_addr, reloc, sym_name);
3037 *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr - reloc);
3038 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003039#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003040 default:
3041 DL_ERR("unknown reloc type %d @ %p (%zu)", type, rel, idx);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003042 return false;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003043 }
3044 }
3045 return true;
Raghu Gandhamd7daacb2012-07-31 12:07:22 -07003046}
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08003047#endif // !defined(__mips__)
Raghu Gandhamd7daacb2012-07-31 12:07:22 -07003048
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07003049// An empty list of soinfos
Dimitry Ivanovb943f302016-08-03 16:00:10 -07003050static soinfo_list_t g_empty_list;
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07003051
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003052bool soinfo::prelink_image() {
Ningsheng Jiane93be992014-09-16 15:22:10 +08003053 /* Extract dynamic section */
3054 ElfW(Word) dynamic_flags = 0;
3055 phdr_table_get_dynamic_section(phdr, phnum, load_bias, &dynamic, &dynamic_flags);
Dmitriy Ivanov498eb182014-09-05 14:57:59 -07003056
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003057 /* We can't log anything until the linker is relocated */
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08003058 bool relocating_linker = (flags_ & FLAG_LINKER) != 0;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003059 if (!relocating_linker) {
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07003060 INFO("[ Linking \"%s\" ]", get_realpath());
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08003061 DEBUG("si->base = %p si->flags = 0x%08x", reinterpret_cast<void*>(base), flags_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003062 }
3063
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003064 if (dynamic == nullptr) {
David 'Digit' Turnerb52e4382012-06-19 01:24:17 +02003065 if (!relocating_linker) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003066 DL_ERR("missing PT_DYNAMIC in \"%s\"", get_realpath());
David 'Digit' Turnerb52e4382012-06-19 01:24:17 +02003067 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003068 return false;
3069 } else {
3070 if (!relocating_linker) {
3071 DEBUG("dynamic = %p", dynamic);
David 'Digit' Turner63f99f42012-06-19 00:08:39 +02003072 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003073 }
David 'Digit' Turner63f99f42012-06-19 00:08:39 +02003074
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07003075#if defined(__arm__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003076 (void) phdr_table_get_arm_exidx(phdr, phnum, load_bias,
3077 &ARM_exidx, &ARM_exidx_count);
David 'Digit' Turner63f99f42012-06-19 00:08:39 +02003078#endif
3079
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003080 // Extract useful information from dynamic section.
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07003081 // Note that: "Except for the DT_NULL element at the end of the array,
3082 // and the relative order of DT_NEEDED elements, entries may appear in any order."
3083 //
3084 // source: http://www.sco.com/developers/gabi/1998-04-29/ch5.dynamic.html
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003085 uint32_t needed_count = 0;
3086 for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
3087 DEBUG("d = %p, d[0](tag) = %p d[1](val) = %p",
3088 d, reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
3089 switch (d->d_tag) {
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003090 case DT_SONAME:
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07003091 // this is parsed after we have strtab initialized (see below).
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003092 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003093
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003094 case DT_HASH:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003095 nbucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0];
3096 nchain_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
3097 bucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8);
3098 chain_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8 + nbucket_ * 4);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003099 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003100
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08003101 case DT_GNU_HASH:
Dmitriy Ivanov3597b802015-03-09 12:02:02 -07003102 gnu_nbucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0];
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08003103 // skip symndx
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003104 gnu_maskwords_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[2];
3105 gnu_shift2_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[3];
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08003106
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003107 gnu_bloom_filter_ = reinterpret_cast<ElfW(Addr)*>(load_bias + d->d_un.d_ptr + 16);
Dmitriy Ivanov3597b802015-03-09 12:02:02 -07003108 gnu_bucket_ = reinterpret_cast<uint32_t*>(gnu_bloom_filter_ + gnu_maskwords_);
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08003109 // amend chain for symndx = header[1]
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07003110 gnu_chain_ = gnu_bucket_ + gnu_nbucket_ -
3111 reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08003112
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003113 if (!powerof2(gnu_maskwords_)) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07003114 DL_ERR("invalid maskwords for gnu_hash = 0x%x, in \"%s\" expecting power to two",
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003115 gnu_maskwords_, get_realpath());
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08003116 return false;
3117 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003118 --gnu_maskwords_;
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08003119
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08003120 flags_ |= FLAG_GNU_HASH;
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08003121 break;
3122
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003123 case DT_STRTAB:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003124 strtab_ = reinterpret_cast<const char*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003125 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003126
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07003127 case DT_STRSZ:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003128 strtab_size_ = d->d_un.d_val;
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07003129 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003130
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003131 case DT_SYMTAB:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003132 symtab_ = reinterpret_cast<ElfW(Sym)*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003133 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003134
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003135 case DT_SYMENT:
3136 if (d->d_un.d_val != sizeof(ElfW(Sym))) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003137 DL_ERR("invalid DT_SYMENT: %zd in \"%s\"",
3138 static_cast<size_t>(d->d_un.d_val), get_realpath());
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003139 return false;
3140 }
3141 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003142
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003143 case DT_PLTREL:
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003144#if defined(USE_RELA)
3145 if (d->d_un.d_val != DT_RELA) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003146 DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_RELA", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003147 return false;
3148 }
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003149#else
3150 if (d->d_un.d_val != DT_REL) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003151 DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_REL", get_realpath());
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003152 return false;
3153 }
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07003154#endif
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003155 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003156
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003157 case DT_JMPREL:
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07003158#if defined(USE_RELA)
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003159 plt_rela_ = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07003160#else
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003161 plt_rel_ = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07003162#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003163 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003164
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003165 case DT_PLTRELSZ:
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07003166#if defined(USE_RELA)
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003167 plt_rela_count_ = d->d_un.d_val / sizeof(ElfW(Rela));
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07003168#else
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003169 plt_rel_count_ = d->d_un.d_val / sizeof(ElfW(Rel));
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07003170#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003171 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003172
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003173 case DT_PLTGOT:
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003174#if defined(__mips__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003175 // Used by mips and mips64.
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003176 plt_got_ = reinterpret_cast<ElfW(Addr)**>(load_bias + d->d_un.d_ptr);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07003177#endif
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003178 // Ignore for other platforms... (because RTLD_LAZY is not supported)
3179 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003180
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003181 case DT_DEBUG:
3182 // Set the DT_DEBUG entry to the address of _r_debug for GDB
3183 // if the dynamic table is writable
Chris Dearman99186652014-02-06 20:36:51 -08003184// FIXME: not working currently for N64
3185// The flags for the LOAD and DYNAMIC program headers do not agree.
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07003186// The LOAD section containing the dynamic table has been mapped as
Chris Dearman99186652014-02-06 20:36:51 -08003187// read-only, but the DYNAMIC header claims it is writable.
3188#if !(defined(__mips__) && defined(__LP64__))
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003189 if ((dynamic_flags & PF_W) != 0) {
3190 d->d_un.d_val = reinterpret_cast<uintptr_t>(&_r_debug);
3191 }
Chris Dearman99186652014-02-06 20:36:51 -08003192#endif
Dmitriy Ivanovc6292ea2015-02-13 16:29:50 -08003193 break;
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07003194#if defined(USE_RELA)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003195 case DT_RELA:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003196 rela_ = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003197 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003198
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003199 case DT_RELASZ:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003200 rela_count_ = d->d_un.d_val / sizeof(ElfW(Rela));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003201 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003202
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003203 case DT_ANDROID_RELA:
3204 android_relocs_ = reinterpret_cast<uint8_t*>(load_bias + d->d_un.d_ptr);
3205 break;
3206
3207 case DT_ANDROID_RELASZ:
3208 android_relocs_size_ = d->d_un.d_val;
3209 break;
3210
3211 case DT_ANDROID_REL:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003212 DL_ERR("unsupported DT_ANDROID_REL in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003213 return false;
3214
3215 case DT_ANDROID_RELSZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003216 DL_ERR("unsupported DT_ANDROID_RELSZ in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003217 return false;
3218
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003219 case DT_RELAENT:
3220 if (d->d_un.d_val != sizeof(ElfW(Rela))) {
Dmitriy Ivanovf240aa82014-09-16 23:34:20 -07003221 DL_ERR("invalid DT_RELAENT: %zd", static_cast<size_t>(d->d_un.d_val));
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003222 return false;
3223 }
3224 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003225
Rahul Chaudhryb7feec72017-12-19 15:25:23 -08003226 // Ignored (see DT_RELCOUNT comments for details).
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003227 case DT_RELACOUNT:
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003228 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003229
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003230 case DT_REL:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003231 DL_ERR("unsupported DT_REL in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003232 return false;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003233
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003234 case DT_RELSZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003235 DL_ERR("unsupported DT_RELSZ in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003236 return false;
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003237
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07003238#else
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003239 case DT_REL:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003240 rel_ = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003241 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003242
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003243 case DT_RELSZ:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003244 rel_count_ = d->d_un.d_val / sizeof(ElfW(Rel));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003245 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003246
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003247 case DT_RELENT:
3248 if (d->d_un.d_val != sizeof(ElfW(Rel))) {
Dmitriy Ivanovf240aa82014-09-16 23:34:20 -07003249 DL_ERR("invalid DT_RELENT: %zd", static_cast<size_t>(d->d_un.d_val));
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003250 return false;
3251 }
3252 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003253
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003254 case DT_ANDROID_REL:
3255 android_relocs_ = reinterpret_cast<uint8_t*>(load_bias + d->d_un.d_ptr);
3256 break;
3257
3258 case DT_ANDROID_RELSZ:
3259 android_relocs_size_ = d->d_un.d_val;
3260 break;
3261
3262 case DT_ANDROID_RELA:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003263 DL_ERR("unsupported DT_ANDROID_RELA in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003264 return false;
3265
3266 case DT_ANDROID_RELASZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003267 DL_ERR("unsupported DT_ANDROID_RELASZ in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003268 return false;
3269
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003270 // "Indicates that all RELATIVE relocations have been concatenated together,
3271 // and specifies the RELATIVE relocation count."
3272 //
3273 // TODO: Spec also mentions that this can be used to optimize relocation process;
3274 // Not currently used by bionic linker - ignored.
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003275 case DT_RELCOUNT:
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003276 break;
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003277
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003278 case DT_RELA:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003279 DL_ERR("unsupported DT_RELA in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003280 return false;
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003281
3282 case DT_RELASZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003283 DL_ERR("unsupported DT_RELASZ in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003284 return false;
3285
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07003286#endif
Rahul Chaudhryb7feec72017-12-19 15:25:23 -08003287 case DT_RELR:
3288 relr_ = reinterpret_cast<ElfW(Relr)*>(load_bias + d->d_un.d_ptr);
3289 break;
3290
3291 case DT_RELRSZ:
3292 relr_count_ = d->d_un.d_val / sizeof(ElfW(Relr));
3293 break;
3294
3295 case DT_RELRENT:
3296 if (d->d_un.d_val != sizeof(ElfW(Relr))) {
3297 DL_ERR("invalid DT_RELRENT: %zd", static_cast<size_t>(d->d_un.d_val));
3298 return false;
3299 }
3300 break;
3301
3302 // Ignored (see DT_RELCOUNT comments for details).
3303 case DT_RELRCOUNT:
3304 break;
3305
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003306 case DT_INIT:
Dimitry Ivanov55437462016-07-20 15:33:07 -07003307 init_func_ = reinterpret_cast<linker_ctor_function_t>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003308 DEBUG("%s constructors (DT_INIT) found at %p", get_realpath(), init_func_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003309 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003310
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003311 case DT_FINI:
Dimitry Ivanov55437462016-07-20 15:33:07 -07003312 fini_func_ = reinterpret_cast<linker_dtor_function_t>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003313 DEBUG("%s destructors (DT_FINI) found at %p", get_realpath(), fini_func_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003314 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003315
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003316 case DT_INIT_ARRAY:
Dimitry Ivanov55437462016-07-20 15:33:07 -07003317 init_array_ = reinterpret_cast<linker_ctor_function_t*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003318 DEBUG("%s constructors (DT_INIT_ARRAY) found at %p", get_realpath(), init_array_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003319 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003320
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003321 case DT_INIT_ARRAYSZ:
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -08003322 init_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003323 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003324
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003325 case DT_FINI_ARRAY:
Dimitry Ivanov55437462016-07-20 15:33:07 -07003326 fini_array_ = reinterpret_cast<linker_dtor_function_t*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003327 DEBUG("%s destructors (DT_FINI_ARRAY) found at %p", get_realpath(), fini_array_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003328 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003329
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003330 case DT_FINI_ARRAYSZ:
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -08003331 fini_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003332 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003333
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003334 case DT_PREINIT_ARRAY:
Dimitry Ivanov55437462016-07-20 15:33:07 -07003335 preinit_array_ = reinterpret_cast<linker_ctor_function_t*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003336 DEBUG("%s constructors (DT_PREINIT_ARRAY) found at %p", get_realpath(), preinit_array_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003337 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003338
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003339 case DT_PREINIT_ARRAYSZ:
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -08003340 preinit_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003341 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003342
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003343 case DT_TEXTREL:
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003344#if defined(__LP64__)
Dimitry Ivanov816676e2016-10-19 11:00:28 -07003345 DL_ERR("\"%s\" has text relocations", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003346 return false;
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003347#else
3348 has_text_relocations = true;
3349 break;
3350#endif
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003351
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003352 case DT_SYMBOLIC:
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -07003353 has_DT_SYMBOLIC = true;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003354 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003355
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003356 case DT_NEEDED:
3357 ++needed_count;
3358 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003359
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003360 case DT_FLAGS:
3361 if (d->d_un.d_val & DF_TEXTREL) {
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003362#if defined(__LP64__)
Dimitry Ivanov816676e2016-10-19 11:00:28 -07003363 DL_ERR("\"%s\" has text relocations", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003364 return false;
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003365#else
3366 has_text_relocations = true;
3367#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003368 }
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -07003369 if (d->d_un.d_val & DF_SYMBOLIC) {
3370 has_DT_SYMBOLIC = true;
3371 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003372 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003373
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07003374 case DT_FLAGS_1:
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07003375 set_dt_flags_1(d->d_un.d_val);
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -07003376
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07003377 if ((d->d_un.d_val & ~SUPPORTED_DT_FLAGS_1) != 0) {
Elliott Hughes9076b0c2018-02-28 11:29:45 -08003378 DL_WARN("Warning: \"%s\" has unsupported flags DT_FLAGS_1=%p "
3379 "(ignoring unsupported flags)",
3380 get_realpath(), reinterpret_cast<void*>(d->d_un.d_val));
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07003381 }
3382 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003383#if defined(__mips__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003384 case DT_MIPS_RLD_MAP:
3385 // Set the DT_MIPS_RLD_MAP entry to the address of _r_debug for GDB.
3386 {
3387 r_debug** dp = reinterpret_cast<r_debug**>(load_bias + d->d_un.d_ptr);
3388 *dp = &_r_debug;
3389 }
3390 break;
Lazar Trsic83b44a92016-04-06 13:39:17 +02003391 case DT_MIPS_RLD_MAP_REL:
3392 // Set the DT_MIPS_RLD_MAP_REL entry to the address of _r_debug for GDB.
Raghu Gandham68815722014-12-18 19:12:19 -08003393 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07003394 r_debug** dp = reinterpret_cast<r_debug**>(
3395 reinterpret_cast<ElfW(Addr)>(d) + d->d_un.d_val);
Raghu Gandham68815722014-12-18 19:12:19 -08003396 *dp = &_r_debug;
3397 }
3398 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003399
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003400 case DT_MIPS_RLD_VERSION:
3401 case DT_MIPS_FLAGS:
3402 case DT_MIPS_BASE_ADDRESS:
3403 case DT_MIPS_UNREFEXTNO:
3404 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003405
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003406 case DT_MIPS_SYMTABNO:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003407 mips_symtabno_ = d->d_un.d_val;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003408 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003409
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003410 case DT_MIPS_LOCAL_GOTNO:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003411 mips_local_gotno_ = d->d_un.d_val;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003412 break;
3413
3414 case DT_MIPS_GOTSYM:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003415 mips_gotsym_ = d->d_un.d_val;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003416 break;
3417#endif
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003418 // Ignored: "Its use has been superseded by the DF_BIND_NOW flag"
3419 case DT_BIND_NOW:
3420 break;
3421
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003422 case DT_VERSYM:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003423 versym_ = reinterpret_cast<ElfW(Versym)*>(load_bias + d->d_un.d_ptr);
3424 break;
3425
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003426 case DT_VERDEF:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003427 verdef_ptr_ = load_bias + d->d_un.d_ptr;
3428 break;
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003429 case DT_VERDEFNUM:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003430 verdef_cnt_ = d->d_un.d_val;
3431 break;
3432
Alexander Ivchenkoe8314332014-12-02 15:32:25 +03003433 case DT_VERNEED:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003434 verneed_ptr_ = load_bias + d->d_un.d_ptr;
3435 break;
3436
Alexander Ivchenkoe8314332014-12-02 15:32:25 +03003437 case DT_VERNEEDNUM:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003438 verneed_cnt_ = d->d_un.d_val;
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003439 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003440
Evgenii Stepanov68650822015-06-10 13:38:39 -07003441 case DT_RUNPATH:
3442 // this is parsed after we have strtab initialized (see below).
3443 break;
3444
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003445 default:
Dmitriy Ivanov8f61d992014-09-16 14:31:06 -07003446 if (!relocating_linker) {
Elliott Hughes45a93c12018-03-23 18:46:07 -07003447 if (d->d_tag == DT_TLSDESC_GOT || d->d_tag == DT_TLSDESC_PLT) {
3448 DL_ERR("unsupported ELF TLS DT entry in \"%s\"", get_realpath());
3449 return false;
3450 }
3451
Elliott Hughes6eae4cc2017-08-30 09:02:33 -07003452 const char* tag_name;
3453 if (d->d_tag == DT_RPATH) {
3454 tag_name = "DT_RPATH";
3455 } else if (d->d_tag == DT_ENCODING) {
3456 tag_name = "DT_ENCODING";
3457 } else if (d->d_tag >= DT_LOOS && d->d_tag <= DT_HIOS) {
3458 tag_name = "unknown OS-specific";
3459 } else if (d->d_tag >= DT_LOPROC && d->d_tag <= DT_HIPROC) {
3460 tag_name = "unknown processor-specific";
3461 } else {
3462 tag_name = "unknown";
3463 }
Elliott Hughes9076b0c2018-02-28 11:29:45 -08003464 DL_WARN("Warning: \"%s\" unused DT entry: %s (type %p arg %p) (ignoring)",
Elliott Hughes6eae4cc2017-08-30 09:02:33 -07003465 get_realpath(),
3466 tag_name,
3467 reinterpret_cast<void*>(d->d_tag),
3468 reinterpret_cast<void*>(d->d_un.d_val));
Dmitriy Ivanov8f61d992014-09-16 14:31:06 -07003469 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003470 break;
Brian Carlstromd4ee82d2013-02-28 15:58:45 -08003471 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003472 }
3473
Duane Sandbc425c72015-06-01 16:29:14 -07003474#if defined(__mips__) && !defined(__LP64__)
3475 if (!mips_check_and_adjust_fp_modes()) {
3476 return false;
3477 }
3478#endif
3479
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003480 DEBUG("si->base = %p, si->strtab = %p, si->symtab = %p",
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003481 reinterpret_cast<void*>(base), strtab_, symtab_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003482
3483 // Sanity checks.
3484 if (relocating_linker && needed_count != 0) {
3485 DL_ERR("linker cannot have DT_NEEDED dependencies on other libraries");
3486 return false;
3487 }
Dmitriy Ivanov3597b802015-03-09 12:02:02 -07003488 if (nbucket_ == 0 && gnu_nbucket_ == 0) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003489 DL_ERR("empty/missing DT_HASH/DT_GNU_HASH in \"%s\" "
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003490 "(new hash type from the future?)", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003491 return false;
3492 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003493 if (strtab_ == 0) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003494 DL_ERR("empty/missing DT_STRTAB in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003495 return false;
3496 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003497 if (symtab_ == 0) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003498 DL_ERR("empty/missing DT_SYMTAB in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003499 return false;
3500 }
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003501
Dmitriy Ivanov624b8f12015-06-08 10:41:33 -07003502 // second pass - parse entries relying on strtab
3503 for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
Evgenii Stepanov68650822015-06-10 13:38:39 -07003504 switch (d->d_tag) {
3505 case DT_SONAME:
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07003506 set_soname(get_string(d->d_un.d_val));
Evgenii Stepanov68650822015-06-10 13:38:39 -07003507 break;
3508 case DT_RUNPATH:
Evgenii Stepanov68650822015-06-10 13:38:39 -07003509 set_dt_runpath(get_string(d->d_un.d_val));
3510 break;
Dmitriy Ivanov624b8f12015-06-08 10:41:33 -07003511 }
3512 }
3513
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003514 // Before M release linker was using basename in place of soname.
Dmitriy Ivanov19133522015-06-02 17:36:54 -07003515 // In the case when dt_soname is absent some apps stop working
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003516 // because they can't find dt_needed library by soname.
Elliott Hughes9076b0c2018-02-28 11:29:45 -08003517 // This workaround should keep them working. (Applies only
3518 // for apps targeting sdk version < M.) Make an exception for
3519 // the main executable and linker; they do not need to have dt_soname.
3520 // TODO: >= O the linker doesn't need this workaround.
Dimitry Ivanov3f660572016-09-09 10:00:39 -07003521 if (soname_ == nullptr &&
3522 this != solist_get_somain() &&
3523 (flags_ & FLAG_LINKER) == 0 &&
Elliott Hughes5bc78c82016-11-16 11:35:43 -08003524 get_application_target_sdk_version() < __ANDROID_API_M__) {
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003525 soname_ = basename(realpath_.c_str());
Elliott Hughes9076b0c2018-02-28 11:29:45 -08003526 DL_WARN_documented_change(__ANDROID_API_M__,
3527 "missing-soname-enforced-for-api-level-23",
3528 "\"%s\" has no DT_SONAME (will use %s instead)",
3529 get_realpath(), soname_);
3530
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07003531 // 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 -07003532 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003533 return true;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07003534}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003535
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003536bool soinfo::link_image(const soinfo_list_t& global_group, const soinfo_list_t& local_group,
3537 const android_dlextinfo* extinfo) {
dimitry965d06d2017-11-28 16:03:07 +01003538 if (is_image_linked()) {
3539 // already linked.
3540 return true;
3541 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003542
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08003543 local_group_root_ = local_group.front();
3544 if (local_group_root_ == nullptr) {
3545 local_group_root_ = this;
3546 }
3547
Dmitriy Ivanov19133522015-06-02 17:36:54 -07003548 if ((flags_ & FLAG_LINKER) == 0 && local_group_root_ == this) {
3549 target_sdk_version_ = get_application_target_sdk_version();
3550 }
3551
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003552 VersionTracker version_tracker;
3553
3554 if (!version_tracker.init(this)) {
3555 return false;
3556 }
3557
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003558#if !defined(__LP64__)
3559 if (has_text_relocations) {
Elliott Hughes5bc78c82016-11-16 11:35:43 -08003560 // Fail if app is targeting M or above.
Elliott Hughes9076b0c2018-02-28 11:29:45 -08003561 int app_target_api_level = get_application_target_sdk_version();
3562 if (app_target_api_level >= __ANDROID_API_M__) {
Elliott Hughes763f6e12017-04-10 09:52:33 -07003563 DL_ERR_AND_LOG("\"%s\" has text relocations (https://android.googlesource.com/platform/"
3564 "bionic/+/master/android-changes-for-ndk-developers.md#Text-Relocations-"
3565 "Enforced-for-API-level-23)", get_realpath());
Dmitriy Ivanove4ad91f2015-06-12 15:00:31 -07003566 return false;
3567 }
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003568 // Make segments writable to allow text relocations to work properly. We will later call
Dmitriy Ivanov7e039932015-10-01 14:02:19 -07003569 // phdr_table_protect_segments() after all of them are applied.
Elliott Hughes9076b0c2018-02-28 11:29:45 -08003570 DL_WARN_documented_change(__ANDROID_API_M__,
3571 "Text-Relocations-Enforced-for-API-level-23",
3572 "\"%s\" has text relocations",
3573 get_realpath());
Dimitry Ivanov769b33f2016-07-21 11:33:40 -07003574 add_dlwarning(get_realpath(), "text relocations");
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003575 if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
Elliott Hughes9076b0c2018-02-28 11:29:45 -08003576 DL_ERR("can't unprotect loadable segments for \"%s\": %s", get_realpath(), strerror(errno));
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003577 return false;
3578 }
3579 }
3580#endif
3581
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003582 if (android_relocs_ != nullptr) {
3583 // check signature
3584 if (android_relocs_size_ > 3 &&
3585 android_relocs_[0] == 'A' &&
3586 android_relocs_[1] == 'P' &&
Dmitriy Ivanov18870d32015-04-22 13:10:04 -07003587 android_relocs_[2] == 'S' &&
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003588 android_relocs_[3] == '2') {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003589 DEBUG("[ android relocating %s ]", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003590
3591 bool relocated = false;
3592 const uint8_t* packed_relocs = android_relocs_ + 4;
3593 const size_t packed_relocs_size = android_relocs_size_ - 4;
3594
Dmitriy Ivanov18870d32015-04-22 13:10:04 -07003595 relocated = relocate(
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003596 version_tracker,
Dmitriy Ivanov18870d32015-04-22 13:10:04 -07003597 packed_reloc_iterator<sleb128_decoder>(
3598 sleb128_decoder(packed_relocs, packed_relocs_size)),
3599 global_group, local_group);
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003600
3601 if (!relocated) {
3602 return false;
3603 }
3604 } else {
3605 DL_ERR("bad android relocation header.");
3606 return false;
3607 }
3608 }
3609
Rahul Chaudhryb7feec72017-12-19 15:25:23 -08003610 if (relr_ != nullptr) {
3611 DEBUG("[ relocating %s relr ]", get_realpath());
3612 if (!relocate_relr()) {
3613 return false;
3614 }
3615 }
3616
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07003617#if defined(USE_RELA)
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003618 if (rela_ != nullptr) {
Rahul Chaudhryb7feec72017-12-19 15:25:23 -08003619 DEBUG("[ relocating %s rela ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003620 if (!relocate(version_tracker,
3621 plain_reloc_iterator(rela_, rela_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003622 return false;
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07003623 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003624 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003625 if (plt_rela_ != nullptr) {
Rahul Chaudhryb7feec72017-12-19 15:25:23 -08003626 DEBUG("[ relocating %s plt rela ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003627 if (!relocate(version_tracker,
3628 plain_reloc_iterator(plt_rela_, plt_rela_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003629 return false;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003630 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003631 }
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07003632#else
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003633 if (rel_ != nullptr) {
Rahul Chaudhryb7feec72017-12-19 15:25:23 -08003634 DEBUG("[ relocating %s rel ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003635 if (!relocate(version_tracker,
3636 plain_reloc_iterator(rel_, rel_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003637 return false;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003638 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003639 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003640 if (plt_rel_ != nullptr) {
Rahul Chaudhryb7feec72017-12-19 15:25:23 -08003641 DEBUG("[ relocating %s plt rel ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003642 if (!relocate(version_tracker,
3643 plain_reloc_iterator(plt_rel_, plt_rel_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003644 return false;
Brigid Smithc5a13ef2014-07-23 11:22:25 -07003645 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003646 }
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07003647#endif
Brigid Smithc5a13ef2014-07-23 11:22:25 -07003648
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07003649#if defined(__mips__)
Dmitriy Ivanovf39cb632015-04-30 20:17:03 -07003650 if (!mips_relocate_got(version_tracker, global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003651 return false;
3652 }
Raghu Gandhamd7daacb2012-07-31 12:07:22 -07003653#endif
3654
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003655 DEBUG("[ finished linking %s ]", get_realpath());
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003656
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003657#if !defined(__LP64__)
3658 if (has_text_relocations) {
3659 // All relocations are done, we can protect our segments back to read-only.
3660 if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
3661 DL_ERR("can't protect segments for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003662 get_realpath(), strerror(errno));
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003663 return false;
3664 }
3665 }
3666#endif
3667
Mingwei Shibe910522015-11-12 07:02:14 +00003668 // We can also turn on GNU RELRO protection if we're not linking the dynamic linker
3669 // itself --- it can't make system calls yet, and will have to call protect_relro later.
3670 if (!is_linker() && !protect_relro()) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003671 return false;
3672 }
Nick Kralevich9ec0f032012-02-28 10:40:00 -08003673
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003674 /* Handle serializing/sharing the RELRO segment */
3675 if (extinfo && (extinfo->flags & ANDROID_DLEXT_WRITE_RELRO)) {
3676 if (phdr_table_serialize_gnu_relro(phdr, phnum, load_bias,
3677 extinfo->relro_fd) < 0) {
3678 DL_ERR("failed serializing GNU RELRO section for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003679 get_realpath(), strerror(errno));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003680 return false;
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +00003681 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003682 } else if (extinfo && (extinfo->flags & ANDROID_DLEXT_USE_RELRO)) {
3683 if (phdr_table_map_gnu_relro(phdr, phnum, load_bias,
3684 extinfo->relro_fd) < 0) {
3685 DL_ERR("failed mapping GNU RELRO section for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003686 get_realpath(), strerror(errno));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003687 return false;
3688 }
3689 }
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +00003690
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003691 notify_gdb_of_load(this);
dimitry965d06d2017-11-28 16:03:07 +01003692 set_image_linked();
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003693 return true;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003694}
3695
Mingwei Shibe910522015-11-12 07:02:14 +00003696bool soinfo::protect_relro() {
3697 if (phdr_table_protect_gnu_relro(phdr, phnum, load_bias) < 0) {
3698 DL_ERR("can't enable GNU RELRO protection for \"%s\": %s",
3699 get_realpath(), strerror(errno));
3700 return false;
3701 }
3702 return true;
3703}
3704
Jiyong Park02586a22017-05-20 01:01:24 +09003705static std::vector<android_namespace_t*> init_default_namespace_no_config(bool is_asan) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003706 g_default_namespace.set_isolated(false);
Dimitry Ivanov77ad6422017-03-06 13:02:29 -08003707 auto default_ld_paths = is_asan ? kAsanDefaultLdPaths : kDefaultLdPaths;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003708
neo.chae2589f9d2016-10-04 11:00:27 +09003709 char real_path[PATH_MAX];
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003710 std::vector<std::string> ld_default_paths;
Dimitry Ivanov77ad6422017-03-06 13:02:29 -08003711 for (size_t i = 0; default_ld_paths[i] != nullptr; ++i) {
3712 if (realpath(default_ld_paths[i], real_path) != nullptr) {
neo.chae2589f9d2016-10-04 11:00:27 +09003713 ld_default_paths.push_back(real_path);
3714 } else {
Dimitry Ivanov77ad6422017-03-06 13:02:29 -08003715 ld_default_paths.push_back(default_ld_paths[i]);
neo.chae2589f9d2016-10-04 11:00:27 +09003716 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003717 }
3718
3719 g_default_namespace.set_default_library_paths(std::move(ld_default_paths));
Jiyong Park02586a22017-05-20 01:01:24 +09003720
3721 std::vector<android_namespace_t*> namespaces;
3722 namespaces.push_back(&g_default_namespace);
3723 return namespaces;
Dimitry Ivanov4cabfaa2017-03-07 11:19:05 -08003724}
3725
Logan Chien21e496c2018-05-08 17:52:18 +08003726static std::string get_ld_config_file_vndk_path() {
Logan Chiendd184722018-05-08 20:17:26 +08003727 if (android::base::GetBoolProperty("ro.vndk.lite", false)) {
3728 return kLdConfigVndkLiteFilePath;
3729 }
3730
Logan Chien21e496c2018-05-08 17:52:18 +08003731 std::string ld_config_file_vndk = kLdConfigFilePath;
3732 size_t insert_pos = ld_config_file_vndk.find_last_of('.');
3733 if (insert_pos == std::string::npos) {
3734 insert_pos = ld_config_file_vndk.length();
3735 }
3736 ld_config_file_vndk.insert(insert_pos, Config::get_vndk_version_string('.'));
3737 return ld_config_file_vndk;
3738}
3739
3740static std::string get_ld_config_file_path() {
3741#ifdef USE_LD_CONFIG_FILE
3742 // This is a debugging/testing only feature. Must not be available on
3743 // production builds.
3744 const char* ld_config_file_env = getenv("LD_CONFIG_FILE");
3745 if (ld_config_file_env != nullptr && file_exists(ld_config_file_env)) {
3746 return ld_config_file_env;
3747 }
3748#endif
3749
3750 if (file_exists(kLdConfigArchFilePath)) {
3751 return kLdConfigArchFilePath;
3752 }
3753
3754 std::string ld_config_file_vndk = get_ld_config_file_vndk_path();
3755 if (file_exists(ld_config_file_vndk.c_str())) {
3756 return ld_config_file_vndk;
3757 }
3758
3759 return kLdConfigFilePath;
3760}
3761
Jiyong Park02586a22017-05-20 01:01:24 +09003762std::vector<android_namespace_t*> init_default_namespaces(const char* executable_path) {
Dimitry Ivanov4cabfaa2017-03-07 11:19:05 -08003763 g_default_namespace.set_name("(default)");
3764
3765 soinfo* somain = solist_get_somain();
3766
3767 const char *interp = phdr_table_get_interpreter_name(somain->phdr, somain->phnum,
3768 somain->load_bias);
Dan Willemsen7ccc50d2017-09-18 21:28:14 -07003769 const char* bname = (interp != nullptr) ? basename(interp) : nullptr;
Dimitry Ivanov4cabfaa2017-03-07 11:19:05 -08003770
3771 g_is_asan = bname != nullptr &&
3772 (strcmp(bname, "linker_asan") == 0 ||
3773 strcmp(bname, "linker_asan64") == 0);
3774
3775 const Config* config = nullptr;
3776
3777 std::string error_msg;
3778
Logan Chien21e496c2018-05-08 17:52:18 +08003779 std::string ld_config_file_path = get_ld_config_file_path();
Jiyong Park02586a22017-05-20 01:01:24 +09003780
Logan Chien21e496c2018-05-08 17:52:18 +08003781 if (!Config::read_binary_config(ld_config_file_path.c_str(),
Dimitry Ivanov4cabfaa2017-03-07 11:19:05 -08003782 executable_path,
3783 g_is_asan,
3784 &config,
3785 &error_msg)) {
3786 if (!error_msg.empty()) {
Elliott Hughes9076b0c2018-02-28 11:29:45 -08003787 DL_WARN("Warning: couldn't read \"%s\" for \"%s\" (using default configuration instead): %s",
Logan Chien21e496c2018-05-08 17:52:18 +08003788 ld_config_file_path.c_str(),
Dimitry Ivanov4cabfaa2017-03-07 11:19:05 -08003789 executable_path,
3790 error_msg.c_str());
3791 }
3792 config = nullptr;
3793 }
3794
3795 if (config == nullptr) {
Jiyong Park02586a22017-05-20 01:01:24 +09003796 return init_default_namespace_no_config(g_is_asan);
Dimitry Ivanov4cabfaa2017-03-07 11:19:05 -08003797 }
3798
3799 const auto& namespace_configs = config->namespace_configs();
3800 std::unordered_map<std::string, android_namespace_t*> namespaces;
3801
3802 // 1. Initialize default namespace
3803 const NamespaceConfig* default_ns_config = config->default_namespace_config();
3804
3805 g_default_namespace.set_isolated(default_ns_config->isolated());
3806 g_default_namespace.set_default_library_paths(default_ns_config->search_paths());
3807 g_default_namespace.set_permitted_paths(default_ns_config->permitted_paths());
3808
3809 namespaces[default_ns_config->name()] = &g_default_namespace;
Justin Yun90de9f02017-07-07 16:21:53 +09003810 if (default_ns_config->visible()) {
3811 g_exported_namespaces[default_ns_config->name()] = &g_default_namespace;
3812 }
Dimitry Ivanov4cabfaa2017-03-07 11:19:05 -08003813
3814 // 2. Initialize other namespaces
3815
3816 for (auto& ns_config : namespace_configs) {
3817 if (namespaces.find(ns_config->name()) != namespaces.end()) {
3818 continue;
3819 }
3820
3821 android_namespace_t* ns = new (g_namespace_allocator.alloc()) android_namespace_t();
3822 ns->set_name(ns_config->name());
3823 ns->set_isolated(ns_config->isolated());
3824 ns->set_default_library_paths(ns_config->search_paths());
3825 ns->set_permitted_paths(ns_config->permitted_paths());
3826
3827 namespaces[ns_config->name()] = ns;
Jiyong Park01de74e2017-04-03 23:10:37 +09003828 if (ns_config->visible()) {
3829 g_exported_namespaces[ns_config->name()] = ns;
3830 }
Dimitry Ivanov4cabfaa2017-03-07 11:19:05 -08003831 }
3832
3833 // 3. Establish links between namespaces
3834 for (auto& ns_config : namespace_configs) {
3835 auto it_from = namespaces.find(ns_config->name());
3836 CHECK(it_from != namespaces.end());
3837 android_namespace_t* namespace_from = it_from->second;
3838 for (const NamespaceLinkConfig& ns_link : ns_config->links()) {
3839 auto it_to = namespaces.find(ns_link.ns_name());
3840 CHECK(it_to != namespaces.end());
3841 android_namespace_t* namespace_to = it_to->second;
Logan Chien9ee45912018-01-18 12:05:09 +08003842 if (ns_link.allow_all_shared_libs()) {
3843 link_namespaces_all_libs(namespace_from, namespace_to);
3844 } else {
3845 link_namespaces(namespace_from, namespace_to, ns_link.shared_libs().c_str());
3846 }
Dimitry Ivanov4cabfaa2017-03-07 11:19:05 -08003847 }
3848 }
3849 // we can no longer rely on the fact that libdl.so is part of default namespace
3850 // this is why we want to add ld-android.so to all namespaces from ld.config.txt
3851 soinfo* ld_android_so = solist_get_head();
dimitry69c68c42018-05-09 15:22:38 +02003852
3853 // we also need vdso to be available for all namespaces (if present)
3854 soinfo* vdso = solist_get_vdso();
Dimitry Ivanov4cabfaa2017-03-07 11:19:05 -08003855 for (auto it : namespaces) {
3856 it.second->add_soinfo(ld_android_so);
dimitry69c68c42018-05-09 15:22:38 +02003857 if (vdso != nullptr) {
3858 it.second->add_soinfo(vdso);
3859 }
Jiyong Park02586a22017-05-20 01:01:24 +09003860 // somain and ld_preloads are added to these namespaces after LD_PRELOAD libs are linked
Dimitry Ivanov4cabfaa2017-03-07 11:19:05 -08003861 }
3862
3863 set_application_target_sdk_version(config->target_sdk_version());
Jiyong Park02586a22017-05-20 01:01:24 +09003864
3865 std::vector<android_namespace_t*> created_namespaces;
3866 created_namespaces.reserve(namespaces.size());
3867 for (auto kv : namespaces) {
3868 created_namespaces.push_back(kv.second);
3869 }
3870 return created_namespaces;
Dimitry Ivanov4cabfaa2017-03-07 11:19:05 -08003871}
Jiyong Park01de74e2017-04-03 23:10:37 +09003872
3873// This function finds a namespace exported in ld.config.txt by its name.
3874// A namespace can be exported by setting .visible property to true.
3875android_namespace_t* get_exported_namespace(const char* name) {
3876 if (name == nullptr) {
3877 return nullptr;
3878 }
3879 auto it = g_exported_namespaces.find(std::string(name));
3880 if (it == g_exported_namespaces.end()) {
3881 return nullptr;
3882 }
3883 return it->second;
3884}