diff options
author | Scott Lobdell <slobdell@google.com> | 2019-08-25 12:20:54 -0700 |
---|---|---|
committer | Scott Lobdell <slobdell@google.com> | 2019-08-25 12:20:54 -0700 |
commit | 4f9bfdcaca2414c8959986f0a4d73f16cb15e1c4 (patch) | |
tree | 540bab5498d276cbbfad24c48a7ff989ee8b920a /linker | |
parent | bfda022dd6fbbcea60e9f52496d90ece514b32da (diff) | |
parent | f77cc9b224c35fa7d1d71e7c374ef19e47b5f6a5 (diff) |
Merge RP1A.190822.001
Change-Id: Iaf90835a99d87f6246798efd2cea6fe9f750ea18
Diffstat (limited to 'linker')
-rw-r--r-- | linker/Android.bp | 5 | ||||
-rw-r--r-- | linker/dlfcn.cpp | 4 | ||||
-rw-r--r-- | linker/ld.config.format.md | 6 | ||||
-rw-r--r-- | linker/ldd | 5 | ||||
-rw-r--r-- | linker/linker.cpp | 145 | ||||
-rw-r--r-- | linker/linker.h | 12 | ||||
-rw-r--r-- | linker/linker_main.cpp | 82 | ||||
-rw-r--r-- | linker/linker_namespaces.h | 9 | ||||
-rw-r--r-- | linker/linker_relocs.h | 6 | ||||
-rw-r--r-- | linker/linker_sdk_versions.cpp | 11 | ||||
-rw-r--r-- | linker/linker_soinfo.cpp | 10 | ||||
-rw-r--r-- | linker/linker_soinfo.h | 3 |
12 files changed, 223 insertions, 75 deletions
diff --git a/linker/Android.bp b/linker/Android.bp index 5e7a921a4..bdb7c178a 100644 --- a/linker/Android.bp +++ b/linker/Android.bp @@ -177,11 +177,6 @@ cc_defaults { "-Wextra", "-Wunused", "-Werror", - - // Define _USING_LIBCXX so <stdatomic.h> defers to the <atomic> header. When a Soong module - // uses the platform libc++, Soong automatically passes this macro, but the dynamic linker - // links against libc++ manually. - "-D_USING_LIBCXX", ], // TODO: split out the asflags. diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp index 5a47272c1..18301e0e2 100644 --- a/linker/dlfcn.cpp +++ b/linker/dlfcn.cpp @@ -308,11 +308,11 @@ static uint8_t __libdl_info_buf[sizeof(soinfo)] __attribute__((aligned(8))); static soinfo* __libdl_info = nullptr; // This is used by the dynamic linker. Every process gets these symbols for free. -soinfo* get_libdl_info(const char* linker_path, const soinfo& linker_si) { +soinfo* get_libdl_info(const soinfo& linker_si) { CHECK((linker_si.flags_ & FLAG_GNU_HASH) != 0); if (__libdl_info == nullptr) { - __libdl_info = new (__libdl_info_buf) soinfo(&g_default_namespace, linker_path, nullptr, 0, 0); + __libdl_info = new (__libdl_info_buf) soinfo(&g_default_namespace, nullptr, nullptr, 0, 0); __libdl_info->flags_ |= (FLAG_LINKED | FLAG_GNU_HASH); __libdl_info->strtab_ = linker_si.strtab_; __libdl_info->symtab_ = linker_si.symtab_; diff --git a/linker/ld.config.format.md b/linker/ld.config.format.md index faf5cc8a6..f9fbcde3f 100644 --- a/linker/ld.config.format.md +++ b/linker/ld.config.format.md @@ -25,7 +25,7 @@ configuration using set of properties described in example below. ## Example ``` -# The following line maps section to a dir. Binraies ran from this location will use namespaces +# The following line maps section to a dir. Binaries ran from this location will use namespaces # configuration specified in [example_section] below dir.example_section=/system/bin/example @@ -38,7 +38,7 @@ dir.example_section=/system/bin/example # default value is false enable.target.sdk.version = true -# This property can be used to declare additional namespaces.Note that there is always the default +# This property can be used to declare additional namespaces. Note that there is always the default # namespace. The default namespace is the namespace for the main executable. This list is # comma-separated. additional.namespaces = ns1 @@ -65,7 +65,7 @@ namespace.default.asan.permitted.paths = /data/${LIB} # This declares linked namespaces - comma separated list. namespace.default.links = ns1 -# For every link define list of shared libraries. This is list of the libraries accessilbe from +# For every link define list of shared libraries. This is list of the libraries accessible from # default namespace but loaded in the linked namespace. namespace.default.link.ns1.shared_libs = libexternal.so:libother.so diff --git a/linker/ldd b/linker/ldd index 3a0aff91a..6bc49b4b1 100644 --- a/linker/ldd +++ b/linker/ldd @@ -10,7 +10,8 @@ function error() { [ $# -eq 1 ] || error "usage: ldd FILE" -case `file -L "$1"` in +what=$(file -L "$1") +case "$what" in *32-bit*) linker --list "$1" ;; @@ -18,6 +19,6 @@ case `file -L "$1"` in linker64 --list "$1" ;; *) - error "$1: not an ELF file" + error "$what" ;; esac diff --git a/linker/linker.cpp b/linker/linker.cpp index 32dce3805..d581dd8ce 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -76,6 +76,7 @@ static std::unordered_map<void*, size_t> g_dso_handle_counters; +static bool g_anonymous_namespace_set = false; static android_namespace_t* g_anonymous_namespace = &g_default_namespace; static std::unordered_map<std::string, android_namespace_t*> g_exported_namespaces; @@ -90,6 +91,8 @@ static const char* const kLdConfigArchFilePath = "/system/etc/ld.config." ABI_ST static const char* const kLdConfigFilePath = "/system/etc/ld.config.txt"; static const char* const kLdConfigVndkLiteFilePath = "/system/etc/ld.config.vndk_lite.txt"; +static const char* const kLdGeneratedConfigFilePath = "/dev/linkerconfig/ld.config.txt"; + #if defined(__LP64__) static const char* const kSystemLibDir = "/system/lib64"; static const char* const kOdmLibDir = "/odm/lib64"; @@ -270,8 +273,6 @@ static bool translateSystemPathToApexPath(const char* name, std::string* out_nam static std::vector<std::string> g_ld_preload_names; -static bool g_anonymous_namespace_initialized; - #if STATS struct linker_stats_t { int count[kRelocMax]; @@ -282,6 +283,16 @@ static linker_stats_t linker_stats; void count_relocation(RelocationKind kind) { ++linker_stats.count[kind]; } + +void print_linker_stats() { + PRINT("RELO STATS: %s: %d abs, %d rel, %d copy, %d symbol (%d cached)", + g_argv[0], + linker_stats.count[kRelocAbsolute], + linker_stats.count[kRelocRelative], + linker_stats.count[kRelocCopy], + linker_stats.count[kRelocSymbol], + linker_stats.count[kRelocSymbolCached]); +} #else void count_relocation(RelocationKind) { } @@ -393,16 +404,23 @@ static void parse_LD_LIBRARY_PATH(const char* path) { } static bool realpath_fd(int fd, std::string* realpath) { - std::vector<char> buf(PATH_MAX), proc_self_fd(PATH_MAX); - async_safe_format_buffer(&proc_self_fd[0], proc_self_fd.size(), "/proc/self/fd/%d", fd); - if (readlink(&proc_self_fd[0], &buf[0], buf.size()) == -1) { + // proc_self_fd needs to be large enough to hold "/proc/self/fd/" plus an + // integer, plus the NULL terminator. + char proc_self_fd[32]; + // We want to statically allocate this large buffer so that we don't grow + // the stack by too much. + static char buf[PATH_MAX]; + + async_safe_format_buffer(proc_self_fd, sizeof(proc_self_fd), "/proc/self/fd/%d", fd); + auto length = readlink(proc_self_fd, buf, sizeof(buf)); + if (length == -1) { if (!is_first_stage_init()) { - PRINT("readlink(\"%s\") failed: %s [fd=%d]", &proc_self_fd[0], strerror(errno), fd); + PRINT("readlink(\"%s\") failed: %s [fd=%d]", proc_self_fd, strerror(errno), fd); } return false; } - *realpath = &buf[0]; + realpath->assign(buf, length); return true; } @@ -934,7 +952,9 @@ static const ElfW(Sym)* dlsym_linear_lookup(android_namespace_t* ns, } soinfo* find_containing_library(const void* p) { - ElfW(Addr) address = reinterpret_cast<ElfW(Addr)>(p); + // Addresses within a library may be tagged if they point to globals. Untag + // them so that the bounds check succeeds. + ElfW(Addr) address = reinterpret_cast<ElfW(Addr)>(untag_address(p)); for (soinfo* si = solist_get_head(); si != nullptr; si = si->next) { if (address < si->base || address - si->base >= si->size) { continue; @@ -1215,12 +1235,14 @@ static bool find_loaded_library_by_inode(android_namespace_t* ns, off64_t file_offset, bool search_linked_namespaces, soinfo** candidate) { + if (file_stat.st_dev == 0 || file_stat.st_ino == 0) { + *candidate = nullptr; + return false; + } auto predicate = [&](soinfo* si) { - return si->get_st_dev() != 0 && - si->get_st_ino() != 0 && + return si->get_st_ino() == file_stat.st_ino && si->get_st_dev() == file_stat.st_dev && - si->get_st_ino() == file_stat.st_ino && si->get_file_offset() == file_offset; }; @@ -1882,6 +1904,9 @@ bool find_libraries(android_namespace_t* ns, // flag is set. link_extinfo = extinfo; } + if (__libc_shared_globals()->load_hook) { + __libc_shared_globals()->load_hook(si->load_bias, si->phdr, si->phnum); + } if (!si->link_image(global_group, local_group, link_extinfo, &relro_fd_offset) || !get_cfi_shadow()->AfterLoad(si, solist_get_head())) { return false; @@ -2020,6 +2045,9 @@ static void soinfo_unload_impl(soinfo* root) { si); notify_gdb_of_unload(si); unregister_soinfo_tls(si); + if (__libc_shared_globals()->unload_hook) { + __libc_shared_globals()->unload_hook(si->load_bias, si->phdr, si->phnum); + } get_cfi_shadow()->BeforeUnload(si); soinfo_free(si); } @@ -2452,14 +2480,29 @@ int do_dlclose(void* handle) { return 0; } -bool init_anonymous_namespace(const char* shared_lib_sonames, const char* library_search_path) { - if (g_anonymous_namespace_initialized) { - DL_ERR("anonymous namespace has already been initialized."); - return false; +// Make ns as the anonymous namespace that is a namespace used when +// we fail to determine the caller address (e.g., call from mono-jited code) +// Since there can be multiple anonymous namespace in a process, subsequent +// call to this function causes an error. +static bool set_anonymous_namespace(android_namespace_t* ns) { + if (!g_anonymous_namespace_set && ns != nullptr) { + CHECK(ns->is_also_used_as_anonymous()); + g_anonymous_namespace = ns; + g_anonymous_namespace_set = true; + return true; } + return false; +} +// TODO(b/130388701) remove this. Currently, this is used only for testing +// where we don't have classloader namespace. +bool init_anonymous_namespace(const char* shared_lib_sonames, const char* library_search_path) { ProtectedDataGuard guard; + // Test-only feature: we need to change the anonymous namespace multiple times + // while the test is running. + g_anonymous_namespace_set = false; + // create anonymous namespace // When the caller is nullptr - create_namespace will take global group // from the anonymous namespace, which is fine because anonymous namespace @@ -2469,21 +2512,18 @@ bool init_anonymous_namespace(const char* shared_lib_sonames, const char* librar "(anonymous)", nullptr, library_search_path, - ANDROID_NAMESPACE_TYPE_ISOLATED, + ANDROID_NAMESPACE_TYPE_ISOLATED | + ANDROID_NAMESPACE_TYPE_ALSO_USED_AS_ANONYMOUS, nullptr, &g_default_namespace); - if (anon_ns == nullptr) { - return false; - } + CHECK(anon_ns != nullptr); if (!link_namespaces(anon_ns, &g_default_namespace, shared_lib_sonames)) { + // TODO: delete anon_ns return false; } - g_anonymous_namespace = anon_ns; - g_anonymous_namespace_initialized = true; - return true; } @@ -2523,6 +2563,7 @@ android_namespace_t* create_namespace(const void* caller_addr, ns->set_name(name); ns->set_isolated((type & ANDROID_NAMESPACE_TYPE_ISOLATED) != 0); ns->set_greylist_enabled((type & ANDROID_NAMESPACE_TYPE_GREYLIST_ENABLED) != 0); + ns->set_also_used_as_anonymous((type & ANDROID_NAMESPACE_TYPE_ALSO_USED_AS_ANONYMOUS) != 0); if ((type & ANDROID_NAMESPACE_TYPE_SHARED) != 0) { // append parent namespace paths. @@ -2554,6 +2595,16 @@ android_namespace_t* create_namespace(const void* caller_addr, ns->set_default_library_paths(std::move(default_library_paths)); ns->set_permitted_paths(std::move(permitted_paths)); + if (ns->is_also_used_as_anonymous() && !set_anonymous_namespace(ns)) { + DL_ERR("failed to set namespace: [name=\"%s\", ld_library_path=\"%s\", default_library_paths=\"%s\"" + " permitted_paths=\"%s\"] as the anonymous namespace", + ns->get_name(), + android::base::Join(ns->get_ld_library_paths(), ':').c_str(), + android::base::Join(ns->get_default_library_paths(), ':').c_str(), + android::base::Join(ns->get_permitted_paths(), ':').c_str()); + return nullptr; + } + return ns; } @@ -2874,6 +2925,17 @@ bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& r const size_t tls_tp_base = __libc_shared_globals()->static_tls_layout.offset_thread_pointer(); std::vector<std::pair<TlsDescriptor*, size_t>> deferred_tlsdesc_relocs; + struct { + // Cache key + ElfW(Word) sym; + + // Cache value + const ElfW(Sym)* s; + soinfo* lsi; + } symbol_lookup_cache; + + symbol_lookup_cache.sym = 0; + for (size_t idx = 0; rel_iterator.has_next(); ++idx) { const auto rel = rel_iterator.next(); if (rel == nullptr) { @@ -2917,14 +2979,25 @@ bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& r return false; } else { sym_name = get_string(symtab_[sym].st_name); - const version_info* vi = nullptr; - if (!lookup_version_info(version_tracker, sym, sym_name, &vi)) { - return false; - } + if (sym == symbol_lookup_cache.sym) { + s = symbol_lookup_cache.s; + lsi = symbol_lookup_cache.lsi; + count_relocation(kRelocSymbolCached); + } else { + const version_info* vi = nullptr; - if (!soinfo_do_lookup(this, sym_name, vi, &lsi, global_group, local_group, &s)) { - return false; + if (!lookup_version_info(version_tracker, sym, sym_name, &vi)) { + return false; + } + + if (!soinfo_do_lookup(this, sym_name, vi, &lsi, global_group, local_group, &s)) { + return false; + } + + symbol_lookup_cache.sym = sym; + symbol_lookup_cache.s = s; + symbol_lookup_cache.lsi = lsi; } if (s == nullptr) { @@ -3121,10 +3194,6 @@ bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& r *reinterpret_cast<ElfW(Addr)*>(reloc) = tpoff; } break; - -#if !defined(__aarch64__) - // Omit support for DTPMOD/DTPREL on arm64, at least until - // http://b/123385182 is fixed. arm64 uses TLSDESC instead. case R_GENERIC_TLS_DTPMOD: count_relocation(kRelocRelative); MARK(rel->r_offset); @@ -3149,7 +3218,6 @@ bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& r reinterpret_cast<void*>(sym_addr + addend), sym_name); *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend; break; -#endif // !defined(__aarch64__) #if defined(__aarch64__) // Bionic currently only implements TLSDESC for arm64. This implementation should work with @@ -4073,10 +4141,10 @@ static std::vector<android_namespace_t*> init_default_namespace_no_config(bool i return namespaces; } -// return /apex/<name>/etc/ld.config.txt from /apex/<name>/bin/<exec> +// return /apex/<name>/etc/ld.config.txt from /apex/<name>/bin/* static std::string get_ld_config_file_apex_path(const char* executable_path) { std::vector<std::string> paths = android::base::Split(executable_path, "/"); - if (paths.size() == 5 && paths[1] == "apex" && paths[3] == "bin") { + if (paths.size() >= 5 && paths[1] == "apex" && paths[3] == "bin") { return std::string("/apex/") + paths[2] + "/etc/ld.config.txt"; } return ""; @@ -4106,6 +4174,13 @@ static std::string get_ld_config_file_path(const char* executable_path) { } #endif + // Use generated linker config if flag is set + // TODO(b/138920271) Do not check property once it is confirmed as stable + if (android::base::GetBoolProperty("sys.linker.use_generated_config", false) && + file_exists(kLdGeneratedConfigFilePath)) { + return kLdGeneratedConfigFilePath; + } + std::string path = get_ld_config_file_apex_path(executable_path); if (!path.empty()) { if (file_exists(path.c_str())) { diff --git a/linker/linker.h b/linker/linker.h index 4c89cebcd..89390b384 100644 --- a/linker/linker.h +++ b/linker/linker.h @@ -94,12 +94,15 @@ enum RelocationKind { kRelocRelative, kRelocCopy, kRelocSymbol, + kRelocSymbolCached, kRelocMax }; void count_relocation(RelocationKind kind); -soinfo* get_libdl_info(const char* linker_path, const soinfo& linker_si); +void print_linker_stats(); + +soinfo* get_libdl_info(const soinfo& linker_si); soinfo* find_containing_library(const void* p); @@ -162,6 +165,13 @@ enum { */ ANDROID_NAMESPACE_TYPE_GREYLIST_ENABLED = 0x08000000, + /* This flag instructs linker to use this namespace as the anonymous + * namespace. There can be only one anonymous namespace in a process. If there + * already an anonymous namespace in the process, using this flag when + * creating a new namespace causes an error + */ + ANDROID_NAMESPACE_TYPE_ALSO_USED_AS_ANONYMOUS = 0x10000000, + ANDROID_NAMESPACE_TYPE_SHARED_ISOLATED = ANDROID_NAMESPACE_TYPE_SHARED | ANDROID_NAMESPACE_TYPE_ISOLATED, }; diff --git a/linker/linker_main.cpp b/linker/linker_main.cpp index f5760231a..fd1592d33 100644 --- a/linker/linker_main.cpp +++ b/linker/linker_main.cpp @@ -63,6 +63,8 @@ static ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf); static void get_elf_base_from_phdr(const ElfW(Phdr)* phdr_table, size_t phdr_count, ElfW(Addr)* base, ElfW(Addr)* load_bias); +static void set_bss_vma_name(soinfo* si); + // These should be preserved static to avoid emitting // RELATIVE relocations for the part of the code running // before linker links itself. @@ -176,11 +178,12 @@ static void add_vdso() { } // Initializes an soinfo's link_map_head field using other fields from the -// soinfo (phdr, phnum, load_bias). -static void init_link_map_head(soinfo& info, const char* linker_path) { +// soinfo (phdr, phnum, load_bias). The soinfo's realpath must not change after +// this function is called. +static void init_link_map_head(soinfo& info) { auto& map = info.link_map_head; map.l_addr = info.load_bias; - map.l_name = const_cast<char*>(linker_path); + map.l_name = const_cast<char*>(info.get_realpath()); phdr_table_get_dynamic_section(info.phdr, info.phnum, info.load_bias, &map.l_ld, nullptr); } @@ -232,9 +235,9 @@ static ExecutableInfo get_executable_info() { } #if defined(__LP64__) -static char kLinkerPath[] = "/system/bin/linker64"; +static char kFallbackLinkerPath[] = "/system/bin/linker64"; #else -static char kLinkerPath[] = "/system/bin/linker"; +static char kFallbackLinkerPath[] = "/system/bin/linker"; #endif __printflike(1, 2) @@ -350,15 +353,11 @@ static ElfW(Addr) linker_main(KernelArgumentBlock& args, const char* exe_to_load const ExecutableInfo exe_info = exe_to_load ? load_executable(exe_to_load) : get_executable_info(); - // Assign to a static variable for the sake of the debug map, which needs - // a C-style string to last until the program exits. - static std::string exe_path = exe_info.path; - - INFO("[ Linking executable \"%s\" ]", exe_path.c_str()); + INFO("[ Linking executable \"%s\" ]", exe_info.path.c_str()); // Initialize the main exe's soinfo. soinfo* si = soinfo_alloc(&g_default_namespace, - exe_path.c_str(), &exe_info.file_stat, + exe_info.path.c_str(), &exe_info.file_stat, 0, RTLD_GLOBAL); somain = si; si->phdr = exe_info.phdr; @@ -367,7 +366,27 @@ static ElfW(Addr) linker_main(KernelArgumentBlock& args, const char* exe_to_load si->size = phdr_table_get_load_size(si->phdr, si->phnum); si->dynamic = nullptr; si->set_main_executable(); - init_link_map_head(*si, exe_path.c_str()); + init_link_map_head(*si); + + set_bss_vma_name(si); + + // Use the executable's PT_INTERP string as the solinker filename in the + // dynamic linker's module list. gdb reads both PT_INTERP and the module list, + // and if the paths for the linker are different, gdb will report that the + // PT_INTERP linker path was unloaded once the module list is initialized. + // There are three situations to handle: + // - the APEX linker (/system/bin/linker[64] -> /apex/.../linker[64]) + // - the ASAN linker (/system/bin/linker_asan[64] -> /apex/.../linker[64]) + // - the bootstrap linker (/system/bin/bootstrap/linker[64]) + const char *interp = phdr_table_get_interpreter_name(somain->phdr, somain->phnum, + somain->load_bias); + if (interp == nullptr) { + // This case can happen if the linker attempts to execute itself + // (e.g. "linker64 /system/bin/linker64"). + interp = kFallbackLinkerPath; + } + solinker->set_realpath(interp); + init_link_map_head(*solinker); // Register the main executable and the linker upfront to have // gdb aware of them before loading the rest of the dependency @@ -405,7 +424,7 @@ static ElfW(Addr) linker_main(KernelArgumentBlock& args, const char* exe_to_load parse_LD_LIBRARY_PATH(ldpath_env); parse_LD_PRELOAD(ldpreload_env); - std::vector<android_namespace_t*> namespaces = init_default_namespaces(exe_path.c_str()); + std::vector<android_namespace_t*> namespaces = init_default_namespaces(exe_info.path.c_str()); if (!si->prelink_image()) __linker_cannot_link(g_argv[0]); @@ -475,11 +494,7 @@ static ElfW(Addr) linker_main(KernelArgumentBlock& args, const char* exe_to_load static_cast<long long>(t0.tv_usec)))); #endif #if STATS - PRINT("RELO STATS: %s: %d abs, %d rel, %d copy, %d symbol", g_argv[0], - linker_stats.count[kRelocAbsolute], - linker_stats.count[kRelocRelative], - linker_stats.count[kRelocCopy], - linker_stats.count[kRelocSymbol]); + print_linker_stats(); #endif #if COUNT_PAGES { @@ -559,6 +574,31 @@ static void get_elf_base_from_phdr(const ElfW(Phdr)* phdr_table, size_t phdr_cou async_safe_fatal("Could not find a PHDR: broken executable?"); } +/* + * Set anonymous VMA name for .bss section. For DSOs loaded by the linker, this + * is done by ElfReader. This function is here for DSOs loaded by the kernel, + * namely the linker itself and the main executable. + */ +static void set_bss_vma_name(soinfo* si) { + for (size_t i = 0; i < si->phnum; ++i) { + auto phdr = &si->phdr[i]; + + if (phdr->p_type != PT_LOAD) { + continue; + } + + ElfW(Addr) seg_start = phdr->p_vaddr + si->load_bias; + ElfW(Addr) seg_page_end = PAGE_END(seg_start + phdr->p_memsz); + ElfW(Addr) seg_file_end = PAGE_END(seg_start + phdr->p_filesz); + + if (seg_page_end > seg_file_end) { + prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, + reinterpret_cast<void*>(seg_file_end), seg_page_end - seg_file_end, + ".bss"); + } + } +} + // Detect an attempt to run the linker on itself. e.g.: // /system/bin/linker64 /system/bin/linker64 // Use priority-1 to run this constructor before other constructors. @@ -649,6 +689,9 @@ __linker_init_post_relocation(KernelArgumentBlock& args, soinfo& tmp_linker_so) // couldn't make system calls on x86 at that point, but we can now... if (!tmp_linker_so.protect_relro()) __linker_cannot_link(args.argv[0]); + // And we can set VMA name for the bss section now + set_bss_vma_name(&tmp_linker_so); + // Initialize the linker's static libc's globals __libc_init_globals(); @@ -695,9 +738,8 @@ __linker_init_post_relocation(KernelArgumentBlock& args, soinfo& tmp_linker_so) // Initialize static variables. Note that in order to // get correct libdl_info we need to call constructors // before get_libdl_info(). - sonext = solist = solinker = get_libdl_info(kLinkerPath, tmp_linker_so); + sonext = solist = solinker = get_libdl_info(tmp_linker_so); g_default_namespace.add_soinfo(solinker); - init_link_map_head(*solinker, kLinkerPath); ElfW(Addr) start_address = linker_main(args, exe_to_load); diff --git a/linker/linker_namespaces.h b/linker/linker_namespaces.h index 215ad05c3..9561bb444 100644 --- a/linker/linker_namespaces.h +++ b/linker/linker_namespaces.h @@ -72,7 +72,10 @@ struct android_namespace_link_t { struct android_namespace_t { public: - android_namespace_t() : is_isolated_(false), is_greylist_enabled_(false) {} + android_namespace_t() : + is_isolated_(false), + is_greylist_enabled_(false), + is_also_used_as_anonymous_(false) {} const char* get_name() const { return name_.c_str(); } void set_name(const char* name) { name_ = name; } @@ -83,6 +86,9 @@ struct android_namespace_t { bool is_greylist_enabled() const { return is_greylist_enabled_; } void set_greylist_enabled(bool enabled) { is_greylist_enabled_ = enabled; } + bool is_also_used_as_anonymous() const { return is_also_used_as_anonymous_; } + void set_also_used_as_anonymous(bool yes) { is_also_used_as_anonymous_ = yes; } + const std::vector<std::string>& get_ld_library_paths() const { return ld_library_paths_; } @@ -164,6 +170,7 @@ struct android_namespace_t { std::string name_; bool is_isolated_; bool is_greylist_enabled_; + bool is_also_used_as_anonymous_; std::vector<std::string> ld_library_paths_; std::vector<std::string> default_library_paths_; std::vector<std::string> permitted_paths_; diff --git a/linker/linker_relocs.h b/linker/linker_relocs.h index 68191f911..1da5ebe34 100644 --- a/linker/linker_relocs.h +++ b/linker/linker_relocs.h @@ -38,9 +38,9 @@ #define R_GENERIC_GLOB_DAT R_AARCH64_GLOB_DAT #define R_GENERIC_RELATIVE R_AARCH64_RELATIVE #define R_GENERIC_IRELATIVE R_AARCH64_IRELATIVE -#define R_GENERIC_TLS_DTPMOD R_AARCH64_TLS_DTPMOD64 -#define R_GENERIC_TLS_DTPREL R_AARCH64_TLS_DTPREL64 -#define R_GENERIC_TLS_TPREL R_AARCH64_TLS_TPREL64 +#define R_GENERIC_TLS_DTPMOD R_AARCH64_TLS_DTPMOD +#define R_GENERIC_TLS_DTPREL R_AARCH64_TLS_DTPREL +#define R_GENERIC_TLS_TPREL R_AARCH64_TLS_TPREL #define R_GENERIC_TLSDESC R_AARCH64_TLSDESC #elif defined (__arm__) diff --git a/linker/linker_sdk_versions.cpp b/linker/linker_sdk_versions.cpp index b06f3e63f..29c0f4af2 100644 --- a/linker/linker_sdk_versions.cpp +++ b/linker/linker_sdk_versions.cpp @@ -26,10 +26,13 @@ * SUCH DAMAGE. */ -#include "linker.h" -#include <android/api-level.h> #include <atomic> +#include <android/api-level.h> +#include <android/fdsan.h> + +#include "linker.h" + static std::atomic<int> g_target_sdk_version(__ANDROID_API__); void set_application_target_sdk_version(int target) { @@ -38,6 +41,10 @@ void set_application_target_sdk_version(int target) { target = __ANDROID_API__; } g_target_sdk_version = target; + + if (target < 30) { + android_fdsan_set_error_level_from_property(ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE); + } } int get_application_target_sdk_version() { diff --git a/linker/linker_soinfo.cpp b/linker/linker_soinfo.cpp index 5f40528e9..d4b25414e 100644 --- a/linker/linker_soinfo.cpp +++ b/linker/linker_soinfo.cpp @@ -550,6 +550,16 @@ void soinfo::set_nodelete() { rtld_flags_ |= RTLD_NODELETE; } +void soinfo::set_realpath(const char* path) { +#if defined(__work_around_b_24465209__) + if (has_min_version(2)) { + realpath_ = path; + } +#else + realpath_ = path; +#endif +} + const char* soinfo::get_realpath() const { #if defined(__work_around_b_24465209__) if (has_min_version(2)) { diff --git a/linker/linker_soinfo.h b/linker/linker_soinfo.h index 80c51af9a..27032c2da 100644 --- a/linker/linker_soinfo.h +++ b/linker/linker_soinfo.h @@ -278,6 +278,7 @@ struct soinfo { void set_soname(const char* soname); const char* get_soname() const; + void set_realpath(const char* path); const char* get_realpath() const; const ElfW(Versym)* get_versym(size_t n) const; ElfW(Addr) get_verneed_ptr() const; @@ -372,7 +373,7 @@ struct soinfo { android_namespace_list_t secondary_namespaces_; uintptr_t handle_; - friend soinfo* get_libdl_info(const char* linker_path, const soinfo& linker_si); + friend soinfo* get_libdl_info(const soinfo& linker_si); // version >= 4 ElfW(Relr)* relr_; |